32
33:- module(slack_client_old, [
34 slack_start_listener/0,
35 slack_chat/2,
36 slack_send/1,
37 slack_ping/0,
38 is_thread_running/1,
39 slack_ensure_im/2,
40 name_to_id/2
41 ]). 42
43
44:- use_module(library(http/http_open)). 45:- use_module(library(http/http_client)). 46:- use_module(library(http/http_json)). 47:- use_module(library(url)). 48:- use_module(library(http/json)). 49:- use_module(library(http/json_convert)). 50:- use_module(library(http/websocket)). 51
52:- if( \+ current_predicate( wdmsg/1 )). 53
54:- meta_predicate(with_visible_leash(0)). 55with_visible_leash(G):-
56 '$leash'(A, A),'$visible'(V, V),
57 (tracing->CU=trace;CU=notrace),
58 (debugging->CU2=debug;CU2=nodebug),!,
59 call_cleanup(G, (notrace,'$leash'(_, A),'$visible'(_, V),call(CU2),call(CU))).
60
61:- meta_predicate(rtrace(0)). 62rtrace(G):- with_visible_leash(( notrace,leash(-all),visible(+full),leash(+exception),trace,debug, call(G))).
63
64:- meta_predicate(must(0)). 65must(G):- G *->true;throw(must_failed(G)).
66
67dmsg(O):- format(user_error,'~N ~w ~n',[O]).
68
69:- endif. 70
71
72is_thread_running(ID):-
73 is_thread(ID), thread_property(ID,status(What)),!,
74 (What==running->true;(thread_join(ID,_ ),!,fail)).
75
76
77
78:- if( \+ current_predicate( slack_token/1 )). 79:- if(exists_file('.slack_auth.pl')). 80:- include('.slack_auth.pl'). 81:- else. 82:- if(exists_file('~/.slack_auth.pl')). 83:- include('~/.slack_auth.pl'). 84:- endif. 85:- endif. 86:- endif. 87
88
90:- slack_token(_). 91
92
93slack_token_string(S):-slack_token(T),atom_string(T,S).
94
95
96:- dynamic(slack_info/3). 97:- dynamic(slack_websocket/3). 98
99
100slack_get_websocket_url(URL):-
101 slack_token(Token),
102 format(atom(GetURL),'https://slack.com/api/rtm.start?token=~w',[Token]),
103 http_open(GetURL, In, []),
104 json_read_dict(In,Term),
105 dict_pairs(Term,_,Pairs),
106 must(maplist(slack_receive(rtm),Pairs)),
107 URL=Term.url,
108 listing(slack_info/3),
109 close(In).
110
111slack_get_websocket(WS):- slack_websocket(WS,_,_),!.
112slack_get_websocket(WS):-
113 slack_get_websocket_url(URL),!,
114 slack_open_websocket(URL,WS),!.
115
116slack_open_websocket(URL,WS):-
117 ignore(slack_websocket(OLD_WS,_,_)),
118 http_open_websocket(URL, WS, []),
119 stream_pair(WS,I,O),
120 asserta(slack_websocket(WS,I,O)),
121 (nonvar(OLD_WS)->slack_remove_websocket(OLD_WS);true).
122
123slack_remove_websocket(OLD_WS):-
124 ignore(retract(slack_websocket(OLD_WS,_,_))),
125 ignore(catch(ws_close(OLD_WS,1000,''),_,true)).
126
127lame_key(K):- var(K),!.
128lame_key(_-_):-!,fail.
129lame_key(Type):-string(Type),!,string_to_atom(Type,K),!,lame_key(K).
130lame_key(rtm).
131lame_key(rtm_e).
132lame_key(data).
133lame_key(var).
134
135slack_key(Type,Key,NewType):- lame_key(Type),!,slack_key(Key,NewType).
136slack_key(Key,Type,NewType):- lame_key(Type),!,slack_key(Key,NewType).
137slack_key(_Type,Key,NewType):-slack_key(Key,NewType).
138
139slack_key(Type,var):-var(Type),!.
140slack_key(Type,K):-string(Type),!,string_to_atom(Type,K).
141slack_key(Key-Type,NewType):-!,slack_key(Key,Type,NewType).
142slack_key(Key,Key).
143
144slack_start_listener:-
145 call_cleanup((
146 repeat,
147 once(slack_get_websocket(WS)),
148 once(ws_receive(WS,Data,[format(json)])),
149 (Data==
150 end_of_file->!;
151 (once(slack_receive(rtm_e,Data)),fail))),
152 slack_remove_websocket(WS)).
153
154
155
156undict(ID,IDO):- is_dict(ID),ID.IDK=IDV,IDK=id,IDO=IDV.
157undict(ID,ID).
158
159
161slack_event(reconnect_url,_Dict):-!.
167
169slack_event(Type,O):- is_dict(O),O.Key=Data,Key=data,!,slack_receive(Type,Data),!.
170
172slack_event(rtm_e,O):- is_dict(O),O.Key=Type,Key=type,!,slack_receive(Type,O),!.
173
175slack_event(im_open,Dict):-
176 Dict.channel=IDI,
177 Dict.user=User,
178 undict(IDI,ID),
179 string_to_atom(ID,IDA),
180 asserta(slack_info(ims, instance, IDA)),
181 asserta(slack_info(IDA, id, ID)),
182 asserta(slack_info(IDA, user, User)).
183
184slack_event(_,end_of_file):- throw(slack_event(rtm_e,end_of_file)).
185slack_event(_,"end_of_file"):- throw(slack_event(rtm_e,end_of_file)).
186
187
188
190
191slack_unused(user_typing).
192slack_unused(reconnect_url).
193
194slack_receive(Type,Data):- string(Data),(string_to_dict(Data,Dict)->true;string_to_atom(Data,Dict)),!,slack_receive(Type,Dict).
195slack_receive(Type,Data):- slack_key(Type,NewType)-> Type\==NewType,!,slack_receive(NewType,Data).
196slack_receive(C,Dict):- type_to_url(K,C),!, slack_receive(K,Dict).
197slack_receive(Type,Data):- slack_event(Type,Data),!.
198slack_receive(Type,Data):- slack_info(Type,Data),!.
199slack_receive(Type,Data):- slack_unused(Type), format(user_error,'~N % UNUSED ~w ~w ~n',[Type,Data]).
200slack_receive(Type,Data):- format(user_error,'~N % ~q ~q ~n',[Type,Data]).
201
202
203
204slack_info(Type,Data):-is_dict(Data),Data.Key=ID,Key=id,!,string_to_atom(ID,Atom),
205 add_slack_info(Type,Atom,Data).
206slack_info(rtm,Data):- is_list(Data),!, maplist(slack_receive(rtm),Data).
207slack_info(Type,Key-[A|Data]):-is_dict(A),is_list(Data),!,maplist(slack_receive(Type-Key),[A|Data]).
208slack_info(Type,Key-Data):- atomic(Data),add_slack_info(Type,Key,Data).
209slack_info(Type,Key-Data):- is_dict(Data),dict_pairs(Data,Tag,Pairs),maplist(slack_receive(Type-Key-Tag),Pairs).
210
211
212add_slack_info(Type,ID,Data):- is_dict(Data),dict_pairs(Data,_Tag,Pairs),!, add_slack_info1(Type,instance,ID),
213 maplist(add_slack_info1(Type,ID),Pairs).
214
215add_slack_info(Type,ID,Data):-add_slack_info1(Type,ID,Data).
216
217add_slack_info1(Type,ID,K-V):- atom(Type),!,add_slack_info1(ID,K,V).
218add_slack_info1(Type,ID,Data):-assert(slack_info(Type,ID,Data)).
219
220
221name_to_id(Name,ID):-text_to_string(Name,NameS),slack_info(ID,name,NameS),!.
222name_to_id(Name,ID):-text_to_string(Name,NameS),slack_info(ID,real_name,NameS),!.
223name_to_id(Name,ID):-text_to_string(Name,NameS),slack_info(_,instance,ID), slack_info(ID,_,NameS),!.
224
225same_ids(ID,IDS):-text_to_string(ID,IDA),text_to_string(IDS,IDB),IDA==IDB.
226
227slack_ensure_im2(To,IM):- name_to_id(To,ID), slack_info(IM,user,IDS),same_ids(ID,IDS),slack_info(ims,instance,IM),!.
228slack_ensure_im(To,IM):- slack_ensure_im2(To,IM),!.
229slack_ensure_im(To,IM):- name_to_id(To,ID), slack_send({type:'im_open',user:ID}),!,must(slack_ensure_im2(To,IM)),!.
230
231
232slack_id_time(ID,TS):-flag(slack_id,OID,OID+1),ID is OID+1,get_time(Time),number_string(Time,TS).
233
234
235slack_self(Self):- get_slack_info(self, id, Self).
236
238slack_ping :- slack_id_time(ID,_),get_time(Time),TimeRnd is round( Time),slack_send({"id":ID,"type":"ping", "time":TimeRnd}).
239
241slack_chat :- slack_chat(logicmoo,"hi there").
242slack_chat2:- slack_chat(dmiles,"hi dmiles").
243
244
245slack_chat(To,Msg):- slack_ensure_im(To,IM),
246 slack_send({ type: "message", username:"@prologmud_connection",
247 channel: IM, text: Msg
248 }),!.
249
250slack_post(Cmd,Params):- slack_token(Token),
251 make_url_params(Params,URLParams),
252 format(string(S),'https://slack.com/api/~w?token=~w&~w',[Cmd,Token,URLParams]),
253 format(user_error,'~N SLACK-POST ~q ~n',[S]),!,
254 http_open(S,Out,[]),!,
255 json_read_dict(Out,Dict),
256 dict_append_curls(Dict,Params,NewDict),
257 slack_receive(Cmd,NewDict).
258
259dict_append_curls(Dict,Params,NewDict):-any_to_curls(Params,Curly),
260 dict_append_curls3(Dict,Curly,NewDict).
261
262dict_append_curls3(Dict,{},Dict):-!.
263dict_append_curls3(Dict,{Curly},NewDict):-!,dict_append_curls3(Dict,Curly,NewDict).
264dict_append_curls3(Dict,(A,B),NewDict):-!,dict_append_curls3(Dict,A,NewDictM),dict_append_curls3(NewDictM,B,NewDict).
265dict_append_curls3(Dict,KS:V,NewDict):- string_to_atom(KS,K), put_dict(K,Dict,V,NewDict).
266
267
268string_to_dict:-
269 string_to_dict("{\"type\":\"dnd_updated_user\",\"user\":\"U3T3R279S\",\"dnd_status\":{\"dnd_enabled\":false,\"next_dnd_start_ts\":1,\"next_dnd_end_ts\":1},\"event_ts\":\"1485012634.280271\"}",Dict),
270 dmsg(Dict).
271
272string_to_dict(String,Dict):-
273 274 open_string(String,Stream),
275 catch(json_read_dict(Stream,Dict),_,fail),!.
276
277
278
279type_to_url("message",'chat.postMessage').
280type_to_url("im_open",'im.open').
281
282make_url_params({In},Out):-!,make_url_params(In,Out).
283make_url_params((A,B),Out):-!,make_url_params(A,AA),make_url_params(B,BB),format(atom(Out),'~w&~w',[AA,BB]).
284make_url_params([A],Out):-!,make_url_params(A,Out).
285make_url_params([A|B],Out):-!,make_url_params(A,AA),make_url_params(B,BB),format(atom(Out),'~w&~w',[AA,BB]).
286make_url_params(K:A,Out):-www_form_encode(A,AA),format(atom(Out),'~w=~w',[K,AA]).
287make_url_params(K-A,Out):-www_form_encode(A,AA),format(atom(Out),'~w=~w',[K,AA]).
288make_url_params(K=A,Out):-www_form_encode(A,AA),format(atom(Out),'~w=~w',[K,AA]).
289
290slack_send(DataI):- any_to_curls(DataI,Data),slack_send00(Data).
291
292slack_send00({"type":Type,Params}):-type_to_url(Type,Cmd),!,slack_post(Cmd,Params).
294slack_send00(Data):-slack_get_websocket(WebSocket),
295 slack_websocket(WebSocket, _WsInput, WsOutput),
296 flush_output(WsOutput),
297 slack_send(WsOutput,Data),
298 flush_output(WsOutput).
299
300dict_to_curly(Dict,{type:Type,Data}):- del_dict(type,Dict,Type,DictOut),dict_pairs(DictOut,_,Pairs),any_to_curls(Pairs,Data).
301dict_to_curly(Dict,{type:Type,Data}):- dict_pairs(Dict,Type,Pairs),nonvar(Type),any_to_curls(Pairs,Data).
302dict_to_curly(Dict,{Data}):- dict_pairs(Dict,_,Pairs),any_to_curls(Pairs,Data).
303
304any_to_curls(Dict,Out):- is_dict(Dict),!,dict_to_curly(Dict,Data),any_to_curls(Data,Out).
305any_to_curls(Var,"var"):- \+ must(\+ var(Var)),!.
306any_to_curls({DataI},{Data}):-!,any_to_curls(DataI,Data).
307any_to_curls((A,B),(AA,BB)):-!,any_to_curls(A,AA),any_to_curls(B,BB).
308any_to_curls([A],AA):-!,any_to_curls(A,AA).
309any_to_curls([A|B],(AA,BB)):-!,any_to_curls(A,AA),any_to_curls(B,BB).
310any_to_curls(A:B,AA:BB):-!,any_to_curls(A,AA),any_to_curls(B,BB).
311any_to_curls(A-B,AA:BB):-!,any_to_curls(A,AA),any_to_curls(B,BB).
312any_to_curls(A,A):- (integer(A);string(A)),!.
313any_to_curls(A,AA):- catch(text_to_string(A,AA),_,fail),!.
314any_to_curls(A,A).
315
316slack_send(WsOutput,Data):- format(WsOutput,'~q',[Data]),format(user_error,'~N ~q ~n',[Data]),!.
317
318
320:- if(( \+ (is_thread_running(slack_start_listener)))). 321:- thread_create(slack_start_listener,_,[alias(slack_start_listener)]). 322:- endif. 323
325:- if(( \+ (is_thread_running(slack_start_listener)))). 326:- rtrace(slack_start_listener). 327:- endif.