1 | static S myBotName; |
2 | static long botRoom = 1; |
3 | static new Matches m; // for matching lines |
4 | static int historyGrab = 10; // read last 10 lines from history |
5 | static new L<ChatLine> msgs; |
6 | static long lastSucked; // timestamp |
7 | static long suckDelay = 2000; // suck every X ms |
8 | static int maxLineLength = 1024; // should match groupchat.json.botsay.php |
9 | static boolean loop_firstTime = true; |
10 | static int loopDelay = 5000; |
11 | static boolean debug_printIncoming; |
12 | static O externalSucker, externalPoster; |
13 | |
14 | static TestRoom testRoom; // Set for testing |
15 | |
16 | static class TestRoom { |
17 | long roomID; |
18 | new L<ChatLine> msgs; |
19 | new L<S> presences; |
20 | |
21 | void post(S name, S text) { |
22 | testPost(name, text, true); |
23 | } |
24 | |
25 | void testPost(S name, S text, boolean isBot) { |
26 | new ChatLine line; |
27 | line.room = roomID; |
28 | line.id = l(msgs)+1; |
29 | line.who = name; |
30 | line.text = text; |
31 | line.isBot = isBot; |
32 | msgs.add(line); |
33 | } |
34 | } |
35 | |
36 | static void testMode() { |
37 | testMode(1); |
38 | } |
39 | |
40 | static synchronized void testMode(long roomID) { |
41 | testRoom = new TestRoom; |
42 | testRoom.roomID = roomID; |
43 | } |
44 | |
45 | static void enterRoom(long roomID) { |
46 | if (testRoom != null) ret; // Do nothing on testing |
47 | |
48 | botRoom = roomID; // TODO: presence? |
49 | lastSucked = 0; |
50 | msgs = new L; |
51 | } |
52 | |
53 | static void changeName(S name) { |
54 | myBotName = unnull(name); |
55 | } |
56 | |
57 | static S botifyName(S name) { |
58 | name = unnull(name); |
59 | if (!name.endsWith("bot")) |
60 | name += " Bot"; |
61 | ret name; |
62 | } |
63 | |
64 | static S getMyName() { |
65 | S name = myBotName; |
66 | if (empty(name)) |
67 | name = getProgramName(); |
68 | ret botifyName(name); |
69 | } |
70 | |
71 | static synchronized void say(S text) { |
72 | text = cleanLine(text); |
73 | S name = getMyName(); |
74 | print(">> " + (testRoom != null ? "TEST" : "") + " " + roomNr() + " > " + name + " > " + text); |
75 | if (testRoom != null) |
76 | testRoom.post(name, text); |
77 | else if (externalPoster != null) |
78 | call(externalPoster, "say", name, text, mc()); |
79 | else |
80 | sayInWebChatRoom(name, text, botRoom); |
81 | } |
82 | |
83 | // should match server's line processing - so we can recognize |
84 | // our own lines |
85 | static S cleanLine(S line) { |
86 | line = unnull(line); |
87 | if (l(line) > maxLineLength) { |
88 | print("Warning: Cutting line from " + l(line) + " to " + maxLineLength + " chars."); |
89 | line = substring(line, 0, maxLineLength); |
90 | } |
91 | ret line.trim(); |
92 | } |
93 | |
94 | static void suckChat() { |
95 | if (testRoom != null) { |
96 | addMsgs(subList(testRoom.msgs, l(msgs))); |
97 | ret; |
98 | } |
99 | |
100 | ChatLine last = last(msgs); |
101 | long lastID = last == null ? 0 : last.id; |
102 | |
103 | if (externalSucker != null) { |
104 | addMsgs((L) quickImport(call(externalSucker, "getNewMessages", lastID))); |
105 | ret; |
106 | } |
107 | |
108 | if (now() < lastSucked + suckDelay) ret; |
109 | try { |
110 | L<ChatLine> newMsgs = suckWebChatRoom(getMyName(), botRoom, lastID, lastID == 0 ? historyGrab : 1000); |
111 | addMsgs(newMsgs); |
112 | } finally { |
113 | lastSucked = now(); |
114 | } |
115 | } |
116 | |
117 | static void addMsgs(L<ChatLine> l) { |
118 | if (l == null) ret; |
119 | if (debug_printIncoming) |
120 | for (ChatLine line : l) |
121 | print("INCOMING: " + line.who + " > " + line.text); |
122 | for (ChatLine line : l) { |
123 | hackfixUmlauts(line); |
124 | msgs.add(line); |
125 | } |
126 | } |
127 | |
128 | // ISO to UTF-8 (lines coming from chat) - broken I think |
129 | static void hackfixUmlauts(ChatLine line) { |
130 | /* |
131 | S s = line.text; |
132 | new StringBuilder buf; |
133 | for (int i = 0; i < l(s); i++) { |
134 | int c = (int) s.charAt(i); |
135 | if (c == 252) c = 195; // ü |
136 | buf.append((char) c); |
137 | } |
138 | line.text = str(buf); |
139 | */ |
140 | } |
141 | |
142 | static class MsgMarker { |
143 | long room, idSeen; |
144 | |
145 | void advance(ChatLine line) { |
146 | if (line == null) ret; |
147 | idSeen = max(idSeen, line.id); |
148 | } |
149 | |
150 | void setRoom(long roomID) { |
151 | if (room != roomID) { |
152 | room = roomID; |
153 | idSeen = 0; |
154 | } |
155 | } |
156 | } |
157 | |
158 | static L<ChatLine> msgsFrom(MsgMarker marker) { |
159 | marker.setRoom(botRoom); |
160 | ret msgsFrom(marker.idSeen); |
161 | } |
162 | |
163 | static synchronized L<ChatLine> msgsFrom(long idSeen) { |
164 | int i = l(msgs); |
165 | while (i > 0 && msgs.get(i-1).id > idSeen) |
166 | --i; |
167 | L<ChatLine> l = subList(msgs, i); |
168 | ret l; |
169 | } |
170 | |
171 | static class WordDropper extends S2S { |
172 | Set wordSet; |
173 | |
174 | *(S words) { |
175 | wordSet = dropWords_preprocess(words); |
176 | } |
177 | |
178 | S get(S s) { |
179 | ret dropWords_impl(s, wordSet); |
180 | } |
181 | } |
182 | |
183 | static S getWordDropper_c1; |
184 | static S2S getWordDropper_c2; |
185 | |
186 | static S2S getWordDropper(S wordsToDrop) { |
187 | if (neq(getWordDropper_c1, wordsToDrop)) { |
188 | getWordDropper_c1 = wordsToDrop; |
189 | getWordDropper_c2 = new WordDropper(wordsToDrop); |
190 | } |
191 | ret getWordDropper_c2; |
192 | } |
193 | |
194 | static new MsgMarker matchQuestion_seen; |
195 | static ChatLine matchQuestion_msg; |
196 | |
197 | static boolean matchQuestion_dropping(S pat, S wordsToDrop) { |
198 | ret matchQuestion(pat, getWordDropper(wordsToDrop)); |
199 | } |
200 | |
201 | static boolean matchQuestion(S pat) { |
202 | ret matchQuestion(pat, null); |
203 | } |
204 | |
205 | static boolean matchQuestion(S pat, S2S preprocessor) { |
206 | suckChat(); |
207 | matchQuestion_msg = null; |
208 | for (ChatLine line : msgsFrom(matchQuestion_seen)) { |
209 | matchQuestion_seen.advance(line); |
210 | S text = preprocess(line.text, preprocessor); |
211 | if (debug_printIncoming) |
212 | print("matchQuestion " + quote(text)); |
213 | if (match(pat, text, m)) { |
214 | matchQuestion_msg = line; |
215 | ret true; |
216 | } |
217 | } |
218 | ret false; |
219 | } |
220 | |
221 | static S whoAsks() { |
222 | ret matchQuestion_msg.who; |
223 | } |
224 | |
225 | static boolean haveAnswered(MsgMarker marker, S answer) { |
226 | S myName = getMyName(); |
227 | for (ChatLine line : msgsFrom(marker)) |
228 | if (eq(line.who, myName) && eq(line.text, answer)) |
229 | ret true; |
230 | ret false; |
231 | } |
232 | |
233 | static void answerQuestion(S answer) { |
234 | if (haveAnswered(matchQuestion_seen, answer)) |
235 | print("Have answered already :)"); |
236 | else |
237 | say(answer); |
238 | } |
239 | |
240 | static long roomNr() { |
241 | ret botRoom; |
242 | } |
243 | |
244 | static S roomNrString() { |
245 | ret str(botRoom); |
246 | } |
247 | |
248 | static boolean loop() { |
249 | if (!licensed()) ret false; |
250 | if (loop_firstTime) |
251 | loop_firstTime = false; |
252 | else if (testRoom != null) |
253 | ret false; |
254 | else |
255 | sleep(loopDelay); |
256 | ret true; |
257 | } |
258 | |
259 | static synchronized void testPost(S name, S text, boolean isUser) { |
260 | if (testRoom != null) |
261 | testRoom.testPost(name, text, !isUser); |
262 | } |
263 | |
264 | static void userPost(S text) { |
265 | testPost("User", text, true); |
266 | } |
267 | |
268 | // for test mode - get my responses |
269 | static synchronized L<S> getResponses() { |
270 | new L<S> l; |
271 | if (testRoom == null) ret l; |
272 | S name = getMyName(); |
273 | for (ChatLine line : testRoom.msgs) { |
274 | if (eq(line.who, name) && line.isBot) |
275 | l.add(line.text); |
276 | } |
277 | ret l; |
278 | } |
279 | |
280 | // string-to-string function |
281 | static abstract class S2S { |
282 | abstract S get(S s); |
283 | } |
284 | |
285 | static S preprocess(S text, S2S preprocessor) { |
286 | pcall { |
287 | if (preprocessor != null) |
288 | text = preprocessor.get(text); |
289 | } |
290 | ret text; |
291 | } |
292 | |
293 | static void printIncoming() { |
294 | debug_printIncoming = true; |
295 | } |
296 | |
297 | static synchronized L<S> getPresentNicks() { |
298 | if (testRoom != null) |
299 | ret cloneList(testRoom.presences); |
300 | |
301 | // TODO: cache this for a bit? |
302 | ret getWebChatPresences(roomNr()); |
303 | } |
download show line numbers debug dex old transpilations
Travelled to 13 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt
No comments. add comment
Snippet ID: | #1002900 |
Snippet name: | Web Chat API (include) |
Eternal ID of this version: | #1002900/1 |
Text MD5: | 87ea57b865b1153f4656e245c7d75fee |
Author: | stefan |
Category: | javax |
Type: | JavaX fragment (include) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2016-04-05 23:32:20 |
Source code size: | 6970 bytes / 303 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 715 / 1549 |
Referenced in: | [show references] |