Difference between revisions of "Dataserver"

From Second Life Wiki
Jump to navigation Jump to search
m
Line 40: Line 40:
{{!}}}
{{!}}}
|caveats=
|caveats=
*Dataserver answers do not necessarily come in the order they were requested.
**If there are multiple pending requests, always use the queryid key to determine which answer is being received.
*Dataserver requests will trigger '''dataserver''' events in all scripts within the same prim where the request was made.
*Dataserver requests will trigger '''dataserver''' events in all scripts within the same prim where the request was made.
**If there are multiple scripts with '''dataserver''' events in the same prim, always use the queryid key to determine which answer is being received.
**If there are multiple scripts with '''dataserver''' events in the same prim, always use the <code>queryid</code> key to determine which answer is being received.
**'''dataserver''' events will not be triggered in scripts contained in other prims in the same linked object.
**'''dataserver''' events will not be triggered in scripts contained in other prims in the same linked object.
*If more data is requested using the same query_id before the '''dataserver''' event dealing with that query_id has resolved the data will be trashed. To avoid the trashing do not ask [[if]](query_key == query_id). Though (see above caveats) this has its own drawbacks.
*When dealing with multiple dataserver queries it is possible to receive the responses in any order, if you receive a response at all. It is good practise to maintain variables (or a list) with keys of all data server events you are waiting for, then use <code>queryid</code>
|notes=*Requesting data from within the '''dataserver''' event is quite valid. However, be aware not to make your own loop inside the event. It will lock the event open until the loop is finished then send all the requests made from within, with the data from the first retrieval.
**When using <code>if (dKey == queryid)</code>, or similar, in your dataserver events it is important to remember that changes to <code>dKey</code> will cause your script to ignore any requests that were made earlier that have not yet arrived.
|examples=<lsl>key kQuery;
**When using a list to track events, it is important to periodically check the list for requests that have taken too long and either resend them, or remove them (see examples), as it is possible for any dataserver request to fail, usually due to high traffic or the script receiving too many other events.
|notes=*Requesting data from within the '''dataserver''' event is quite valid. However, be aware that further '''dataserver''' events cannot be received until the event that sent the request has been completed.
|examples=<lsl>// Example script handling sequential data server events (notecard reading)
key kQuery;
integer iLine = 0;
integer iLine = 0;
default {
default {
   
     state_entry() {
     state_entry() {
         llSay(0, "Reading notecard...");
         llSay(0, "Reading notecard...");
Line 57: Line 57:


     dataserver(key query_id, string data) {
     dataserver(key query_id, string data) {
         if (query_id == kQuery) {
         if (query_id == kQuery) {
             // this is a line of our notecard
             // this is a line of our notecard
             if (data == EOF) {     
             if (data == EOF) {     
                 llSay(0, "No more lines in notecard, read " + (string)iLine + " lines.");
                 llSay(0, "No more lines in notecard, read " + (string)iLine + " lines.");
             } else {
             } else {
                 // increment line count
                 // increment line count
                 llSay(0, "Line " + (string)iLine + ": " + data);
                 llSay(0, "Line " + (string)iLine + ": " + data);
Line 72: Line 68:
                 ++iLine;
                 ++iLine;
                 kQuery = llGetNotecardLine("My Notecard", iLine);
                 kQuery = llGetNotecardLine("My Notecard", iLine);
            }
        }
    }
}</lsl>
<lsl>// Example script handling multiple data server events
list events = []; integer EVENTS_STRIDE = 3;
integer EVENTS_DATA = 1;
integer EVENTS_TIME = 2;
default {
    touch_start(integer x) {
        integer empty = [] == events;
        while ((--x) >= 0) {
            key avatar = llDetectedKey(x);
            events += [
                llRequestDisplayName(avatar), // Send request for display name and store the key for the response
                avatar, // Keep a note of avatar ID so we can send them a message
                llGetUnixTime() // Store time so we can clear out failed requests
            ];
        }
        if (empty && ([] != events)) llSetTimerEvent(35.0); // Start timer for clean up
    }
    dataserver(key id, string data) {
        integer index = llListFindList(events, [id]);
        if (~index & !(index % EVENTS_STRIDE)) { // index should be a key in the first stride/column
            id = llList2Key(events, index + EVENTS_DATA);
            llRegionSayTo(id, PUBLIC_CHANNEL, "Hello " + data + "!");
            events = llDeleteSubList((events = []) + events, index, index + (EVENTS_STRIDE - 1));
            if ([] == events) llSetTimerEvent(0.0); // No more events to tidy
        }
    }


    timer() {
        integer length = events != []; integer i;
        if (length > 0) {
            // Loop until we find a valid entry (as all entries after will be valid too)
            while(length && (llList2Integer(events, EVENTS_TIME) < (llGetUnixTime() - 30))) {
                events = llDeleteSubList((events = []) + events, 0, EVENTS_STRIDE - 1);
                length -= EVENTS_STRIDE;
             }
             }
         }
         }
        if ([] == events) llSetTimerEvent(0.0); // No more events to tidy
     }
     }
}</lsl>
}</lsl>

Revision as of 09:22, 16 July 2012

Description

! Event: dataserver( key queryid, string data ){ ; }

Triggered when task receives asynchronous data

• key queryid matches the return of the requesting function
• string data the requested data (cast as a string as necessary).
Function Input Decode Description
llGetNotecardLine string The line in the requested notecard, limited to 255 bytes.
If EOF the line requested is past the end of the notecard.
llGetNumberOfNotecardLines (integer) The number of lines in the notecard requested.
llRequestAgentData DATA_ONLINE 1 (integerboolean If the requested agent is online
DATA_NAME 2 string The requested agent's legacy name
DATA_BORN 3 string The account creation/"born on" date as a string in an ISO 8601 format of YYYY-MM-DD.
DATA_RATING 4 llCSV2List() Deprecated: Returns [0, 0, 0, 0, 0, 0]
Used to return: [pos_behavior, neg_behavior, pos_appearance, neg_appearance, pos_building, neg_building]
DATA_PAYINFO 8 (integermask Flag Description
PAYMENT_INFO_ON_FILE 0x1 If payment info is on file.
PAYMENT_INFO_USED 0x2 If payment info has been used.
llRequestDisplayName (string) The agent's display name
llRequestUsername (string) The agent's username (legacy format: "first.last")
llRequestInventoryData Landmark (vector) The vector data received by dataserver is a global position as an offset from the current region's origin (<0,0,0>). To obtain the absolute global position of a landmark, add llGetRegionCorner() to the vector.
llRequestSimulatorData DATA_SIM_POS 5 (vector) The regions global position.
DATA_SIM_STATUS 6 string Value Description
"up" region currently up and running
"down" region currently down
"starting" region currently starting
"stopping" region currently stopping
"crashed" region has crashed
"unknown" region status unknown or unknown region
DATA_SIM_RATING 7 string Value Maturity rating
"PG" Parcel lght G.png General
"MATURE" Parcel lght M.png Moderate
"ADULT" Parcel lght A.png Adult
"UNKNOWN" rating or region unknown

Caveats

  • Dataserver requests will trigger dataserver events in all scripts within the same prim where the request was made.
    • If there are multiple scripts with dataserver events in the same prim, always use the queryid key to determine which answer is being received.
    • dataserver events will not be triggered in scripts contained in other prims in the same linked object.
  • When dealing with multiple dataserver queries it is possible to receive the responses in any order, if you receive a response at all. It is good practise to maintain variables (or a list) with keys of all data server events you are waiting for, then use queryid
    • When using if (dKey == queryid), or similar, in your dataserver events it is important to remember that changes to dKey will cause your script to ignore any requests that were made earlier that have not yet arrived.
    • When using a list to track events, it is important to periodically check the list for requests that have taken too long and either resend them, or remove them (see examples), as it is possible for any dataserver request to fail, usually due to high traffic or the script receiving too many other events.

Important Issues

~ All Issues ~ Search JIRA for related Bugs
   llRequestAgentData with DATA_ONLINE parameter has a delay of up to 10 minutes in reporting offline status

Examples

<lsl>// Example script handling sequential data server events (notecard reading) key kQuery; integer iLine = 0; default {

   state_entry() {
       llSay(0, "Reading notecard...");
       kQuery = llGetNotecardLine("My Notecard", iLine);
   }
   dataserver(key query_id, string data) {
       if (query_id == kQuery) {
           // this is a line of our notecard
           if (data == EOF) {    
               llSay(0, "No more lines in notecard, read " + (string)iLine + " lines.");
           } else {
               // increment line count
               llSay(0, "Line " + (string)iLine + ": " + data);
               
               //request next line
               ++iLine;
               kQuery = llGetNotecardLine("My Notecard", iLine);
           }
       }
   }

}</lsl> <lsl>// Example script handling multiple data server events list events = []; integer EVENTS_STRIDE = 3; integer EVENTS_DATA = 1; integer EVENTS_TIME = 2;

default {

   touch_start(integer x) {
       integer empty = [] == events;
       while ((--x) >= 0) {
           key avatar = llDetectedKey(x);
           events += [
               llRequestDisplayName(avatar), // Send request for display name and store the key for the response
               avatar, // Keep a note of avatar ID so we can send them a message
               llGetUnixTime() // Store time so we can clear out failed requests
           ];
       }
       if (empty && ([] != events)) llSetTimerEvent(35.0); // Start timer for clean up
   }
   dataserver(key id, string data) {
       integer index = llListFindList(events, [id]);
       if (~index & !(index % EVENTS_STRIDE)) { // index should be a key in the first stride/column
           id = llList2Key(events, index + EVENTS_DATA);
           llRegionSayTo(id, PUBLIC_CHANNEL, "Hello " + data + "!");
           events = llDeleteSubList((events = []) + events, index, index + (EVENTS_STRIDE - 1));
           if ([] == events) llSetTimerEvent(0.0); // No more events to tidy
       }
   }
   timer() {
       integer length = events != []; integer i;
       if (length > 0) {
           // Loop until we find a valid entry (as all entries after will be valid too)
           while(length && (llList2Integer(events, EVENTS_TIME) < (llGetUnixTime() - 30))) {
               events = llDeleteSubList((events = []) + events, 0, EVENTS_STRIDE - 1);
               length -= EVENTS_STRIDE;
           }
       }
       if ([] == events) llSetTimerEvent(0.0); // No more events to tidy
   }

}</lsl>

Notes

  • Requesting data from within the dataserver event is quite valid. However, be aware that further dataserver events cannot be received until the event that sent the request has been completed.

Deep Notes

Issues

All Issues

~ Search JIRA for related Issues
   llRequestAgentData with DATA_ONLINE parameter has a delay of up to 10 minutes in reporting offline status
   Script dataserver events become permanently blocked until sim restart

Signature

event void dataserver( key queryid, string data );