corrade-lsl-templates – Blame information for rev 42
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
4 | office | 1 | /////////////////////////////////////////////////////////////////////////// |
29 | office | 2 | // Copyright (C) Wizardry and Steamworks 2014 - License: CC BY 2.0 // |
4 | office | 3 | /////////////////////////////////////////////////////////////////////////// |
4 | |||
5 | /////////////////////////////////////////////////////////////////////////// |
||
39 | office | 6 | // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 // |
4 | office | 7 | /////////////////////////////////////////////////////////////////////////// |
8 | string wasKeyValueGet(string k, string data) { |
||
9 | if(llStringLength(data) == 0) return ""; |
||
10 | if(llStringLength(k) == 0) return ""; |
||
39 | office | 11 | list a = llParseStringKeepNulls(data, ["&", "="], []); |
12 | integer i = llListFindList(llList2ListStrided(a, 0, -1, 2), [ k ]); |
||
13 | if(i != -1) return llList2String(a, 2*i+1); |
||
4 | office | 14 | return ""; |
15 | } |
||
40 | office | 16 | |
4 | office | 17 | /////////////////////////////////////////////////////////////////////////// |
40 | office | 18 | // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 // |
4 | office | 19 | /////////////////////////////////////////////////////////////////////////// |
20 | string wasKeyValueEncode(list data) { |
||
21 | list k = llList2ListStrided(data, 0, -1, 2); |
||
22 | list v = llList2ListStrided(llDeleteSubList(data, 0, 0), 0, -1, 2); |
||
23 | data = []; |
||
24 | do { |
||
25 | data += llList2String(k, 0) + "=" + llList2String(v, 0); |
||
26 | k = llDeleteSubList(k, 0, 0); |
||
27 | v = llDeleteSubList(v, 0, 0); |
||
28 | } while(llGetListLength(k) != 0); |
||
29 | return llDumpList2String(data, "&"); |
||
30 | } |
||
31 | |||
32 | /////////////////////////////////////////////////////////////////////////// |
||
40 | office | 33 | // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // |
4 | office | 34 | /////////////////////////////////////////////////////////////////////////// |
35 | // escapes a string in conformance with RFC1738 |
||
36 | string wasURLEscape(string i) { |
||
37 | string o = ""; |
||
38 | do { |
||
39 | string c = llGetSubString(i, 0, 0); |
||
40 | i = llDeleteSubString(i, 0, 0); |
||
41 | if(c == "") jump continue; |
||
42 | if(c == " ") { |
||
43 | o += "+"; |
||
44 | jump continue; |
||
45 | } |
||
46 | if(c == "\n") { |
||
47 | o += "%0D" + llEscapeURL(c); |
||
48 | jump continue; |
||
49 | } |
||
50 | o += llEscapeURL(c); |
||
51 | @continue; |
||
52 | } while(i != ""); |
||
53 | return o; |
||
54 | } |
||
55 | |||
56 | /////////////////////////////////////////////////////////////////////////// |
||
40 | office | 57 | // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // |
4 | office | 58 | /////////////////////////////////////////////////////////////////////////// |
59 | // unescapes a string in conformance with RFC1738 |
||
60 | string wasURLUnescape(string i) { |
||
61 | return llUnescapeURL( |
||
62 | llDumpList2String( |
||
63 | llParseString2List( |
||
64 | llDumpList2String( |
||
65 | llParseString2List( |
||
66 | i, |
||
67 | ["+"], |
||
68 | [] |
||
69 | ), |
||
70 | " " |
||
71 | ), |
||
72 | ["%0D%0A"], |
||
73 | [] |
||
74 | ), |
||
75 | "\n" |
||
76 | ) |
||
77 | ); |
||
78 | } |
||
79 | |||
80 | /////////////////////////////////////////////////////////////////////////// |
||
40 | office | 81 | // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // |
4 | office | 82 | /////////////////////////////////////////////////////////////////////////// |
83 | list wasCSVToList(string csv) { |
||
84 | list l = []; |
||
85 | list s = []; |
||
86 | string m = ""; |
||
87 | do { |
||
88 | string a = llGetSubString(csv, 0, 0); |
||
89 | csv = llDeleteSubString(csv, 0, 0); |
||
90 | if(a == ",") { |
||
91 | if(llList2String(s, -1) != "\"") { |
||
92 | l += m; |
||
93 | m = ""; |
||
94 | jump continue; |
||
95 | } |
||
96 | m += a; |
||
97 | jump continue; |
||
98 | } |
||
99 | if(a == "\"" && llGetSubString(csv, 0, 0) == a) { |
||
100 | m += a; |
||
101 | csv = llDeleteSubString(csv, 0, 0); |
||
102 | jump continue; |
||
103 | } |
||
104 | if(a == "\"") { |
||
105 | if(llList2String(s, -1) != a) { |
||
106 | s += a; |
||
107 | jump continue; |
||
108 | } |
||
109 | s = llDeleteSubList(s, -1, -1); |
||
110 | jump continue; |
||
111 | } |
||
112 | m += a; |
||
113 | @continue; |
||
114 | } while(csv != ""); |
||
115 | // postcondition: length(s) = 0 |
||
116 | return l + m; |
||
117 | } |
||
118 | |||
40 | office | 119 | |
120 | |||
121 | /////////////////////////////////////////////////////////////////////////// |
||
122 | // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 // |
||
123 | /////////////////////////////////////////////////////////////////////////// |
||
124 | string wasListToCSV(list l) { |
||
125 | list v = []; |
||
126 | do { |
||
127 | string a = llDumpList2String( |
||
128 | llParseStringKeepNulls( |
||
129 | llList2String( |
||
130 | l, |
||
131 | |||
132 | ), |
||
133 | ["\""], |
||
134 | [] |
||
135 | ), |
||
136 | "\"\"" |
||
137 | ); |
||
138 | if(llParseStringKeepNulls( |
||
139 | a, |
||
140 | [" ", ",", "\n", "\""], [] |
||
141 | ) != |
||
142 | (list) a |
||
143 | ) a = "\"" + a + "\""; |
||
144 | v += a; |
||
145 | l = llDeleteSubList(l, 0, 0); |
||
146 | } while(l != []); |
||
147 | return llDumpList2String(v, ","); |
||
148 | } |
||
149 | |||
150 | /////////////////////////////////////////////////////////////////////////// |
||
151 | // SQL STATEMENT DEFINITIONS // |
||
152 | /////////////////////////////////////////////////////////////////////////// |
||
153 | |||
154 | string SQL_INSERT_VISITOR = "INSERT OR REPLACE INTO visitors (firstname, lastname, lastseen, time, memory) VALUES(:firstname, :lastname, :time, COALESCE((SELECT time FROM visitors WHERE firstname=:firstname AND lastname=:lastname), 0) + 1, :memory)"; |
||
155 | string SQL_CREATE_TABLE = "CREATE TABLE IF NOT EXISTS visitors ('firstname' TEXT NOT NULL, 'lastname' TEXT NOT NULL, 'lastseen' TEXT NOT NULL, 'time' INTEGER NOT NULL, 'memory' INTEGER NOT NULL, PRIMARY KEY ('firstname', 'lastname'))"; |
||
156 | string SQL_COUNT_VISITORS = "SELECT COUNT(*) AS 'Visits', AVG(time) AS 'Time', AVG(memory) AS 'Memory' FROM visitors"; |
||
157 | string SQL_SELECT_VISITOR = "SELECT * FROM visitors ORDER BY lastseen DESC LIMIT 1 OFFSET :offset"; |
||
158 | string SQL_DROP_TABLE = "DROP TABLE IF EXISTS visitors"; |
||
159 | |||
160 | /////////////////////////////////////////////////////////////////////////// |
||
161 | |||
4 | office | 162 | // corrade data |
163 | key CORRADE = NULL_KEY; |
||
164 | string GROUP = ""; |
||
165 | string PASSWORD = ""; |
||
166 | |||
167 | // for holding the callback URL |
||
168 | string callback = ""; |
||
169 | |||
170 | // for notecard reading |
||
171 | integer line = 0; |
||
172 | |||
173 | // key-value data will be read into this list |
||
174 | list tuples = []; |
||
40 | office | 175 | list agents = []; |
176 | string agentName = ""; |
||
4 | office | 177 | |
178 | |||
179 | default { |
||
180 | state_entry() { |
||
181 | if(llGetInventoryType("configuration") != INVENTORY_NOTECARD) { |
||
182 | llOwnerSay("Sorry, could not find a configuration inventory notecard."); |
||
183 | return; |
||
184 | } |
||
185 | // DEBUG |
||
186 | llOwnerSay("Reading configuration file..."); |
||
187 | llGetNotecardLine("configuration", line); |
||
188 | } |
||
189 | dataserver(key id, string data) { |
||
190 | if(data == EOF) { |
||
191 | // invariant, length(tuples) % 2 == 0 |
||
192 | if(llGetListLength(tuples) % 2 != 0) { |
||
193 | llOwnerSay("Error in configuration notecard."); |
||
194 | return; |
||
195 | } |
||
196 | CORRADE = llList2Key( |
||
197 | tuples, |
||
198 | llListFindList( |
||
199 | tuples, |
||
200 | [ |
||
201 | "corrade" |
||
202 | ] |
||
203 | ) |
||
204 | +1 |
||
205 | ); |
||
206 | if(CORRADE == NULL_KEY) { |
||
207 | llOwnerSay("Error in configuration notecard: corrade"); |
||
208 | return; |
||
209 | } |
||
210 | GROUP = llList2String( |
||
211 | tuples, |
||
212 | llListFindList( |
||
213 | tuples, |
||
214 | [ |
||
215 | "group" |
||
216 | ] |
||
217 | ) |
||
218 | +1 |
||
219 | ); |
||
220 | if(GROUP == "") { |
||
221 | llOwnerSay("Error in configuration notecard: group"); |
||
222 | return; |
||
223 | } |
||
224 | PASSWORD = llList2String( |
||
225 | tuples, |
||
226 | llListFindList( |
||
227 | tuples, |
||
228 | [ |
||
229 | "password" |
||
230 | ] |
||
231 | ) |
||
232 | +1 |
||
233 | ); |
||
234 | if(PASSWORD == "") { |
||
235 | llOwnerSay("Error in configuration notecard: password"); |
||
236 | return; |
||
237 | } |
||
238 | // DEBUG |
||
239 | llOwnerSay("Read configuration notecard..."); |
||
240 | tuples = []; |
||
241 | state url; |
||
242 | } |
||
243 | if(data == "") jump continue; |
||
244 | integer i = llSubStringIndex(data, "#"); |
||
245 | if(i != -1) data = llDeleteSubString(data, i, -1); |
||
246 | list o = llParseString2List(data, ["="], []); |
||
247 | // get rid of starting and ending quotes |
||
248 | string k = llDumpList2String( |
||
249 | llParseString2List( |
||
250 | llStringTrim( |
||
251 | llList2String( |
||
252 | o, |
||
253 | |||
254 | ), |
||
255 | STRING_TRIM), |
||
256 | ["\""], [] |
||
257 | ), "\""); |
||
258 | string v = llDumpList2String( |
||
259 | llParseString2List( |
||
260 | llStringTrim( |
||
261 | llList2String( |
||
262 | o, |
||
263 | 1 |
||
264 | ), |
||
265 | STRING_TRIM), |
||
266 | ["\""], [] |
||
267 | ), "\""); |
||
268 | if(k == "" || v == "") jump continue; |
||
269 | tuples += k; |
||
270 | tuples += v; |
||
271 | @continue; |
||
272 | llGetNotecardLine("configuration", ++line); |
||
273 | } |
||
274 | on_rez(integer num) { |
||
275 | llResetScript(); |
||
276 | } |
||
277 | changed(integer change) { |
||
278 | if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { |
||
279 | llResetScript(); |
||
280 | } |
||
281 | } |
||
282 | } |
||
283 | |||
284 | state url { |
||
285 | state_entry() { |
||
286 | // DEBUG |
||
287 | llOwnerSay("Requesting URL..."); |
||
288 | llRequestURL(); |
||
289 | } |
||
290 | http_request(key id, string method, string body) { |
||
291 | if(method != URL_REQUEST_GRANTED) return; |
||
292 | callback = body; |
||
293 | // DEBUG |
||
294 | llOwnerSay("Got URL..."); |
||
295 | state detect; |
||
296 | } |
||
297 | on_rez(integer num) { |
||
298 | llResetScript(); |
||
299 | } |
||
300 | changed(integer change) { |
||
301 | if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { |
||
302 | llResetScript(); |
||
303 | } |
||
304 | } |
||
305 | } |
||
306 | |||
307 | state detect { |
||
308 | state_entry() { |
||
309 | // DEBUG |
||
310 | llOwnerSay("Detecting if Corrade is online..."); |
||
311 | llSetTimerEvent(5); |
||
312 | } |
||
313 | timer() { |
||
40 | office | 314 | llRequestAgentData(CORRADE, DATA_ONLINE); |
4 | office | 315 | } |
316 | dataserver(key id, string data) { |
||
317 | if(data != "1") { |
||
318 | // DEBUG |
||
319 | llOwnerSay("Corrade is not online, sleeping..."); |
||
320 | llSetTimerEvent(30); |
||
321 | return; |
||
322 | } |
||
323 | state initialize; |
||
324 | } |
||
325 | on_rez(integer num) { |
||
326 | llResetScript(); |
||
327 | } |
||
328 | changed(integer change) { |
||
329 | if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { |
||
330 | llResetScript(); |
||
331 | } |
||
332 | } |
||
333 | } |
||
334 | |||
335 | state initialize { |
||
336 | state_entry() { |
||
337 | // DEBUG |
||
338 | llOwnerSay("Creating the database if it does not exist..."); |
||
339 | llInstantMessage( |
||
40 | office | 340 | CORRADE, |
4 | office | 341 | wasKeyValueEncode( |
342 | [ |
||
343 | "command", "database", |
||
344 | "group", wasURLEscape(GROUP), |
||
345 | "password", wasURLEscape(PASSWORD), |
||
40 | office | 346 | "SQL", wasURLEscape(SQL_CREATE_TABLE), |
4 | office | 347 | "callback", wasURLEscape(callback) |
348 | ] |
||
349 | ) |
||
350 | ); |
||
351 | // alarm 60 |
||
352 | llSetTimerEvent(60); |
||
353 | } |
||
354 | timer() { |
||
355 | // DEBUG |
||
356 | llOwnerSay("Timeout creating table..."); |
||
357 | llResetScript(); |
||
358 | } |
||
359 | http_request(key id, string method, string body) { |
||
360 | llHTTPResponse(id, 200, "OK"); |
||
40 | office | 361 | if(wasKeyValueGet("command", body) == "database") { |
362 | integer success = wasKeyValueGet("success", body) == "True"; |
||
363 | if(!success) { |
||
364 | // DEBUG |
||
365 | llOwnerSay("Failed to create the table: " + |
||
366 | wasURLUnescape( |
||
367 | wasKeyValueGet( |
||
368 | "error", |
||
369 | body |
||
370 | ) |
||
371 | ) |
||
372 | ); |
||
373 | return; |
||
374 | } |
||
375 | |||
4 | office | 376 | // DEBUG |
40 | office | 377 | llOwnerSay("Table created..."); |
378 | state show; |
||
4 | office | 379 | } |
380 | } |
||
40 | office | 381 | link_message(integer sender_num, integer num, string str, key id) { |
382 | if(str == "reset") { |
||
383 | state reset; |
||
384 | } |
||
385 | } |
||
4 | office | 386 | on_rez(integer num) { |
387 | llResetScript(); |
||
388 | } |
||
389 | changed(integer change) { |
||
390 | if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { |
||
391 | llResetScript(); |
||
392 | } |
||
393 | } |
||
394 | state_exit() { |
||
395 | llSetTimerEvent(0); |
||
396 | } |
||
397 | } |
||
398 | |||
399 | state show { |
||
400 | state_entry() { |
||
401 | // DEBUG |
||
402 | llOwnerSay("Updating display with the number of recorded visitors..."); |
||
403 | llInstantMessage( |
||
40 | office | 404 | CORRADE, |
4 | office | 405 | wasKeyValueEncode( |
406 | [ |
||
407 | "command", "database", |
||
408 | "group", wasURLEscape(GROUP), |
||
409 | "password", wasURLEscape(PASSWORD), |
||
40 | office | 410 | "SQL", wasURLEscape(SQL_COUNT_VISITORS), |
4 | office | 411 | "callback", wasURLEscape(callback) |
412 | ] |
||
413 | ) |
||
414 | ); |
||
415 | // alarm 60 |
||
416 | llSetTimerEvent(60); |
||
417 | } |
||
418 | timer() { |
||
419 | // DEBUG |
||
420 | llOwnerSay("Timeout reading rows from visitors table..."); |
||
421 | llResetScript(); |
||
422 | } |
||
423 | http_request(key id, string method, string body) { |
||
424 | llHTTPResponse(id, 200, "OK"); |
||
40 | office | 425 | if(wasKeyValueGet("command", body) == "database") { |
426 | integer success = wasKeyValueGet("success", body) == "True"; |
||
427 | if(!success) { |
||
428 | // DEBUG |
||
429 | llOwnerSay("Failed to enumerate visitors: " + |
||
430 | wasURLUnescape( |
||
431 | wasKeyValueGet( |
||
432 | "error", |
||
433 | body |
||
434 | ) |
||
435 | ) |
||
436 | ); |
||
437 | llResetScript(); |
||
438 | } |
||
439 | list data = wasCSVToList( |
||
4 | office | 440 | wasURLUnescape( |
441 | wasKeyValueGet( |
||
40 | office | 442 | "data", |
4 | office | 443 | body |
444 | ) |
||
445 | ) |
||
446 | ); |
||
40 | office | 447 | |
448 | // DEBUG |
||
449 | //llOwnerSay("Data: " + llDumpList2String(data, ",")); |
||
450 | |||
451 | integer visits = llList2Integer( |
||
4 | office | 452 | data, |
40 | office | 453 | llListFindList( |
454 | data, |
||
455 | (list)"Visits" |
||
456 | ) + 1 |
||
457 | ); |
||
458 | integer time = llList2Integer( |
||
4 | office | 459 | data, |
40 | office | 460 | llListFindList( |
461 | data, |
||
462 | (list)"Time" |
||
463 | ) + 1 |
||
464 | ); |
||
465 | integer memory = llList2Integer( |
||
4 | office | 466 | data, |
40 | office | 467 | llListFindList( |
468 | data, |
||
469 | (list)"Memory" |
||
470 | ) + 1 |
||
471 | ); |
||
472 | |||
473 | // Send message to xyz script. |
||
474 | llMessageLinked(LINK_ROOT, 204000, "V:" + (string)visits, "0"); |
||
475 | llMessageLinked(LINK_ROOT, 204000, "T:" + (string)time + "m", "1"); |
||
476 | llMessageLinked(LINK_ROOT, 204000, "M:" + (string)memory + "k", "2"); |
||
477 | |||
478 | // Get the list of agents. |
||
479 | agents = llGetAgentList(AGENT_LIST_REGION, []); |
||
480 | state insert_trampoline; |
||
481 | } |
||
4 | office | 482 | } |
483 | link_message(integer sender_num, integer num, string str, key id) { |
||
484 | if(str == "reset") |
||
485 | state reset; |
||
486 | if(str == "display") { |
||
487 | line = 0; |
||
488 | state display; |
||
489 | } |
||
490 | } |
||
491 | on_rez(integer num) { |
||
492 | llResetScript(); |
||
493 | } |
||
494 | changed(integer change) { |
||
495 | if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { |
||
496 | llResetScript(); |
||
497 | } |
||
498 | } |
||
499 | state_exit() { |
||
500 | llSetTimerEvent(0); |
||
501 | } |
||
502 | } |
||
503 | |||
40 | office | 504 | state insert_trampoline { |
4 | office | 505 | state_entry() { |
40 | office | 506 | llSetTimerEvent(1); |
4 | office | 507 | } |
508 | timer() { |
||
40 | office | 509 | state insert; |
4 | office | 510 | } |
511 | link_message(integer sender_num, integer num, string str, key id) { |
||
512 | if(str == "reset") |
||
513 | state reset; |
||
514 | if(str == "display") { |
||
515 | line = 0; |
||
516 | state display; |
||
517 | } |
||
518 | } |
||
40 | office | 519 | on_rez(integer num) { |
520 | llResetScript(); |
||
521 | } |
||
522 | changed(integer change) { |
||
523 | if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { |
||
524 | llResetScript(); |
||
525 | } |
||
526 | } |
||
527 | state_exit() { |
||
528 | llSetTimerEvent(0); |
||
529 | } |
||
530 | } |
||
531 | |||
532 | state insert { |
||
533 | state_entry() { |
||
534 | // Once the list is empty, go back to display. |
||
535 | if(llGetListLength(agents) == 0) { |
||
536 | state show; |
||
537 | } |
||
538 | |||
539 | key agent = llList2Key(agents, 0); |
||
540 | agents = llDeleteSubList(agents, 0, 0); |
||
541 | list name = llParseString2List(llKey2Name(agent), [" "], []); |
||
542 | if(llGetListLength(name) != 2) { |
||
543 | return; |
||
544 | } |
||
545 | string firstname = llList2String(name, 0); |
||
546 | string lastname = llList2String(name, 1); |
||
547 | agentName = firstname + " " + lastname; |
||
548 | string memory = (string)( |
||
549 | (integer)( |
||
550 | llList2Float( |
||
551 | llGetObjectDetails( |
||
552 | agent, |
||
553 | [OBJECT_SCRIPT_MEMORY] |
||
554 | ), |
||
555 | |||
556 | ) |
||
557 | / |
||
558 | 1024 /*in kib, to mib 1048576*/ |
||
559 | ) |
||
560 | |||
561 | ); |
||
4 | office | 562 | // DEBUG |
40 | office | 563 | //llOwnerSay("Memory: " + memory); |
564 | // The command sent to Corrade responsible for adding a visitor |
||
565 | // or updating the data for the visitor in case the visitor is |
||
566 | // already entered into the visitors table. This is performed |
||
567 | // with an INSER OR REPLACE sqlite command given the first name |
||
568 | // and the last name of the avatar are unique primary keys. |
||
569 | llInstantMessage( |
||
570 | CORRADE, |
||
571 | wasKeyValueEncode( |
||
572 | [ |
||
573 | "command", "database", |
||
574 | "group", wasURLEscape(GROUP), |
||
575 | "password", wasURLEscape(PASSWORD), |
||
576 | "SQL", wasURLEscape(SQL_INSERT_VISITOR), |
||
577 | "data", wasListToCSV( |
||
578 | [ |
||
579 | "firstname", |
||
580 | firstname, |
||
581 | "lastname", |
||
582 | lastname, |
||
583 | "time", |
||
584 | llGetTimestamp(), |
||
585 | "memory", |
||
586 | memory |
||
587 | ] |
||
588 | ), |
||
589 | "callback", wasURLEscape(callback) |
||
590 | ] |
||
591 | ) |
||
592 | ); |
||
593 | |||
594 | // Command timeout. |
||
595 | llSetTimerEvent(60); |
||
4 | office | 596 | } |
40 | office | 597 | http_request(key id, string method, string body) { |
598 | llHTTPResponse(id, 200, "OK"); |
||
599 | |||
600 | // DEBUG |
||
601 | //llOwnerSay(wasURLUnescape(body)); |
||
602 | |||
603 | if(wasKeyValueGet("command", body) == "database") { |
||
604 | integer success = wasKeyValueGet("success", body) == "True"; |
||
605 | if(!success) { |
||
606 | // DEBUG |
||
607 | llOwnerSay("Failed to insert visitor " + agentName + " due to: " + |
||
608 | wasURLUnescape( |
||
609 | wasKeyValueGet( |
||
610 | "error", |
||
611 | body |
||
612 | ) |
||
613 | ) |
||
614 | ); |
||
615 | state insert_trampoline; |
||
616 | } |
||
617 | |||
618 | // DEBUG |
||
619 | llOwnerSay("Processed visitor named " + agentName + "..."); |
||
620 | |||
621 | state insert_trampoline; |
||
622 | } |
||
623 | } |
||
624 | timer() { |
||
625 | // DEBUG |
||
626 | llOwnerSay("Inserting visitors has timed out, resetting..."); |
||
627 | |||
628 | state insert_trampoline; |
||
629 | } |
||
630 | link_message(integer sender_num, integer num, string str, key id) { |
||
631 | if(str == "reset") { |
||
632 | state reset; |
||
633 | } |
||
634 | if(str == "display") { |
||
635 | line = 0; |
||
636 | state display; |
||
637 | } |
||
638 | } |
||
4 | office | 639 | on_rez(integer num) { |
640 | llResetScript(); |
||
641 | } |
||
642 | changed(integer change) { |
||
643 | if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { |
||
644 | llResetScript(); |
||
645 | } |
||
646 | } |
||
647 | state_exit() { |
||
648 | llSetTimerEvent(0); |
||
649 | } |
||
650 | } |
||
651 | |||
652 | state display_trampoline { |
||
653 | state_entry() { |
||
654 | ++line; |
||
655 | state display; |
||
656 | } |
||
657 | link_message(integer sender_num, integer num, string str, key id) { |
||
658 | if(str == "reset") |
||
659 | state reset; |
||
660 | } |
||
661 | } |
||
662 | |||
663 | state display { |
||
664 | state_entry() { |
||
665 | llInstantMessage( |
||
40 | office | 666 | CORRADE, |
4 | office | 667 | wasKeyValueEncode( |
668 | [ |
||
669 | "command", "database", |
||
670 | "group", wasURLEscape(GROUP), |
||
671 | "password", wasURLEscape(PASSWORD), |
||
40 | office | 672 | "SQL", wasURLEscape(SQL_SELECT_VISITOR), |
673 | "data", wasListToCSV( |
||
674 | [ |
||
675 | "offset", |
||
676 | (string)line |
||
677 | ] |
||
4 | office | 678 | ), |
679 | "callback", wasURLEscape(callback) |
||
680 | ] |
||
681 | ) |
||
682 | ); |
||
40 | office | 683 | |
4 | office | 684 | // alarm 60 |
685 | llSetTimerEvent(60); |
||
686 | } |
||
687 | http_request(key id, string method, string body) { |
||
688 | llHTTPResponse(id, 200, "OK"); |
||
40 | office | 689 | |
690 | if(wasKeyValueGet("command", body) == "database") { |
||
691 | integer success = wasKeyValueGet("success", body) == "True"; |
||
692 | if(!success) { |
||
693 | // DEBUG |
||
694 | llOwnerSay("Failed to query the visitors table: " + |
||
695 | wasURLUnescape( |
||
696 | wasKeyValueGet( |
||
697 | "error", |
||
698 | body |
||
699 | ) |
||
4 | office | 700 | ) |
40 | office | 701 | ); |
702 | return; |
||
703 | } |
||
704 | |||
705 | // Grab the data key if it exists. |
||
706 | string dataKey = wasURLUnescape( |
||
707 | wasKeyValueGet( |
||
708 | "data", |
||
709 | body |
||
4 | office | 710 | ) |
711 | ); |
||
712 | |||
40 | office | 713 | // We got no more rows, so switch back to scanning. |
714 | if(dataKey == "") |
||
715 | state show; |
||
716 | |||
717 | list data = wasCSVToList(dataKey); |
||
718 | |||
719 | string firstname = llList2String( |
||
4 | office | 720 | data, |
40 | office | 721 | llListFindList( |
722 | data, |
||
723 | (list)"firstname" |
||
724 | ) + 1 |
||
725 | ); |
||
726 | string lastname = llList2String( |
||
4 | office | 727 | data, |
40 | office | 728 | llListFindList( |
729 | data, |
||
730 | (list)"lastname" |
||
731 | ) + 1 |
||
732 | ); |
||
733 | string lastseen = llList2String( |
||
4 | office | 734 | data, |
40 | office | 735 | llListFindList( |
736 | data, |
||
737 | (list)"lastseen" |
||
738 | ) + 1 |
||
739 | ); |
||
740 | |||
741 | llOwnerSay(firstname + " " + lastname + " @ " + lastseen); |
||
742 | |||
743 | state display_trampoline; |
||
744 | } |
||
4 | office | 745 | } |
746 | link_message(integer sender_num, integer num, string str, key id) { |
||
40 | office | 747 | if(str == "reset") { |
4 | office | 748 | state reset; |
40 | office | 749 | } |
750 | // If the display button is pressed again, go back to the display and stop. |
||
751 | if(str == "display") { |
||
752 | state show; |
||
753 | } |
||
4 | office | 754 | } |
755 | timer() { |
||
756 | // DEBUG |
||
757 | llOwnerSay("Timeout reading rows from visitors table..."); |
||
758 | llResetScript(); |
||
759 | } |
||
760 | on_rez(integer num) { |
||
761 | llResetScript(); |
||
762 | } |
||
763 | changed(integer change) { |
||
764 | if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { |
||
765 | llResetScript(); |
||
766 | } |
||
767 | } |
||
768 | state_exit() { |
||
769 | llSetTimerEvent(0); |
||
770 | } |
||
771 | } |
||
772 | |||
773 | state reset { |
||
774 | state_entry() { |
||
775 | // DEBUG |
||
776 | llOwnerSay("Resetting all visitors..."); |
||
777 | llInstantMessage( |
||
40 | office | 778 | CORRADE, |
4 | office | 779 | wasKeyValueEncode( |
780 | [ |
||
781 | "command", "database", |
||
782 | "group", wasURLEscape(GROUP), |
||
783 | "password", wasURLEscape(PASSWORD), |
||
40 | office | 784 | "SQL", wasURLEscape(SQL_DROP_TABLE), |
4 | office | 785 | "callback", wasURLEscape(callback) |
786 | ] |
||
787 | ) |
||
788 | ); |
||
40 | office | 789 | |
4 | office | 790 | // alarm 60 |
791 | llSetTimerEvent(60); |
||
792 | } |
||
793 | timer() { |
||
794 | // DEBUG |
||
795 | llOwnerSay("Timeout deleting database..."); |
||
796 | llResetScript(); |
||
797 | } |
||
798 | http_request(key id, string method, string body) { |
||
799 | llHTTPResponse(id, 200, "OK"); |
||
40 | office | 800 | if(wasKeyValueGet("command", body) == "database") { |
801 | integer success = wasKeyValueGet("success", body) == "True"; |
||
802 | if(!success) { |
||
803 | // DEBUG |
||
804 | llOwnerSay("Failed to drop the visitors table: " + |
||
805 | wasURLUnescape( |
||
806 | wasKeyValueGet( |
||
807 | "error", |
||
808 | body |
||
809 | ) |
||
810 | ) |
||
811 | ); |
||
812 | llResetScript(); |
||
813 | } |
||
4 | office | 814 | // DEBUG |
40 | office | 815 | llOwnerSay("Table dropped..."); |
4 | office | 816 | llResetScript(); |
817 | } |
||
818 | } |
||
819 | on_rez(integer num) { |
||
820 | llResetScript(); |
||
821 | } |
||
822 | changed(integer change) { |
||
823 | if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { |
||
824 | llResetScript(); |
||
825 | } |
||
826 | } |
||
827 | state_exit() { |
||
828 | llSetTimerEvent(0); |
||
829 | } |
||
830 | } |