Recommendation: GSI LEP (v1)
Structured encapsulation and protocol suite for LSL/SLua link_message events
The Global Scripting Institute (GSI) is an informal organization of Second Life® users that design and test standards for efficient, flexible, and readable scripts in Second Life. "Second Life®" and "Second Life Grid™" are trademarks of Linden Research, Inc., d/b/a Linden Lab. The Global Scripting Institute and its catalog are not affiliated with with or sponsored by Linden Research.
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119.
The Link_message Encapsulation Protocol (LEP) is a message protocol for llMessageLinked/link_message in Linden Scripting Language (LSL) and SLua.
LSL-style syntax is used throughout this document, but all specifications also apply to the equivalent SLua functions and event callbacks.
LEP uses the string parameter of llMessageLinked to pass structured JSON data. The script MUST pass its own values for the integer and key parameters.
The metadata included in each LEP message permit other scripts to identify the source, target, and type of message to rapidly discard unwanted link_message events.
The string parameter of all LEP link messages MUST be a JSON object with the following pairs:
| Name | Type | Description |
|---|---|---|
| "ss" | string | MUST be the name of the source script. |
| "ts" | string | MUST be the name of the target script. If targeting all scripts in the selected link(s), use "". |
| "t" | string | MAY be the protocol in use (see below). |
Depending on the protocol in use, additional pairs may be added to this JSON object.
The integer and key parameters of LEP link messages MAY be any value.
Scripts that receive LEP link_message events SHOULD immediately filter out messages that are not targeted to them by name using "ts". Target scripts MAY accept substrings of script names to allow a script to target some, but not all, scripts in a prim, if desired.
LEP-RPC is a JSON-based remote procedure call (RPC) protocol. LEP-RPC allows scripts to segregate messages between broadcasts, requests, and successful and unsuccessful responses.
The string parameter of a LEP-RPC message MUST be a base LEP message JSON object with the following additional pairs:
| Name | Type | Description |
|---|---|---|
| "t" | JSON string | MUST be "RPC". |
| "id" | JSON string | Broadcast: MUST be omitted. This indicates that the source does not want a response. Targets SHOULD NOT respond to such messages. Request: MUST be a unique identifier for the request, typically a UUID. If a script receives a properly targeted request, it SHOULD respond. Response: MUST be the unique identifier sent with the associated request. |
| "m" | JSON string | Broadcast/Request: MUST be a "method string", i.e. a hierarchically-defined action to perform. A method string is a list (array) dumped to a period (".") delineated string, such as "foo.bar.baz". MUST NOT be a JSON array. Response: MUST be the method string sent with the associated request. |
| "p" | JSON data | Broadcast/Request: MAY be omitted. Otherwise, MUST be any JSON data. Response: SHOULD be the JSON data sent with the associated request. This data MAY be modified in response to the request. It MAY be omitted. |
| "r" | JSON data | Broadcast/Request: MUST be omitted. Successful response: MUST be any JSON data (object, array, string, etc.). Even if this value is not used, it MUST be set. Error response: MUST be omitted.. |
| "e" | JSON object | Broadcast/Request: MUST be omitted. Successful response: MUST be omitted. Error response: MUST be a JSON object, defined below.. |
Error responses must contain an "e" object with the following pairs:
| Name | Type | Description |
|---|---|---|
| "c" | JSON number | MUST be any integer. This SHOULD be an error code. |
| "m" | JSON string | MUST be any string. This SHOULD be an error message. |
| "d" | JSON data | MAY be any JSON data. If set, this SHOULD be additional error data. |
Scripts that receive LEP-RPC messages SHOULD route messages as broadcasts, requests, results, and errors by checking if "id", "r", and "e" are defined.
A sample broadcast (note that whitespace and line breaks are for readability only, and SHOULD be omitted for memory efficiency):
{
"ss":"Source Script Name",
"ts":"",
"t":"RPC",
"m":"texts.sample.distribute",
"p":{
"foo":"This data is optional and may be any JSON data, not just an object",
"bar":"Scripts MAY omit the \"p\" value if not needed",
"baz":"This message should be processed by all scripts in the target link(s)"
}
}
A sample request:
{
"ss":"UI",
"ts":"Filesystem",
"t":"RPC",
"id":"(any value, typically a UUID)",
"m":"file.save",
"p":{
"name":"helloworld.txt",
"readonly":false,
"memo":"The existence of the \"id\" value above, but not \"r\" or \"e\", makes this a request"
}
}
A sample response with result:
{
"ss":"Filesystem",
"ts":"UI",
"t":"RPC",
"id":"(the value sent in the request)",
"m":"file.save",
"p":{
"name":"helloworld.txt",
"readonly":false,
"memo":"The existence of the \"r\" value below makes this a response with result; also, the \"p\" value MAY be omitted or modified"
},
"r":"This could be any JSON data, but a string suffices to say that the file was saved"
}
A sample response with error:
{
"ss":"Filesystem",
"ts":"UI",
"t":"RPC",
"id":"(the value sent in the request)",
"m":"file.save",
"p":{
"name":"helloworld.txt",
"readonly":false,
"memo":"The existence of the \"e\" value below makes this a response with error; also, the \"p\" value MAY be omitted or modified"
},
"e":{
"c":1,
"m":"file already exists"
"d":{
"ipsum":"The \"d\" value in the error information is optional, but can be used to pass additional error data for debugging"
}
}
}
LEP-RLS is a remote script loading protocol for llRemoteLoadScriptPin. LEP-RLS provides a standardized method to negotiate safe transfers of scripts between prims.
TODO
LEP-aware scripts MUST process incoming link_message events by running the below checks. If a check fails, the script SHOULD immediately release the event with return to reduce script time (or run additional code to interpret non-LEP messages). The script MAY log this dropped message.
For the purposes of this example, the link_message event handler is defined as follows:
link_message(integer source_link, integer flags, string message, key data)
flags contains required flags (for example, if the script only needs to process errors, check that flags & STATUS_ERROR = STATUS_ERROR).source_link is a known link number.message using list parameters = llParseStringKeepNulls(message, ["\n"], []).parameters contains at least two elements.parameters is either a blank string, matches the recipient script's name, or matches a substring of the recipient script's name.After a message passes these checks, recipient SHOULD process the message as desired. For performance, it is RECOMMENDED to iterate through the remaining elements of parameters, if any, through an if-else or if-return tree.
I need to pass a newline in the parameters list. Can I use a different llDumpList2String separator?
No. The implementation MUST use "\n" to be in compliance with the LEP specification. If your implementation needs to pass strings with newlines in parameters, consider using llEscapeURL/llUnescapeURL or llStringToBase64/llBase64ToString on individual elements of parameters.
Why is the metadata added to the string parameter instead of the key parameter?
Typecasting is almost free, but not totally free in LSL's limited memory space. If the message is discarded while processing the metadata, data is never typecast from key to string. Typecasting data into a new string is only necessary if the message needs to be processed.
LEP was authored by Nelson Jenkins on behalf of GSI.