Difference between revisions of "User:Void Singer/Red Tea"

From Second Life Wiki
Jump to navigation Jump to search
m (~updates)
m (Compatibility update)
Line 26: Line 26:
# Copy the text in the grey box below [[User:Void Singer/Teacup#teacup.js|Code: teacup.js]] into a notecard named "teacup.js", save it, and drop it in your rezzed box
# Copy the text in the grey box below [[User:Void Singer/Teacup#teacup.js|Code: teacup.js]] into a notecard named "teacup.js", save it, and drop it in your rezzed box
#* You May want to Edit this file to your liking first... You can ''add'' most valid javascript functions that do not rely on body onload behavior.
#* You May want to Edit this file to your liking first... You can ''add'' most valid javascript functions that do not rely on body onload behavior.
# Copy the text in the grey box below [[User:Void Singer/Teacup#teacup.css|Code: teacup.css]] into a notecard named "teacup.css", save it, and drop it in your rezzed box
#* You May want to Edit this file to your liking first... You can use any valid css.
# Copy the text in the grey box below [[User:Void Singer/Red_Tea#Sample_Index.tsp|Code: Sample Index.tsp]] into a notecard named "index.tsp", save it, and drop it in your rezzed box
# Copy the text in the grey box below [[User:Void Singer/Red_Tea#Sample_Index.tsp|Code: Sample Index.tsp]] into a notecard named "index.tsp", save it, and drop it in your rezzed box
#* You May want to Edit this file to your liking first... You can use any html that is valid inside of a body tag.
#* You May want to Edit this file to your liking first... You can use any html that is valid inside of a body tag.
Line 42: Line 40:
=== Red Tea ===
=== Red Tea ===
----
----
* Save in a [[Mono#How_to_use_Mono|MONO]] script named "'''Red Tea v0.3.1'''"
* Save in a [[Mono#How_to_use_Mono|MONO]] script named "'''Red Tea v0.5'''"
<lsl>/*( Red Tea v0.3.1 )*/
<lsl>/*( Red Tea v0.5 )*/
   
   
//-- Master Handling lists
//-- Master Handling lists
Line 58: Line 56:
integer gIntNcd;
integer gIntNcd;
string  gStrTmp;
string  gStrTmp;
 
default{
default{
    state_entry(){
state_entry(){
        //-- grab all possible notecard names
//-- grab all possible notecard names
        if (gIntCap = llGetInventoryNumber( INVENTORY_NOTECARD )){
if (gIntCap = llGetInventoryNumber( INVENTORY_NOTECARD )){
            llWhisper( 0, "Attempting to load " + (string)gIntCap + " notecards" );
llWhisper( 0, "Attempting to load " + (string)gIntCap + " notecards" );
            do{
do{
                gLstNom += [llGetInventoryName( INVENTORY_NOTECARD, gIntNcd )];
gLstNom += [llGetInventoryName( INVENTORY_NOTECARD, gIntNcd )];
            }while (++gIntNcd < gIntCap);
}while (++gIntNcd < gIntCap);
            //-- work on the firs one.
//-- work on the firs one.
            gKeyQry = llGetNotecardLine( gStrNcd = llList2String( gLstNom, 0 ), gIntNcd = 0 );
gKeyQry = llGetNotecardLine( gStrNcd = llList2String( gLstNom, 0 ), gIntNcd = 0 );
            gIntCap = llGetFreeMemory();
gIntCap = llGetFreeMemory();
        }else{
}else{
            llWhisper( 0, "No content to load" );
llWhisper( 0, "No content to load" );
        }
}
    }
}
   
    changed( integer vBitChg ){
changed( integer vBitChg ){
        if (CHANGED_INVENTORY & vBitChg){
if (CHANGED_INVENTORY & vBitChg){
            //-- when inventory changes, only restart if the notecard count changed
//-- when inventory changes, only restart if the notecard count changed
            if (llGetInventoryNumber( INVENTORY_NOTECARD ) != (gLstNom != [])){
if (llGetInventoryNumber( INVENTORY_NOTECARD ) != (gLstNom != [])){
                llSetTimerEvent( 3.0 );
llSetTimerEvent( 5.0 );
            }
}
        }
}
    }
}
   
    timer(){
timer(){
        llResetScript();
llResetScript();
    }
}
   
    dataserver( key vKeyQID, string vStrDta ){
dataserver( key vKeyQID, string vStrDta ){
        if (gKeyQry == vKeyQID){ //-- is this our dataserver event?
if (gKeyQry == vKeyQID){ //-- is this our dataserver event?
            if (EOF == vStrDta){ //-- did we finish the notecard?
if (EOF == vStrDta){ //-- did we finish the notecard?
                if (~llSubStringIndex( gStrNcd, ".tsp" )){ //-- is this a html page?
if (~llSubStringIndex( gStrNcd, ".tsp" )){ //-- is this a html page?
                    gStrTmp = "vTea='" + gStrTmp + "';"; //-- wrap it
gStrTmp = "v0='" + gStrTmp + "';"; //-- wrap it
                }
}
                gLstTxt += [(gStrTmp = "") + gStrTmp]; //-- save it
gLstTxt += [(gStrTmp = "") + gStrTmp]; //-- save it
                llWhisper( 0, gStrNcd + " successfully loaded");
llWhisper( 0, gStrNcd + " successfully loaded");
                llMessageLinked( LINK_SET, 601, gStrNcd, NULL_KEY );
llMessageLinked( LINK_SET, 601, gStrNcd, NULL_KEY ); //-- saucer compatibility
                if ((integer)(vStrDta = (string)(gIntCap - llGetFreeMemory())) > gIntBfr){
if ((integer)(vStrDta = (string)(gIntCap - llGetFreeMemory())) > gIntBfr){
                    gIntBfr = (integer)vStrDta; //-- adjust buffer if needed
gIntBfr = (integer)vStrDta; //-- adjust buffer if needed
                } //-- test if we have more cards to read and room to spare
} //-- test if we have more cards to read and room to spare
                if ((gIntNcd = -~llListFindList( gLstNom, [gStrNcd] )) < (gLstNom != []) && (gIntCap = llGetFreeMemory()) > gIntBfr){
if ((gIntNcd = -~llListFindList( gLstNom, [gStrNcd] )) < (gLstNom != []) && (gIntCap = llGetFreeMemory()) > gIntBfr){
                    gKeyQry = llGetNotecardLine( gStrNcd = llList2String( gLstNom, gIntNcd ), gIntNcd = 0 ); //-- get next card
gKeyQry = llGetNotecardLine( gStrNcd = llList2String( gLstNom, gIntNcd ), gIntNcd = 0 ); //-- get next card
                }else{ //-- out of cards or space
}else{ //-- out of cards or space
                    gStrTmp = gKeyQry = ""; //-- clear vars
gStrTmp = gKeyQry = ""; //-- clear vars
                    //-- save totals and set conditional failure message
//-- save totals and set conditional failure message
                    if ((gIntCap = (gLstNom != [])) > (gIntNcd = (gLstTxt != []))){
if ((gIntCap = (gLstNom != [])) > (gIntNcd = (gLstTxt != []))){
                        gStrNcd = "\nFailed to read " + gStrNcd;  
gStrNcd = "\nFailed to read " + gStrNcd;  
                    }else{
}else{
                        gStrNcd = gStrTmp;
gStrNcd = gStrTmp;
                    }//-- report load
}//-- report load
                    llWhisper( 0, "Loaded " + (string)gIntNcd + " of " + (string)gIntCap + " pages" + (gStrNcd = "") +
llWhisper( 0, "Loaded " + (string)gIntNcd + " of " + (string)gIntCap + " pages" + (gStrNcd = "") +
                                  gStrNcd + "\n~" + (string)(llGetFreeMemory() - gIntBfr) + " bytes free"  );
              gStrNcd + "\n~" + (string)(llGetFreeMemory() - gIntBfr) + " bytes free"  );
                }
}
            }else{ //-- notecard read
}else{ //-- notecard read
                if (~llSubStringIndex( gStrNcd, ".tsp" )){ //-- is this a html page?
if (~llSubStringIndex( gStrNcd, ".tsp" )){ //-- is this a html page?
                    //-- tweak for javascript wrapper compatibility
//-- tweak for javascript wrapper compatibility
                    vStrDta = llDumpList2String( llParseStringKeepNulls( vStrDta, ["\\"], [] ), "\\\\" ); //-- "
vStrDta = llDumpList2String( llParseStringKeepNulls( vStrDta, ["\\"], [] ), "\\\\" ); //-- "
                    vStrDta = llDumpList2String( llParseStringKeepNulls( vStrDta, ["'"], [] ), "\\'" ) + "\\n";
vStrDta = llDumpList2String( llParseStringKeepNulls( vStrDta, ["'"], [] ), "\\'" ) + "\\n";
                }else{
}else{
                    vStrDta += "\n";
vStrDta += "\n";
                }
}
                gStrTmp += vStrDta; //-- accumulate to variable
gStrTmp += vStrDta; //-- accumulate to variable
                if ((integer)(vStrDta = (string)(gIntCap - llGetFreeMemory())) > gIntBfr){
if ((integer)(vStrDta = (string)(gIntCap - llGetFreeMemory())) > gIntBfr){
                    gIntBfr = (integer)vStrDta; //-- adjust buffer if needed
gIntBfr = (integer)vStrDta; //-- adjust buffer if needed
                }
}
                if ((gIntCap >> 1) > gIntBfr){ //-- test free space against buffer
if ((gIntCap >> 1) > gIntBfr){ //-- test free space against buffer
                    gKeyQry = llGetNotecardLine( gStrNcd, ++gIntNcd ); //-- get next line
gKeyQry = llGetNotecardLine( gStrNcd, ++gIntNcd ); //-- get next line
                }else{ //-- our saftey cap was exceeded, stop and report what we have
}else{ //-- our saftey cap was exceeded, stop and report what we have
                    gLstNom = llDeleteSubList( gLstNom, gIntNcd, -1 );
gLstNom = llDeleteSubList( gLstNom, gIntNcd, -1 );
                    gIntCap = (gLstNom != []);
gIntCap = (gLstNom != []);
                    gIntNcd = (gLstTxt != []);
gIntNcd = (gLstTxt != []);
                    gStrTmp = gKeyQry = "";
gStrTmp = gKeyQry = "";
                    llWhisper( 0, "Loaded " + (string)gIntNcd + " of " + (string)gIntCap + " page(s)\nFailed while reading " +
llWhisper( 0, "Loaded " + (string)gIntNcd + " of " + (string)gIntCap + " page(s)\nFailed while reading " +
                                  gStrNcd + "\n~" + (string)(llGetFreeMemory() - gIntBfr) + " bytes free"  );
              gStrNcd + "\n~" + (string)(llGetFreeMemory() - gIntBfr) + " bytes free"  );
                }
}
            }
}
        }
}
    }
}
   
    link_message( integer vIntSrc, integer vIntDta, string vStrDta, key vKeyDta ){
link_message( integer vIntSrc, integer vIntDta, string vStrDta, key vKeyDta ){
        if (vKeyDta){ //-- valid key?
if (vKeyDta){ //-- valid key?
            if (418 == vIntDta){ //-- server request?
if (418 == vIntDta){ //-- server request?
                if (~vIntDta = llListFindList( gLstNom, [llList2String( llParseStringKeepNulls( vStrDta, [], ["?", "#"] ), 0 )] )){ //-- do we have that?
if (~vIntDta = llListFindList( gLstNom, [llList2String( llParseStringKeepNulls( vStrDta, [], ["?", "#"] ), 0 )] )){ //-- do we have that?
                    llMessageLinked( vIntSrc, 200, llList2String( gLstTxt, vIntDta ), vKeyDta );
llMessageLinked( vIntSrc, 200, llList2String( gLstTxt, vIntDta ), vKeyDta );
                }
}
            }
}
        }//-- we serve pages fast, so we don't report loaded pages on saucer startup message and instead rely on lazy detection
}//-- fast service, no need to add saucer start compatibility
    }
}
}
}
/*//--                          License Text                          --//*/
/*//--                          License Text                          --//*/
Line 161: Line 159:
* Save in a notecard named "'''index.tsp'''"
* Save in a notecard named "'''index.tsp'''"
  <html4strict><h1>This is a sample Index Page</h1>
  <html4strict><h1>This is a sample Index Page</h1>
<p>would you like to <a href="page1.tsp">go to page 1</a>?</p></html4strict>
<p>would you like to <a href="page1.tsp">go to page 1</a>?<br>
Would you like to <a onClick="u1('Region Stats.tsp');" style="color:blue;text-decoration:underline;cursor:pointer;">view the Region Stats</a>?</p></html4strict>
^ [[User:Void Singer/Red_Tea#Return_to_Void_Singers_user_page|Return to top]]
^ [[User:Void Singer/Red_Tea#Return_to_Void_Singers_user_page|Return to top]]


Line 168: Line 167:
* Save in a notecard named "'''page1.tsp'''"
* Save in a notecard named "'''page1.tsp'''"
  <html4strict><h1>This is a sample linked page</h1>
  <html4strict><h1>This is a sample linked page</h1>
<p>would you like to <a href="index.tsp">go to the index</a>?</p></html4strict>
<p>Would you like to <a onClick="u1('Region Stats.tsp');" style="color:blue;text-decoration:underline;cursor:pointer;">view the Region Stats</a>?<br>
would you like to <a href="index.tsp">go to the index</a>?</p></html4strict>
:[[User:Void Singer/Red_Tea#Return_to_Void_Singers_user_page|Return to top]]
:[[User:Void Singer/Red_Tea#Return_to_Void_Singers_user_page|Return to top]]
}}
}}
Line 178: Line 178:
----
----
* [[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/Saucer|Saucer]] - Optional Fast 404 Extension for preventing long timeouts for missing/bad pages
* [[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 193: Line 193:
=== ChangeLog / Old Versions ===
=== ChangeLog / Old Versions ===
----
----
* Version will be considered stable when it reaches 1.0
* Code will be considered stable when it reaches v1.0
* [[User:Void_Singer/Red_Tea|Red Tea v0.3.1]]
* [[User:Void_Singer/Red_Tea|Red Tea v0.5]]
** Compatibility update to match [[Teacup|Teacup v0.5]]
** Sample pages updated
* [http://wiki.secondlife.com/w/index.php?title=User:Void_Singer/Red_Tea&oldid=1141629 Red Tea v0.3.1]
** tweaked for changes to [[Saucer]]
** tweaked for changes to [[Saucer]]
* [https://wiki.secondlife.com/w/index.php?title=User:Void_Singer/Red_Tea&oldid=1141144 Red Tea v0.3]
* [http://wiki.secondlife.com/w/index.php?title=User:Void_Singer/Red_Tea&oldid=1141144 Red Tea v0.3]
** No longer sends 404 messages of it's own
** No longer sends 404 messages of it's own
** No longer restarts on every inventory change, only if the notecard count changes from what it has already read.
** No longer restarts on every inventory change, only if the notecard count changes from what it has already read.
* [https://wiki.secondlife.com/w/index.php?title=User:Void_Singer/Red_Tea&oldid=1140507 v0.2]
* [http://wiki.secondlife.com/w/index.php?title=User:Void_Singer/Red_Tea&oldid=1140507 v0.2]
** Initial Public Release
** Initial Public Release



Revision as of 22:28, 3 May 2011

Red Tea

What is it?

Red Tea is an open source File Service custom built for Teacup/Saucer

How does it work?

When Red Tea starts, it looks for any notecards in the prim, reads them, converting and wrapping any notecards with names ending with ".tsp", then storing them in memory, waiting for a request from the Teacup server. If the number of notecards changes it waits 3 seconds then restarts.

Format Requirments?

Red Tea reads a modified html page from a notecard

  • For html content, the notecard name should end with ".tsp"
  • For html content, the notecard contents are limited to what's valid inside a normal html "body" tag.
  • no more than 255 bytes per line in the notecard (this is an LSL limitation)
Return to top

Quick Start

So you don't want to read a bunch of tech babble, you just want to make a website in a prim right? Well I can sympathize so here are some (mostly) easy steps to get you up and running fast...

  1. Rez a box and name it something creative, like "My website"
  2. Copy the text in the grey box below Code: teacup.js into a notecard named "teacup.js", save it, and drop it in your rezzed box
    • You May want to Edit this file to your liking first... You can add most valid javascript functions that do not rely on body onload behavior.
  3. Copy the text in the grey box below Code: Sample Index.tsp into a notecard named "index.tsp", save it, and drop it in your rezzed box
    • You May want to Edit this file to your liking first... You can use any html that is valid inside of a body tag.
  4. Copy the text in the grey box below Code: Sample Page1.js into a notecard named "page1.tsp", save it, and drop it in your rezzed box
    • You May want to Edit this file to your liking first... You can use any html that is valid inside of a body tag.
  5. Copy the text in the grey box below Code: Red Tea into a script named "Red Tea v0.3.1", save it, and drop it in your rezzed box
  6. Go here and start at step 2...
Return to top

Code

Red Tea


  • Save in a MONO script named "Red Tea v0.5"

<lsl>/*( Red Tea v0.5 )*/

//-- Master Handling lists list gLstNom; list gLstTxt;

//-- These track memory while loading integer gIntCap; integer gIntBfr;

//-- these handle the notecard loading key gKeyQry; string gStrNcd; integer gIntNcd; string gStrTmp;

default{ state_entry(){ //-- grab all possible notecard names if (gIntCap = llGetInventoryNumber( INVENTORY_NOTECARD )){ llWhisper( 0, "Attempting to load " + (string)gIntCap + " notecards" ); do{ gLstNom += [llGetInventoryName( INVENTORY_NOTECARD, gIntNcd )]; }while (++gIntNcd < gIntCap); //-- work on the firs one. gKeyQry = llGetNotecardLine( gStrNcd = llList2String( gLstNom, 0 ), gIntNcd = 0 ); gIntCap = llGetFreeMemory(); }else{ llWhisper( 0, "No content to load" ); } }

changed( integer vBitChg ){ if (CHANGED_INVENTORY & vBitChg){ //-- when inventory changes, only restart if the notecard count changed if (llGetInventoryNumber( INVENTORY_NOTECARD ) != (gLstNom != [])){ llSetTimerEvent( 5.0 ); } } }

timer(){ llResetScript(); }

dataserver( key vKeyQID, string vStrDta ){ if (gKeyQry == vKeyQID){ //-- is this our dataserver event? if (EOF == vStrDta){ //-- did we finish the notecard? if (~llSubStringIndex( gStrNcd, ".tsp" )){ //-- is this a html page? gStrTmp = "v0='" + gStrTmp + "';"; //-- wrap it } gLstTxt += [(gStrTmp = "") + gStrTmp]; //-- save it llWhisper( 0, gStrNcd + " successfully loaded"); llMessageLinked( LINK_SET, 601, gStrNcd, NULL_KEY ); //-- saucer compatibility if ((integer)(vStrDta = (string)(gIntCap - llGetFreeMemory())) > gIntBfr){ gIntBfr = (integer)vStrDta; //-- adjust buffer if needed } //-- test if we have more cards to read and room to spare if ((gIntNcd = -~llListFindList( gLstNom, [gStrNcd] )) < (gLstNom != []) && (gIntCap = llGetFreeMemory()) > gIntBfr){ gKeyQry = llGetNotecardLine( gStrNcd = llList2String( gLstNom, gIntNcd ), gIntNcd = 0 ); //-- get next card }else{ //-- out of cards or space gStrTmp = gKeyQry = ""; //-- clear vars //-- save totals and set conditional failure message if ((gIntCap = (gLstNom != [])) > (gIntNcd = (gLstTxt != []))){ gStrNcd = "\nFailed to read " + gStrNcd; }else{ gStrNcd = gStrTmp; }//-- report load llWhisper( 0, "Loaded " + (string)gIntNcd + " of " + (string)gIntCap + " pages" + (gStrNcd = "") + gStrNcd + "\n~" + (string)(llGetFreeMemory() - gIntBfr) + " bytes free" ); } }else{ //-- notecard read if (~llSubStringIndex( gStrNcd, ".tsp" )){ //-- is this a html page? //-- tweak for javascript wrapper compatibility vStrDta = llDumpList2String( llParseStringKeepNulls( vStrDta, ["\\"], [] ), "\\\\" ); //-- " vStrDta = llDumpList2String( llParseStringKeepNulls( vStrDta, ["'"], [] ), "\\'" ) + "\\n"; }else{ vStrDta += "\n"; } gStrTmp += vStrDta; //-- accumulate to variable if ((integer)(vStrDta = (string)(gIntCap - llGetFreeMemory())) > gIntBfr){ gIntBfr = (integer)vStrDta; //-- adjust buffer if needed } if ((gIntCap >> 1) > gIntBfr){ //-- test free space against buffer gKeyQry = llGetNotecardLine( gStrNcd, ++gIntNcd ); //-- get next line }else{ //-- our saftey cap was exceeded, stop and report what we have gLstNom = llDeleteSubList( gLstNom, gIntNcd, -1 ); gIntCap = (gLstNom != []); gIntNcd = (gLstTxt != []); gStrTmp = gKeyQry = ""; llWhisper( 0, "Loaded " + (string)gIntNcd + " of " + (string)gIntCap + " page(s)\nFailed while reading " + gStrNcd + "\n~" + (string)(llGetFreeMemory() - gIntBfr) + " bytes free" ); } } } }

link_message( integer vIntSrc, integer vIntDta, string vStrDta, key vKeyDta ){ if (vKeyDta){ //-- valid key? if (418 == vIntDta){ //-- server request? if (~vIntDta = llListFindList( gLstNom, [llList2String( llParseStringKeepNulls( vStrDta, [], ["?", "#"] ), 0 )] )){ //-- do we have that? llMessageLinked( vIntSrc, 200, llList2String( gLstTxt, vIntDta ), vKeyDta ); } } }//-- fast service, no need to add saucer start compatibility } } /*//-- 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. //*/ /*//-- --//*/</lsl> ^ Return to top

Sample Index.tsp


  • Save in a notecard named "index.tsp"
<html4strict>

This is a sample Index Page

would you like to <a href="page1.tsp">go to page 1</a>?
Would you like to <a onClick="u1('Region Stats.tsp');" style="color:blue;text-decoration:underline;cursor:pointer;">view the Region Stats</a>?

</html4strict>

^ Return to top

Sample Page1.tsp


  • Save in a notecard named "page1.tsp"
<html4strict>

This is a sample linked page

Would you like to <a onClick="u1('Region Stats.tsp');" style="color:blue;text-decoration:underline;cursor:pointer;">view the Region Stats</a>?
would you like to <a href="index.tsp">go to the index</a>?

</html4strict>
Return to top

Notes

Compatible Servers and Extensions


  • Teacup - SIP front end
  • Saucer - Optional Fast 404 Extension for preventing long timeouts for missing/bad pages
  • Tea Strainer - Optional Troubleshooting Monitor for checking messages being sent and received.

Known Bugs


  • Extra line break inserted at the end of every ".tsp" or text file
  • If the server request a file that has a notecard, before that notecard is finished loading, a 200 "Success" response will be generated and an empty file will be served.
  • Loading large files before small ones may lock them out if the buffer limit is reached. Try to read small files first. (they are read in alphabetic order)

Planned Upgrades


  • None really, the intent is to be an example. other "flavors" can use different methods. but it may get minor updates as time passes

ChangeLog / Old Versions


  • Code will be considered stable when it reaches v1.0
  • Red Tea v0.5
    • Compatibility update to match Teacup v0.5
    • Sample pages updated
  • Red Tea v0.3.1
  • Red Tea v0.3
    • No longer sends 404 messages of it's own
    • No longer restarts on every inventory change, only if the notecard count changes from what it has already read.
  • v0.2
    • Initial Public Release
Return to top

Questions or Comments?

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