Difference between revisions of "User:Void Singer/Saucer"

From Second Life Wiki
Jump to navigation Jump to search
m (moved to it's own page)
 
m (updating form LSL tags to SOURCE tags)
 
(One intermediate revision by the same user not shown)
Line 9: Line 9:
=== What is it? ===
=== What is it? ===
----
----
Saucer is an optional open source extension to [[Teacup]] that helps prevent missing or bad pages from delaying webpage loads.
Saucer is an optional open source Extension to [[Teacup]] that helps prevent missing or bad pages from delaying webpage loads.


=== How does it work? ===
=== How does it work? ===
Line 21: Line 21:
=== Saucer ===
=== Saucer ===
----
----
* Save to a [[Mono#How_to_use_Mono|MONO]] script named '''"Saucer v0.3.1"''' and place in the same prim as [[Teacup]]
* Save to a [[Mono#How_to_use_Mono|MONO]] script named '''"Saucer v0.5"''' and place in the same prim as [[Teacup]]
<lsl>/*( Saucer v0.3.1 )*/
<source lang="lsl2">/*( Saucer v0.5 )*/




/*//-- Request Handler variables --//*/
/*//-- Request Handler variables --//*/
list    gLstPag = [""]; //-- List of known pages
list    gLstPag;   //-- List of known pages
list    gLst404Tim; //-- 404 timeout
list    gLst404Tim; //-- 404 timeout
list    gLst404Key; //-- 404 request key
list    gLst404Key; //-- 404 request key
Line 34: Line 34:


default{
default{
    state_entry(){
state_entry(){
        gIntLnk = llGetLinkNumber();
gIntLnk = llGetLinkNumber();
        llMessageLinked( LINK_SET, 418, "Saucer Start", NULL_KEY );
llMessageLinked( LINK_SET, 418, "Saucer Start", NULL_KEY );
    }
}
   
    link_message( integer vIntSrc, integer vIntDta, string vStrDta, key vKeyDta ){
link_message( integer vIntSrc, integer vIntDta, string vStrDta, key vKeyDta ){
        if (vKeyDta){ //-- server traffic?
if (vKeyDta){ //-- server traffic?
            if (418 == vIntDta && gIntLnk == vIntSrc){ //-- server request? // next line: Ignore Known Pages
if (418 == vIntDta && gIntLnk == vIntSrc){ //-- server request? // next line: Ignore Known Pages
                if (!~vIntDta = llListFindList( gLstPag, [vStrDta = llList2String( llParseStringKeepNulls( vStrDta, ["?"], [] ), 0 )] )){
if (!~vIntDta = llListFindList( gLstPag, [vStrDta = llList2String( llParseStringKeepNulls( vStrDta, ["?"], [] ), 0 )] )){
                    gLst404Key += [vKeyDta]; //-- Pending 404 key (used to detect lazy page additions or Send 404s)
gLst404Key += [vKeyDta]; //-- Pending 404 key (used to detect lazy page additions or Send 404s)
                    gLst404Pag += [vStrDta]; //-- Pending 404 name (used for lazy Know Page additions)
gLst404Pag += [vStrDta]; //-- Pending 404 name (used for lazy Know Page additions)
                    gLst404Tim += [llGetUnixTime() + 2]; //-- Timeout value: this actually amount to a ~2.25sec timeout
gLst404Tim += [llGetUnixTime() + 2]; //-- Timeout value: this actually amount to a ~2.25sec timeout
                    if (gLst404Tim == [""]){ //-- Only start timer for first pending 404, avoids bumping the timer forward.
if (gLst404Tim == [""]){ //-- Only start timer for first pending 404, avoids bumping the timer forward.
                        llSetTimerEvent( 0.75 ); //-- Fast to deal with fast pages requests
llSetTimerEvent( 0.75 ); //-- Fast to deal with fast pages requests
                    }
}
                } //-- Next Line: Check for unadvertised responses for pending 404s
} //-- Next Line: Check for unadvertised responses for pending 404s
            }else if (~vIntSrc = llListFindList( gLst404Key, [vKeyDta] )){
}else if (~vIntSrc = llListFindList( gLst404Key, [vKeyDta] )){
                if (200 == vIntDta){ //-- auto discovery of  unadvertised pages
if (200 == vIntDta){ //-- auto discovery of  unadvertised pages
                    gLstPag += [llList2String( gLst404Pag, vIntSrc )];
gLstPag += [llList2String( gLst404Pag, vIntSrc )];
                }
}
                gLst404Tim = llDeleteSubList( gLst404Tim, vIntSrc, vIntSrc );
gLst404Tim = llDeleteSubList( gLst404Tim, vIntSrc, vIntSrc );
                gLst404Key = llDeleteSubList( gLst404Key, vIntSrc, vIntSrc );
gLst404Key = llDeleteSubList( gLst404Key, vIntSrc, vIntSrc );
                gLst404Pag = llDeleteSubList( gLst404Pag, vIntSrc, vIntSrc );
gLst404Pag = llDeleteSubList( gLst404Pag, vIntSrc, vIntSrc );
            }
}
        }else if (601 == ( vIntDta | 1 ) && NULL_KEY == (string)vKeyDta){
}else if (601 == (1 | vIntDta) && NULL_KEY == (string)vKeyDta){
            if (1 & vIntDta){ //-- 601: Page Added
if (1 & vIntDta){ //-- 601 = add file (if NOT found)
                if (!~vIntDta = llListFindList( gLstPag, [vStrDta] )){
if (!~vIntDta = llListFindList( gLstPag, [vStrDta] )){
                    gLstPag += [vStrDta]; //-- only add if not already known
gLstPag += [vStrDta];
                }
}
            }else{ //-- 600: Page Removed
}else{ //-- 600 remove file (only if found, avoids wrong index)
                if (~vIntDta = llListFindList( gLstPag, [vStrDta] )){ //-- only remove if found, avoids wrong index
if (~vIntDta = llListFindList( gLstPag, [vStrDta] )){
                    gLstPag = llDeleteSubList( gLstPag, vIntDta, vIntDta );
gLstPag = llDeleteSubList( gLstPag, vIntDta, vIntDta );
                }
}
            }
}
        }
}
    }
}
   
    timer(){ //-- handle pending 404s
timer(){ //-- handle pending 404s
        if (gLst404Tim != []){ //-- Pending 404s?
if (gLst404Tim != []){ //-- Pending 404s?
            while (llList2Integer( gLst404Tim, 0 ) < llGetUnixTime()){ //-- Timeouts expired?
while (llList2Integer( gLst404Tim, 0 ) < llGetUnixTime()){ //-- Timeouts expired?
                llMessageLinked( llGetLinkNumber(), 404, "Not Found", llList2Key( gLst404Key, 0 ) );
llMessageLinked( llGetLinkNumber(), 404, "404 Not Found", llList2Key( gLst404Key, 0 ) );
                gLst404Tim = llDeleteSubList( gLst404Tim, 0, 0 ); //-- Send 404, Remove pending
gLst404Tim = llDeleteSubList( gLst404Tim, 0, 0 ); //-- Send 404, Remove pending
                gLst404Key = llDeleteSubList( gLst404Key, 0, 0 );
gLst404Key = llDeleteSubList( gLst404Key, 0, 0 );
                gLst404Pag = llDeleteSubList( gLst404Pag, 0, 0 );
gLst404Pag = llDeleteSubList( gLst404Pag, 0, 0 );
                if (gLst404Tim == []){ //-- Pending Queue empty?
if (gLst404Tim == []){ //-- Pending Queue empty?
                    llSetTimerEvent( 0.0 );
llSetTimerEvent( 0.0 );
                    return; //-- Stop timer, & exit
return; //-- Stop timer, & exit
                }
}
            }
}
        }else{ //-- No Pending 404s, stop timer
}else{ //-- No Pending 404s, stop timer
            llSetTimerEvent( 0.0 );
llSetTimerEvent( 0.0 );
        }
}
    }
}
}
}
/*//--                          License Text                          --//*/
/*//--                          License Text                          --//*/
Line 93: Line 93:
/*//  Void Singer [ https://wiki.secondlife.com/wiki/User:Void_Singer ]  //*/
/*//  Void Singer [ https://wiki.secondlife.com/wiki/User:Void_Singer ]  //*/
/*//  All usages must contain a plain text copy of the previous 2 lines.  //*/
/*//  All usages must contain a plain text copy of the previous 2 lines.  //*/
/*//--                                                                  --//*/</lsl>
/*//--                                                                  --//*/</source>
:[[User:Void Singer/Saucer#Return_to_Void_Singers_user_page|Return to top]]
:[[User:Void Singer/Saucer#Return_to_Void_Singers_user_page|Return to top]]
}}
}}
Line 103: Line 103:
Saucer accepts three special messages using the [[User:Void_Singer/Teacup#Protocol|Teacup Protocols]].
Saucer accepts three special messages using the [[User:Void_Singer/Teacup#Protocol|Teacup Protocols]].
: "File Removed"
: "File Removed"
<lsl>llMessageLinked( LINK_SET, 600, "File Name", NULL_KEY ); //-- as called by another script</lsl>
<source lang="lsl2">llMessageLinked( LINK_SET, 600, "File Name", NULL_KEY ); //-- as called by another script</source>
: "File Added"
: "File Added"
<lsl>llMessageLinked( LINK_SET, 601, "File Name", NULL_KEY ); //-- as called by another script</lsl>
<source lang="lsl2">llMessageLinked( LINK_SET, 601, "File Name", NULL_KEY ); //-- as called by another script</source>
: "100 Continue"
: "100 Continue"
<lsl>llMessageLinked( LINK_SET, 100, "File Name", REQUEST_KEY ); //-- as called by another script</lsl>
<source lang="lsl2">llMessageLinked( LINK_SET, 100, "File Name", REQUEST_KEY ); //-- as called by another script</source>
where "File Name" is the name of the file that the service is adding, removing, or serving. and REQUEST_KEY is the key of the request from the server for that file.
where "File Name" is the name of the file that the service is adding, removing, or serving. and REQUEST_KEY is the key of the request from the server for that file.
* [[LINK_SET]] should be replaced with the server prim number when known to prevent spamming messages
* [[LINK_SET]] should be replaced with the server prim number when known to prevent spamming messages
Line 132: Line 132:
* [[User:Void_Singer/Teacup|Teacup]] - [[Server_In_a_Prim|SIP]] front end
* [[User:Void_Singer/Teacup|Teacup]] - [[Server_In_a_Prim|SIP]] front end
* [[User:Void_Singer/Red_Tea|Red Tea]] - A very simple [[Server_In_a_Prim|SIP]] back end File Service for a starting point.
* [[User:Void_Singer/Red_Tea|Red Tea]] - A very simple [[Server_In_a_Prim|SIP]] back end File Service for a starting point.
* [[User:Void_Singer/Region_Stats|Region Stats]] - A single page Extension that gets live data from the region and refreshes every minute
* [[User:Void_Singer/Tea_Strainer|Tea Strainer]] - Optional Troubleshooting Monitor for checking messages being sent and received.
* [[User:Void_Singer/Tea_Strainer|Tea Strainer]] - Optional Troubleshooting Monitor for checking messages being sent and received.


Line 148: Line 149:
----
----
Most Recent Changes are at the top, old version links below.
Most Recent Changes are at the top, old version links below.
* Version will be considered stable when it reaches 1.0
* Code will be considered stable when it reaches v1.0
* Saucer v0.3.1
* [[Saucer|Saucer v0.5]]
** Update to match version number on [[Teacup]], transparent tweaks and page formatting.
* [http://wiki.secondlife.com/w/index.php?title=User:Void_Singer/Saucer&oldid=1141626 Saucer v0.3.1]
** Separated from The [[Teacup]] Server, and Messaging Protocol tweaked
** Separated from The [[Teacup]] Server, and Messaging Protocol tweaked
* [https://wiki.secondlife.com/w/index.php?title=User:Void_Singer/Teacup&oldid=1141137#Saucer Saucer v0.3]
* [http://wiki.secondlife.com/w/index.php?title=User:Void_Singer/Teacup&oldid=1141137#Saucer Saucer v0.3]
** Initial Public Release
** Initial Public Release



Latest revision as of 07:58, 26 January 2015

Saucer

What is it?


Saucer is an optional open source Extension to Teacup that helps prevent missing or bad pages from delaying webpage loads.

How does it work?


Once Saucer starts up, it advertises it's existence to available file sources, which can signal which pages they have available to serve. If it hears a request from the Teacup server, it checks to see if the requested page is already known to it, and if so, does nothing. If not, the page name is added to a queue and then Saucer waits a few seconds to see if anything responds to that request; if not, it sends a "404 Not Found" message to the server so that webpages waiting for it can know that the file isn't available and continue immediately. If a service does respond to the request within 2 seconds, with a "100 Continue", Saucer will not send a 404 message for that request. Additionally, any request that is filled via a "200 Success" message, will be added to it's list of known files.

Code

Saucer


  • Save to a MONO script named "Saucer v0.5" and place in the same prim as Teacup
/*( Saucer v0.5 )*/


/*//-- Request Handler variables --//*/
list    gLstPag;    //-- List of known pages
list    gLst404Tim; //-- 404 timeout
list    gLst404Key; //-- 404 request key
list    gLst404Pag; //-- 404 page name (used for discovery only)
integer gIntLnk;    //-- link number to save on function calls


default{
	state_entry(){
		gIntLnk = llGetLinkNumber();
		llMessageLinked( LINK_SET, 418, "Saucer Start", NULL_KEY );
	}
	
	link_message( integer vIntSrc, integer vIntDta, string vStrDta, key vKeyDta ){
		if (vKeyDta){ //-- server traffic?
			if (418 == vIntDta && gIntLnk == vIntSrc){ //-- server request? // next line: Ignore Known Pages
				if (!~vIntDta = llListFindList( gLstPag, [vStrDta = llList2String( llParseStringKeepNulls( vStrDta, ["?"], [] ), 0 )] )){
					gLst404Key += [vKeyDta]; //-- Pending 404 key (used to detect lazy page additions or Send 404s)
					gLst404Pag += [vStrDta]; //-- Pending 404 name (used for lazy Know Page additions)
					gLst404Tim += [llGetUnixTime() + 2]; //-- Timeout value: this actually amount to a ~2.25sec timeout
					if (gLst404Tim == [""]){ //-- Only start timer for first pending 404, avoids bumping the timer forward.
						llSetTimerEvent( 0.75 ); //-- Fast to deal with fast pages requests
					}
				} //-- Next Line: Check for unadvertised responses for pending 404s
			}else if (~vIntSrc = llListFindList( gLst404Key, [vKeyDta] )){
				if (200 == vIntDta){ //-- auto discovery of  unadvertised pages
					gLstPag += [llList2String( gLst404Pag, vIntSrc )];
				}
				gLst404Tim = llDeleteSubList( gLst404Tim, vIntSrc, vIntSrc );
				gLst404Key = llDeleteSubList( gLst404Key, vIntSrc, vIntSrc );
				gLst404Pag = llDeleteSubList( gLst404Pag, vIntSrc, vIntSrc );
			}
		}else if (601 == (1 | vIntDta) && NULL_KEY == (string)vKeyDta){
			if (1 & vIntDta){ //-- 601 = add file (if NOT found)
				if (!~vIntDta = llListFindList( gLstPag, [vStrDta] )){
					gLstPag += [vStrDta];
				}
			}else{ //-- 600 remove file (only if found, avoids wrong index)
				if (~vIntDta = llListFindList( gLstPag, [vStrDta] )){
					gLstPag = llDeleteSubList( gLstPag, vIntDta, vIntDta );
				}
			}
		}
	}
	
	timer(){ //-- handle pending 404s
		if (gLst404Tim != []){ //-- Pending 404s?
			while (llList2Integer( gLst404Tim, 0 ) < llGetUnixTime()){ //-- Timeouts expired?
				llMessageLinked( llGetLinkNumber(), 404, "404 Not Found", llList2Key( gLst404Key, 0 ) );
				gLst404Tim = llDeleteSubList( gLst404Tim, 0, 0 ); //-- Send 404, Remove pending
				gLst404Key = llDeleteSubList( gLst404Key, 0, 0 );
				gLst404Pag = llDeleteSubList( gLst404Pag, 0, 0 );
				if (gLst404Tim == []){ //-- Pending Queue empty?
					llSetTimerEvent( 0.0 );
					return; //-- Stop timer, & exit
				}
			}
		}else{ //-- No Pending 404s, stop timer
			llSetTimerEvent( 0.0 );
		}
	}
}
/*//--                           License Text                           --//*/
/*//  Free to copy, use, modify, distribute, or sell, with attribution.   //*/
/*//    (C)2011 (CC-BY) [ http://creativecommons.org/licenses/by/3.0 ]    //*/
/*//   Void Singer [ https://wiki.secondlife.com/wiki/User:Void_Singer ]  //*/
/*//  All usages must contain a plain text copy of the previous 2 lines.  //*/
/*//--                                                                  --//*/
Return to top

Protocol

Special Messages

Saucer accepts three special messages using the Teacup Protocols.

"File Removed"
llMessageLinked( LINK_SET, 600, "File Name", NULL_KEY ); //-- as called by another script
"File Added"
llMessageLinked( LINK_SET, 601, "File Name", NULL_KEY ); //-- as called by another script
"100 Continue"
llMessageLinked( LINK_SET, 100, "File Name", REQUEST_KEY ); //-- as called by another script

where "File Name" is the name of the file that the service is adding, removing, or serving. and REQUEST_KEY is the key of the request from the server for that file.

  • LINK_SET should be replaced with the server prim number when known to prevent spamming messages

Basic Functions

Upon startup, Saucer will advertise it's availability with "Saucer Start"

Services that take longer than 2 seconds to respond normally have two options to avoid their pages being timed out quickly

  1. Send a "File Added" message for each file name they service when they start, and when they receive the "Saucer Start" advertisement
    • File names added in this manner should be removed with "File Removed" when no longer available
    • "File Added" messages should be throttled to no more than a few per second, suggest adding a delay based on link number.
  2. Immediately send a "100 Continue" message for server requested file names, then send the requested file normally when available.
    • This method does not require removal unless sent with a "200 Success" code. Instead, use codes "201 Created", "202 Accepted", or "204 No Content"

other services that can respond quickly should send files with "200 Success" where applicable to prevent additional processing by Saucer. Otherwise they should use Option 1 above.

  • Any file sent with a "200 Success" code will be added to the known files list
Return to top

Notes

Compatible Servers, File Systems, and Extensions


  • Teacup - SIP front end
  • Red Tea - A very simple SIP back end File Service for a starting point.
  • Region Stats - A single page Extension that gets live data from the region and refreshes every minute
  • Tea Strainer - Optional Troubleshooting Monitor for checking messages being sent and received.

Known Bugs


  • Current version responds to any unknown code in the proper format as if it were a "100 Continue".
    • This may be cleaned up in a future revision, Do not rely on this behavior
  • Not really a bug, but inefficient... must have one copy for each server
    • probably needs revised to save the server source too so that it can handle multiple Teacups

Requested Feature Upgrades


  • Got a feature request? add it here

Change Log / Old Versions


Most Recent Changes are at the top, old version links below.

  • Code will be considered stable when it reaches v1.0
  • Saucer v0.5
    • Update to match version number on Teacup, transparent tweaks and page formatting.
  • Saucer v0.3.1
    • Separated from The Teacup Server, and Messaging Protocol tweaked
  • Saucer v0.3
    • Initial Public Release
Return to top

Questions or Comments?

Feel free to leave me a note on the discussion page.