corrade-lsl-templates

Subversion Repositories:
Compare Path: Rev
With Path: Rev
?path1? @ 39  →  ?path2? @ 40
/source/visitor-track-and-record/visitor-track-and-record.lsl
@@ -13,9 +13,9 @@
if(i != -1) return llList2String(a, 2*i+1);
return "";
}
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) 2013 Wizardry and Steamworks - License: CC BY 2.0 //
// Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
string wasKeyValueEncode(list data) {
list k = llList2ListStrided(data, 0, -1, 2);
@@ -30,7 +30,7 @@
}
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
// Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
// escapes a string in conformance with RFC1738
string wasURLEscape(string i) {
@@ -54,7 +54,7 @@
}
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
// Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
// unescapes a string in conformance with RFC1738
string wasURLUnescape(string i) {
@@ -78,7 +78,7 @@
}
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
// Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
list wasCSVToList(string csv) {
list l = [];
@@ -116,6 +116,49 @@
return l + m;
}
 
 
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
///////////////////////////////////////////////////////////////////////////
string wasListToCSV(list l) {
list v = [];
do {
string a = llDumpList2String(
llParseStringKeepNulls(
llList2String(
l,
0
),
["\""],
[]
),
"\"\""
);
if(llParseStringKeepNulls(
a,
[" ", ",", "\n", "\""], []
) !=
(list) a
) a = "\"" + a + "\"";
v += a;
l = llDeleteSubList(l, 0, 0);
} while(l != []);
return llDumpList2String(v, ",");
}
 
///////////////////////////////////////////////////////////////////////////
// SQL STATEMENT DEFINITIONS //
///////////////////////////////////////////////////////////////////////////
 
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)";
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'))";
string SQL_COUNT_VISITORS = "SELECT COUNT(*) AS 'Visits', AVG(time) AS 'Time', AVG(memory) AS 'Memory' FROM visitors";
string SQL_SELECT_VISITOR = "SELECT * FROM visitors ORDER BY lastseen DESC LIMIT 1 OFFSET :offset";
string SQL_DROP_TABLE = "DROP TABLE IF EXISTS visitors";
 
///////////////////////////////////////////////////////////////////////////
 
// corrade data
key CORRADE = NULL_KEY;
string GROUP = "";
@@ -129,6 +172,8 @@
// key-value data will be read into this list
list tuples = [];
list agents = [];
string agentName = "";
 
 
default {
@@ -266,7 +311,7 @@
llSetTimerEvent(5);
}
timer() {
llRequestAgentData((key)CORRADE, DATA_ONLINE);
llRequestAgentData(CORRADE, DATA_ONLINE);
}
dataserver(key id, string data) {
if(data != "1") {
@@ -292,22 +337,13 @@
// DEBUG
llOwnerSay("Creating the database if it does not exist...");
llInstantMessage(
(key)CORRADE,
CORRADE,
wasKeyValueEncode(
[
"command", "database",
"group", wasURLEscape(GROUP),
"password", wasURLEscape(PASSWORD),
"SQL", wasURLEscape(
"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')
)"
),
"SQL", wasURLEscape(SQL_CREATE_TABLE),
"callback", wasURLEscape(callback)
]
)
@@ -322,23 +358,31 @@
}
http_request(key id, string method, string body) {
llHTTPResponse(id, 200, "OK");
if(wasKeyValueGet("command", body) != "database") return;
if(wasKeyValueGet("success", body) != "True") {
if(wasKeyValueGet("command", body) == "database") {
integer success = wasKeyValueGet("success", body) == "True";
if(!success) {
// DEBUG
llOwnerSay("Failed to create the table: " +
wasURLUnescape(
wasKeyValueGet(
"error",
body
)
)
);
return;
}
// DEBUG
llOwnerSay("Failed to create the table: " +
wasURLUnescape(
wasKeyValueGet(
"error",
body
)
)
);
return;
llOwnerSay("Table created...");
state show;
}
// DEBUG
llOwnerSay("Table created...");
state show;
}
link_message(integer sender_num, integer num, string str, key id) {
if(str == "reset") {
state reset;
}
}
on_rez(integer num) {
llResetScript();
}
@@ -357,19 +401,13 @@
// DEBUG
llOwnerSay("Updating display with the number of recorded visitors...");
llInstantMessage(
(key)CORRADE,
CORRADE,
wasKeyValueEncode(
[
"command", "database",
"group", wasURLEscape(GROUP),
"password", wasURLEscape(PASSWORD),
"SQL", wasURLEscape(
"SELECT
COUNT(*) AS 'Visits',
AVG(time) AS 'Time',
AVG(memory) AS 'Memory'
FROM visitors"
),
"SQL", wasURLEscape(SQL_COUNT_VISITORS),
"callback", wasURLEscape(callback)
]
)
@@ -384,52 +422,63 @@
}
http_request(key id, string method, string body) {
llHTTPResponse(id, 200, "OK");
if(wasKeyValueGet("command", body) != "database") return;
if(wasKeyValueGet("success", body) != "True") {
// DEBUG
llOwnerSay("Failed to enumerate visitors: " +
if(wasKeyValueGet("command", body) == "database") {
integer success = wasKeyValueGet("success", body) == "True";
if(!success) {
// DEBUG
llOwnerSay("Failed to enumerate visitors: " +
wasURLUnescape(
wasKeyValueGet(
"error",
body
)
)
);
llResetScript();
}
list data = wasCSVToList(
wasURLUnescape(
wasKeyValueGet(
"error",
"data",
body
)
)
);
llResetScript();
}
list data = wasCSVToList(
wasURLUnescape(
wasKeyValueGet(
"data",
body
)
)
);
integer visits = llList2Integer(
data,
llListFindList(
// DEBUG
//llOwnerSay("Data: " + llDumpList2String(data, ","));
integer visits = llList2Integer(
data,
(list)"Visits"
) + 1
);
integer time = llList2Integer(
data,
llListFindList(
llListFindList(
data,
(list)"Visits"
) + 1
);
integer time = llList2Integer(
data,
(list)"Time"
) + 1
);
integer memory = llList2Integer(
data,
llListFindList(
llListFindList(
data,
(list)"Time"
) + 1
);
integer memory = llList2Integer(
data,
(list)"Memory"
) + 1
);
llMessageLinked(LINK_ROOT, 204000, "V:" + (string)visits, "0");
llMessageLinked(LINK_ROOT, 204000, "T:" + (string)time + "m", "1");
llMessageLinked(LINK_ROOT, 204000, "M:" + (string)memory + "k", "2");
state scan;
llListFindList(
data,
(list)"Memory"
) + 1
);
// Send message to xyz script.
llMessageLinked(LINK_ROOT, 204000, "V:" + (string)visits, "0");
llMessageLinked(LINK_ROOT, 204000, "T:" + (string)time + "m", "1");
llMessageLinked(LINK_ROOT, 204000, "M:" + (string)memory + "k", "2");
// Get the list of agents.
agents = llGetAgentList(AGENT_LIST_REGION, []);
state insert_trampoline;
}
}
link_message(integer sender_num, integer num, string str, key id) {
if(str == "reset")
@@ -452,75 +501,12 @@
}
}
 
state scan {
state insert_trampoline {
state_entry() {
// DEBUG
llOwnerSay("Scanning for visitors...");
// Scan for visitors every 60 seconds.
llSetTimerEvent(60);
llSetTimerEvent(1);
}
timer() {
// Check if Corrade is online.
llRequestAgentData((key)CORRADE, DATA_ONLINE);
// Get agents
list as = llGetAgentList(AGENT_LIST_REGION, []);
do {
key a = llList2Key(as, 0);
as = llDeleteSubList(as, 0, 0);
list name = llParseString2List(llKey2Name(a), [" "], []);
if(llGetListLength(name) != 2) return;
string fn = llList2String(name, 0);
string ln = llList2String(name, 1);
// The command sent to Corrade responsible for adding a visitor
// or updating the data for the visitor in case the visitor is
// already entered into the visitors table. This is performed
// with an INSER OR REPLACE sqlite command given the first name
// and the last name of the avatar are unique primary keys.
llInstantMessage(
(key)CORRADE,
wasKeyValueEncode(
[
"command", "database",
"group", wasURLEscape(GROUP),
"password", wasURLEscape(PASSWORD),
"SQL", wasURLEscape(
"INSERT OR REPLACE INTO visitors (
firstname,
lastname,
lastseen,
time,
memory
) VALUES(
'" + fn + "', '" + ln + "', '" + llGetTimestamp() + "',
COALESCE(
(
SELECT time FROM visitors WHERE
firstname='" + fn + "' AND lastname='" + ln + "'
) + 1
,
1
), " +
(string)(
(integer)(
llList2Float(
llGetObjectDetails(
a,
[OBJECT_SCRIPT_MEMORY]
),
0
)
/
1024 /*in kib, to mib 1048576*/
)
 
) +
")"
)
]
)
);
} while(llGetListLength(as));
state show;
state insert;
}
link_message(integer sender_num, integer num, string str, key id) {
if(str == "reset")
@@ -530,13 +516,126 @@
state display;
}
}
dataserver(key id, string data) {
if(data == "1") return;
on_rez(integer num) {
llResetScript();
}
changed(integer change) {
if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
llResetScript();
}
}
state_exit() {
llSetTimerEvent(0);
}
}
 
state insert {
state_entry() {
// Once the list is empty, go back to display.
if(llGetListLength(agents) == 0) {
state show;
}
key agent = llList2Key(agents, 0);
agents = llDeleteSubList(agents, 0, 0);
list name = llParseString2List(llKey2Name(agent), [" "], []);
if(llGetListLength(name) != 2) {
return;
}
string firstname = llList2String(name, 0);
string lastname = llList2String(name, 1);
agentName = firstname + " " + lastname;
string memory = (string)(
(integer)(
llList2Float(
llGetObjectDetails(
agent,
[OBJECT_SCRIPT_MEMORY]
),
0
)
/
1024 /*in kib, to mib 1048576*/
)
);
// DEBUG
llOwnerSay("Corrade is not online, sleeping...");
// Switch to detect loop and wait there for Corrade to come online.
state detect;
//llOwnerSay("Memory: " + memory);
// The command sent to Corrade responsible for adding a visitor
// or updating the data for the visitor in case the visitor is
// already entered into the visitors table. This is performed
// with an INSER OR REPLACE sqlite command given the first name
// and the last name of the avatar are unique primary keys.
llInstantMessage(
CORRADE,
wasKeyValueEncode(
[
"command", "database",
"group", wasURLEscape(GROUP),
"password", wasURLEscape(PASSWORD),
"SQL", wasURLEscape(SQL_INSERT_VISITOR),
"data", wasListToCSV(
[
"firstname",
firstname,
"lastname",
lastname,
"time",
llGetTimestamp(),
"memory",
memory
]
),
"callback", wasURLEscape(callback)
]
)
);
// Command timeout.
llSetTimerEvent(60);
}
http_request(key id, string method, string body) {
llHTTPResponse(id, 200, "OK");
// DEBUG
//llOwnerSay(wasURLUnescape(body));
if(wasKeyValueGet("command", body) == "database") {
integer success = wasKeyValueGet("success", body) == "True";
if(!success) {
// DEBUG
llOwnerSay("Failed to insert visitor " + agentName + " due to: " +
wasURLUnescape(
wasKeyValueGet(
"error",
body
)
)
);
state insert_trampoline;
}
// DEBUG
llOwnerSay("Processed visitor named " + agentName + "...");
state insert_trampoline;
}
}
timer() {
// DEBUG
llOwnerSay("Inserting visitors has timed out, resetting...");
state insert_trampoline;
}
link_message(integer sender_num, integer num, string str, key id) {
if(str == "reset") {
state reset;
}
if(str == "display") {
line = 0;
state display;
}
}
on_rez(integer num) {
llResetScript();
}
@@ -564,82 +663,94 @@
state display {
state_entry() {
llInstantMessage(
(key)CORRADE,
CORRADE,
wasKeyValueEncode(
[
"command", "database",
"group", wasURLEscape(GROUP),
"password", wasURLEscape(PASSWORD),
"SQL", wasURLEscape(
"SELECT * FROM visitors
ORDER BY lastseen DESC
LIMIT 1
OFFSET " + (string)line
"SQL", wasURLEscape(SQL_SELECT_VISITOR),
"data", wasListToCSV(
[
"offset",
(string)line
]
),
"callback", wasURLEscape(callback)
]
)
);
// alarm 60
llSetTimerEvent(60);
}
http_request(key id, string method, string body) {
llHTTPResponse(id, 200, "OK");
if(wasKeyValueGet("command", body) != "database") return;
if(wasKeyValueGet("success", body) != "True") {
// DEBUG
llOwnerSay("Failed to query the table: " +
wasURLUnescape(
wasKeyValueGet(
"error",
body
if(wasKeyValueGet("command", body) == "database") {
integer success = wasKeyValueGet("success", body) == "True";
if(!success) {
// DEBUG
llOwnerSay("Failed to query the visitors table: " +
wasURLUnescape(
wasKeyValueGet(
"error",
body
)
)
);
return;
}
// Grab the data key if it exists.
string dataKey = wasURLUnescape(
wasKeyValueGet(
"data",
body
)
);
return;
}
// Grab the data key if it exists.
string dataKey = wasURLUnescape(
wasKeyValueGet(
"data",
body
)
);
// We got no more rows, so switch back to scanning.
if(dataKey == "")
state scan;
list data = wasCSVToList(dataKey);
string firstname = llList2String(
data,
llListFindList(
// We got no more rows, so switch back to scanning.
if(dataKey == "")
state show;
list data = wasCSVToList(dataKey);
string firstname = llList2String(
data,
(list)"firstname"
) + 1
);
string lastname = llList2String(
data,
llListFindList(
llListFindList(
data,
(list)"firstname"
) + 1
);
string lastname = llList2String(
data,
(list)"lastname"
) + 1
);
string lastseen = llList2String(
data,
llListFindList(
llListFindList(
data,
(list)"lastname"
) + 1
);
string lastseen = llList2String(
data,
(list)"lastseen"
) + 1
);
 
llOwnerSay(firstname + " " + lastname + " @ " + lastseen);
state display_trampoline;
llListFindList(
data,
(list)"lastseen"
) + 1
);
llOwnerSay(firstname + " " + lastname + " @ " + lastseen);
state display_trampoline;
}
}
link_message(integer sender_num, integer num, string str, key id) {
if(str == "reset")
if(str == "reset") {
state reset;
}
// If the display button is pressed again, go back to the display and stop.
if(str == "display") {
state show;
}
}
timer() {
// DEBUG
@@ -664,17 +775,18 @@
// DEBUG
llOwnerSay("Resetting all visitors...");
llInstantMessage(
(key)CORRADE,
CORRADE,
wasKeyValueEncode(
[
"command", "database",
"group", wasURLEscape(GROUP),
"password", wasURLEscape(PASSWORD),
"SQL", "DROP TABLE visitors",
"SQL", wasURLEscape(SQL_DROP_TABLE),
"callback", wasURLEscape(callback)
]
)
);
// alarm 60
llSetTimerEvent(60);
}
@@ -685,22 +797,24 @@
}
http_request(key id, string method, string body) {
llHTTPResponse(id, 200, "OK");
if(wasKeyValueGet("command", body) != "database") return;
if(wasKeyValueGet("success", body) != "True") {
if(wasKeyValueGet("command", body) == "database") {
integer success = wasKeyValueGet("success", body) == "True";
if(!success) {
// DEBUG
llOwnerSay("Failed to drop the visitors table: " +
wasURLUnescape(
wasKeyValueGet(
"error",
body
)
)
);
llResetScript();
}
// DEBUG
llOwnerSay("Failed to drop the visitors table: " +
wasURLUnescape(
wasKeyValueGet(
"error",
body
)
)
);
llOwnerSay("Table dropped...");
llResetScript();
}
// DEBUG
llOwnerSay("Table dropped...");
llResetScript();
}
on_rez(integer num) {
llResetScript();