-
Notifications
You must be signed in to change notification settings - Fork 1
/
heraldCore.m
223 lines (183 loc) · 7.5 KB
/
heraldCore.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
function res = heraldCore(botToken, chatId, message, varargin)
%HERALDCORE Communicate with Telegram channel through @herald_matlab_bot
% heraldCore(chatId, ...) is always the most basic way of calling the
% function, as a chatId is always required. However, it is recommended
% to write wrapper functions with a hardcoded chatId, such as the one
% included in the folder. All communication happens through the Telegram
% Bot API (see *bot* below).
%
% S = heraldCore(...) returns the struct S converted from the JSON string
% that the Telegram API sent as a response. If a message has been sent,
% this struct will contain a messageId that can then be used to edit or
% delete that message.
%
% heraldCore(botToken, chatId, ...) specify which botToken and
% chatId/channelId to use. These two parameters are always necessary.
%
% heraldCore(..., text) sends the text message to the channel as the bot.
% Message is formatted in markdown (see *markdown* below).
%
% heraldCore(..., figHandle) sends the figHandle figure as a png to the
% channel.
%
% heraldCore(..., text, messageId) edits the messageId message with the
% new text. The output S of a previous call to the heraldCore function is
% also a valid messageId value.
%
% heraldCore(..., [], messageId) deletes the messageId message. The
% output S of a previous call to the heraldCore function is also a valid
% messageId value.
%
% About the chatId (when using direct chat):
% After starting a conversation with @herald_matlab_bot, forward a
% message inside that conversation to @get_id_bot and the chatId will be
% returned to you.
%
% About the chatId (when using channels):
% The chatId is obtained from forwarding a random message inside the
% dedicated channel to @get_id_bot. The dedicated channel should have
% the bot as an administrator in order to function.
%
% About curl:
% Herald uses the operating system's curl command. If this is not
% installed, please install a binary from *curl* below.
%
% Links:
% *bot* https://core.telegram.org/bots/api
% *markdown* https://core.telegram.org/bots/api#markdown-style
% *curl (info)* https://curl.haxx.se
% *curl (install)* https://chocolatey.org/packages/curl
%
% See also system, jsondecode
p = inputParser;
p.addRequired('botToken');
p.addRequired('chatId');
p.addRequired('message');
p.addOptional('messageId', [], @(x)isnumeric(x)||isstruct(x));
p.parse(botToken, chatId, message, varargin{:});
p = p.Results;
botToken = p.botToken;
chatId = p.chatId;
message = p.message;
messageId = p.messageId;
% If a msg struct was provided instead of just a messageId
if isstruct(messageId) && isfield(messageId, 'result') && isfield(messageId.result, 'message_id')
messageId = messageId.result.message_id;
else
messageId = [];
end
% If message is not a string or a handle, throw an error
if iscell(p.message) || (isnumeric(p.message) && ~ishandle(p.message))
error('herald:messageNotChar', 'Provided message is not a string or a handle');
end
if isempty(messageId)
% Send new content
if ishandle(message)
% Send photo
fname = p_exportImg(message);
res = p_sendPhoto(botToken, chatId, fname);
else
% Send message
res = p_sendMessage(botToken, chatId, message);
end
else
% Modify existing content
if isempty(message)
% Delete message
res = p_deleteMessage(botToken, chatId, messageId);
elseif ishandle(message)
% Edit message by changing the image
warning('herald:notSupported', 'Editing an existing image is not (yet) supported');
else
% Edit message by changing the text
res = p_editMessage(botToken, chatId, message, messageId);
end
end
end
function fname = p_exportImg(handle)
% Save a figure to disk and return the path
% Save figure to disk
fname = [tempname '.png'];
export_fig(fname, '-nocrop', '-r120', handle);
end
function s = p_jsondecode(json)
% Make jsondecode backwards compatible
% The included jsonDecodeLegacy is prone to error, but is decent for
% older versions of MatLab (<R2016b) that do not have jsondecode.
%
% Because an incorrect conversion of JSON to a struct is not impeding (in
% fact, the message/photo will have been sent anyway), any errors at this
% stage will be discarded and an empty struct will be returned. A warning
% will be displayed to inform the user.
try
if exist('jsondecode', 'builtin')
s = jsondecode(json);
else
s = jsonDecodeLegacy(json);
end
catch err
warning(['An error happened during the conversion of JSON to a struct '...
'(JSON: ' json ')']);
s = [];
end
end
function res = p_sendMessage(botToken, chatId, message)
% Call the sendMessage method of the Telegram API
% https://core.telegram.org/bots/api#sendmessage
urlPattern = 'https://api.telegram.org/bot%s/sendMessage';
url = sprintf(urlPattern, botToken);
paramsPattern = 'chat_id=%s&parse_mode=Markdown&text=%s';
params = sprintf(paramsPattern, chatId, urlencode(message));
command = ['curl -s -X POST -d "' params '" ' url ''];
try
[status res] = system(command);
catch err
error('You probably need to install cURL first, see documentation for instructions.');
end
res = p_jsondecode(res);
end
function res = p_sendPhoto(botToken, chatId, fname)
% Call the sendPhoto method of the Telegram API
% https://core.telegram.org/bots/api#sendphoto
urlPattern = 'https://api.telegram.org/bot%s/sendPhoto';
url = sprintf(urlPattern, botToken);
paramsPattern = 'chat_id=%s';
params = sprintf(paramsPattern, chatId);
command = ['curl -s -X POST -F "' params '" -F photo="@' fname '" ' url ''];
try
[status res] = system(command);
catch err
error('You probably need to install cURL first, see documentation for instructions.');
end
res = p_jsondecode(res);
end
function res = p_editMessage(botToken, chatId, message, messageId)
% Call the editMessageText method of the Telegram API
% https://core.telegram.org/bots/api#editmessagetext
urlPattern = 'https://api.telegram.org/bot%s/editMessageText';
url = sprintf(urlPattern, botToken);
paramsPattern = 'chat_id=%s&parse_mode=Markdown&message_id=%i&text=%s';
params = sprintf(paramsPattern, chatId, messageId, urlencode(message));
command = ['curl -s -X POST -d "' params '" ' url ''];
try
[status res] = system(command);
catch err
error('You probably need to install cURL first, see documentation for instructions.');
end
res = p_jsondecode(res);
end
function res = p_deleteMessage(botToken, chatId, messageId)
% Call the deleteMessage method of the Telegram API
% https://core.telegram.org/bots/api#deletemessage
urlPattern = 'https://api.telegram.org/bot%s/deleteMessage';
url = sprintf(urlPattern, botToken);
paramsPattern = 'chat_id=%s&messageId=%i';
params = sprintf(paramsPattern, chatId, messageId);
command = ['curl -s -X POST -d "' params '" ' url ''];
try
[status res] = system(command);
catch err
error('You probably need to install cURL first, see documentation for instructions.');
end
res = p_jsondecode(res);
end