User:Strife Onizuka/Projects/TestHost/Coordinator

From Second Life Wiki
Jump to navigation Jump to search

Scripts

It was my thought to combine the different types of slave scripts to reduce the number of scripts.

Interface Coordinator

This script handles the bidirectional communication between the high level and the lower level interfaces. It's job is to interpret the commands sent from the user (from a specific Interface script) and relay them to the appropriate script. Likewise it must also send messages from low level interfaces to the user in an understandable fashion.

Because there are multiple interfaces I've listed priorities for completion. Optional interfaces may or may not get implemented but are included as a place holder.

//////////////////////////////////////////////////
//
//	Coordinator Interface
//	Version 0.1 Alpha
//	ESL Compiled: "Mar 22 2007", "09:06:42"
//	Copyright (C) 2007  Linden Research, Inc
//	
//	http://lindenlab.com
//
//////////////////////////////////////////////////

//===================================================//
//                 Combined Library                  //
//  Copyright (C) 2004-2007, Strife Onizuka (cc-by)  //
//    http://creativecommons.org/licenses/by/3.0/    //
//===================================================//
//{

//Tightlist family of functions Version 1.0
//Copyright Strife Onizuka 2004-2007
//Free to use and distribute as long as this message is not removed.

list TightListParse(string input)
{
    string seperator = llGetSubString(input,(0),(0));//save memory
    return llParseStringKeepNulls(llDeleteSubString(input,(0),(0)), [input=seperator],[]);
}

list stack;
integer position;

//{ Stack Functions

string popL()				{	return llToLower(llList2String(stack, (position = -~position)));	}

//}

list ParamGrouping(string input)
{//Faster but uses more bytecode
	list out;
	string buffer;
	integer null;
	integer group = 1;
	integer quote_index = llSubStringIndex(input, "\"");
	integer space_index = llSubStringIndex(input, ",");
	while(quote_index ^ space_index)//when they are both negitive we are done.
	{
		//process which ever came first or available; the "&" makes -1 into max_int
		//we could bake "& 0x7FFFFFFF" into them, but it uses more bytecode and in
		//this case it would still need to get executed (so it is moot).

		if((quote_index & 0x7FFFFFFF) < (space_index & 0x7FFFFFFF))
		{//quote
			//flip the group bit, add the buffer, set the null catch.
			null = ((buffer += llDeleteSubString(input, quote_index, -1)) == "") * (group = !group);
			if(~space_index)//only if it was found should it be adjusted
				space_index += ~quote_index;//"x += ~y" is mathematicly equivelent to "x -= y + 1"
			quote_index = llSubStringIndex(input = llDeleteSubString(input, 0, quote_index), "\"");
		}
		else
		{//space
			buffer += llDeleteSubString(input, space_index + !group, 0x10000);
			if(group)
			{//if the group bit isn't set then dump the buffer
				if(buffer != "" || null)
				{
					out += Unescape(llStringTrim(buffer, STRING_TRIM));
					null = (integer)(buffer = "");
				}
			}
			if(~quote_index)//only if it was found should it be adjusted
				quote_index += ~space_index;//"x += ~y" is mathematicly equivelent to "x -= y + 1"
			space_index = llSubStringIndex(input = llDeleteSubString(input, 0, space_index), ",");
		}
	}
	if((buffer += input) != "" || null)
		out += Unescape(llStringTrim(buffer, STRING_TRIM));
	return out;
}

string Unescape(string a)
{//Requires less memory then the other two versions (UnescapeTight)
//Please visit the website for instructions about this function
// http://lslwiki.com/lslwiki/wakka.php?wakka=FunctionUnescape
// http://rpgstats.com/wiki/index.php?title=FunctionUnescape
    string  b = a;
    integer c = -1;
    integer f = 0;
    @loop;
    integer d = -~llSubStringIndex(b, "\\");
    if(d)
    {
        integer e = llSubStringIndex("uUhts\"q\\n", llGetSubString(a, -~(c += d), -~c));
        if(2 < e)
            a = llInsertString(llDeleteSubString(a,c, -~c), c, llGetSubString("     \"\"\\\n", e * (e != 3), e));
        else if(2 == e)
        {
            if(c + (e = (integer)("0x"+llGetSubString(a,c+2,c+2)) << !(integer)(b = "")) + 2 >= (f = llStringLength(b)))
                e = (f + ~d) & -2;
            if((f = e))//this may look like a mistake, it's not
            {
                do
                    b = "%"+llGetSubString(a,c - ~e,c + e + 2) + b;
                while((e-=2) > 0);
            }
            a = llInsertString(llDeleteSubString(a,c, c + f + 2),c, b = llUnescapeURL(b));
            c = c + ~-llStringLength(b);//add to c so we don't accidentily unescape result
        }
        else if(~e)// \uXXXX or  \UXXXXXXXX
        {
            a = llDeleteSubString(a, c, (e = 4 << e) - ~c);
            if(0 < e = (integer)("0x" + llGetSubString(b, -~d, d + e)))
            {
                b = "%" + byte2hex((e >> (6 * f)) | ((0x7F80 >> f) <<
                    !(f = ((e >= 0x80) + (e >= 0x800) + (e >= 0x10000) + (e >= 0x200000) + (e >= 0x4000000)))));
                while(f)
                    b += "%" + byte2hex((((e >> (6 * (f=~-f))) | 0x80) & 0xBF));
                a = llInsertString(a, c, llUnescapeURL(b));
            }
        }
        b = llDeleteSubString(a,0,c);
        jump loop;
    }
    return a;
}

string byte2hex(integer x)
{//Helper function for use with unicode characters.
    return llGetSubString(hexc, x = ((x >> 4) & 0xF), x) + llGetSubString(hexc, x & 0xF, x & 0xF);
}

string hexc="0123456789ABCDEF";

//}

//==================//
//      Source      //
//==================//


integer main_chan;
integer control_chan;
integer test_broadcast_chan;
integer chat_chan;
integer verbosity;
integer msg_proxy_chan;

integer mode;
//integer w;

integer slave;
integer slaves = 1;


default
{
    state_entry()
    {
        llListen(main_chan, "", "", "");
        llListen(test_broadcast_chan, "", "", "");
    }
    listen(integer a, string b, key c, string d)
    {
        if(a == test_broadcast_chan)
        {
            stack = TightListParse(d);
        }
        else if(a == control_chan)
        {
            stack = TightListParse(d);
        }
        else if(a == main_chan)
        {

            integer help = ("help" == llToLower(llList2String(stack = ParamGrouping(d), position = ([] != stack))));
            if(help) b = popL();
            if("coordinator" == b){
                if("summary" == b = popL()){
                    if("configure" == b = popL()){
                        if("say" == b = popL()){
                            if(help) llSay(0, llList2CSV(llList2List(stack, help, position) + "(integer-channel, 'public', 'debug', 'off', 'on' 'default')\ndefault = debug"));
                            else {
                                if(llGetSubString(b,0,0) == "0" || (a = (integer)(b = popL()))){
                                    chat_chan = a;
                                    mode = mode | 0x1;
                                }
                                else if(~a = llListFindList(["public","debug", "default"],[b])){
                                    chat_chan = DEBUG_CHANNEL * !!a;
                                    mode = mode | 0x1;
                                }

                                else if(~a = llListFindList(["off","on"],[b]))
                                    mode = (mode & 0xFFFFFFFe) | a;//

                                else
                                    llSay(0, llList2CSV(llList2List(stack, help, ~-position))+": "+b + " - unkown command");
                            }
                        }
                        else if("controller" == b){
                            if(help) llSay(0, llList2CSV(llList2List(stack, help, position) + "('off', 'on' 'default')\nEnables proxing of output to Controller\ndefault = on"));

                            else if(~a = llListFindList(["off","on"],[popL()]))
                                mode = (mode & 0xFFFFFFFd) | (a * 0x2);

                            else
                                llSay(0, llList2CSV(llList2List(stack, help, ~-position))+": "+b + " - unkown command");
                        }
                        else if("im" == b){
                            if(help) llSay(0, llList2CSV(llList2List(stack, help, position) + "(UUID or 'me')"));
                            else {
                                if("me" != b = llList2String(stack, (position = -~position)))
                                    c = b;
                                if(c);else
                                    c = "";
                                llSay(DEBUG_CHANNEL, "FixMe #"+ (string)115 +": "+ llList2CSV(llList2List(stack, 0, position)));
                            }
                        }
                        else if("email" == b){
                            if("address" == b = popL()){
                                if(help) llSay(0, llList2CSV(llList2List(stack, help, position) + "(email address)"));
                                else {
                                    llSay(DEBUG_CHANNEL, "FixMe #"+ (string)122 +": "+ llList2CSV(llList2List(stack, 0, position)));
                                }
                            }
                            else if("mode" == b){
                                if(help) llSay(0, llList2CSV(llList2List(stack, help, position) + "('single','digest')"));
                                else {
                                    llSay(DEBUG_CHANNEL, "FixMe #"+ (string)128 +": "+ llList2CSV(llList2List(stack, 0, position)));
                                }
                            }
                            else if(help) llSay(0, llList2CSV(llList2List(stack, help, position) + "[address, mode]"));
                        }
                        else if("http" == b){
                            if("url" == b = popL()){
                                if(help) llSay(0, llList2CSV(llList2List(stack, help, position) + "(url)"));
                                else {
                                    llSay(DEBUG_CHANNEL, "FixMe #"+ (string)137 +": "+ llList2CSV(llList2List(stack, 0, position)));
                                }
                            }
                            else if("mode" == b){
                                if(help) llSay(0, llList2CSV(llList2List(stack, help, position) + "('single','digest','default')\ndefault = digest"));
                                else {
                                    llSay(DEBUG_CHANNEL, "FixMe #"+ (string)143 +": "+ llList2CSV(llList2List(stack, 0, position)));
                                }
                            }
                            else if(help) llSay(0, llList2CSV(llList2List(stack, help, position) + "('url', 'mode')"));
                        }
                        else if("verbosity" == b){
                            if(help) llSay(0, llList2CSV(llList2List(stack, help, position) + "('quiet', 'normal', 'warnings', 'verbose', 'default', integer-level)\n0) Quiet - summary information only\n2) Normal - failures and summary information\n4) Warnings - failures, warnings and summering information\n6) Verbose - failures, warnings, comments and summering information\ndefault = normal"));
                            else if(llGetSubString(b,0,0) == "0" || (a = (integer)(b = popL()))){
                                verbosity = a;
                            }
                            else if(~a = llListFindList(["quiet", "normal", "warnings", "verbose", "default"],[b])) {
                                if(a ^ 4)
                                    verbosity = a * 2;
                                else
                                    verbosity = 2;
                                llSay(DEBUG_CHANNEL, "FixMe #"+ (string)158 +": "+ llList2CSV(llList2List(stack, 0, position)));
                            }
                        }
                        else if(help) llSay(0, llList2CSV(llList2List(stack, help, position) + "['say', 'controller', 'im', 'email', 'http', 'verbosity']\nconfigures how summaries are gathered and displayed."));
                    }
                    else if("read" == b){
                        if(help) llSay(0, llList2CSV(llList2List(stack, help, position) + "outputs the summary"));
                        else
                        {
                            llSay(DEBUG_CHANNEL, "FixMe #"+ (string)167 +": "+ llList2CSV(llList2List(stack, 0, position)));
                        }
                    }
                    else if("clear" == b){
                        if(help) llSay(0, llList2CSV(llList2List(stack, help, position) + "clears the summary"));
                        else
                        {
                            llSay(DEBUG_CHANNEL, "FixMe #"+ (string)174 +": "+ llList2CSV(llList2List(stack, 0, position)));
                        }
                    }
                    else if(help) llSay(0, llList2CSV(llList2List(stack, help, position) + "['configure', 'read', 'clear']"));
                }
                else if("setup" == b){
                    if(help) llSay(0, llList2CSV(llList2List(stack, help, position) + "return to setup"));
                    else
                    {
                        llSay(DEBUG_CHANNEL, "FixMe #"+ (string)183 +": "+ llList2CSV(llList2List(stack, 0, position)));
                    }
                }
                else if("reset" == b){
                    if(help) llSay(0, llList2CSV(llList2List(stack, help, position) + ""));
                    else
                    {
                        //send reset command to all tests
                        llSay(DEBUG_CHANNEL, "FixMe #"+ (string)191 +": "+ llList2CSV(llList2List(stack, 0, position)));
                    }
                }
                else if("list" == b){
                    if("tests" == b = popL()){
                        if(help) llSay(0, llList2CSV(llList2List(stack, help, position) + ""));
                        else
                        {
                            llSay(DEBUG_CHANNEL, "FixMe #"+ (string)199 +": "+ llList2CSV(llList2List(stack, 0, position)));
                        }
                    }
                    else if("groups" == b){
                        if(help) llSay(0, llList2CSV(llList2List(stack, help, position) + ""));
                        else
                        {
                            llSay(DEBUG_CHANNEL, "FixMe #"+ (string)206 +": "+ llList2CSV(llList2List(stack, 0, position)));
                        }
                    }
                    else if(b)
                        llSay(0, llList2CSV(llList2List(stack, help, ~-position))+": "+b + " - unkown command");
                    else if(help) llSay(0, llList2CSV(llList2List(stack, help, position) + "[tests, groups]"));
                }
                else if(b)
                    llSay(0, llList2CSV(llList2List(stack, help, ~-position))+": "+b + " - unkown command");
                else if(help) llSay(0, llList2CSV(llList2List(stack, help, position) + "[summary, setup, reset, list]"));
            }
            else if("test" == b){
                if("list" == b = popL()){
                    if(help) llSay(0, llList2CSV(llList2List(stack, help, position) + "lists available tests"));
                    else
                    {
                        llSay(DEBUG_CHANNEL, "FixMe #"+ (string)222 +": "+ llList2CSV(llList2List(stack, 0, position)));
                    }
                }
                else
                {
                    d = popL();
                    if("start" == b){
                        if(help) llSay(0, llList2CSV(llList2List(stack, help, position) + "starts test " + d));
                        else
                        {
                            llSay(DEBUG_CHANNEL, "FixMe #"+ (string)232 +": "+ llList2CSV(llList2List(stack, 0, position)));
                        }
                    }
                    else if("stop" == b){
                        if(help) llSay(0, llList2CSV(llList2List(stack, help, position) + "stops test " + d));
                        else
                        {
                            llSay(DEBUG_CHANNEL, "FixMe #"+ (string)239 +": "+ llList2CSV(llList2List(stack, 0, position)));
                        }
                    }
                    else if("about" == b){
                        if(help) llSay(0, llList2CSV(llList2List(stack, help, position) + "displays about text for test " + d));
                        else
                        {
                            llSay(DEBUG_CHANNEL, "FixMe #"+ (string)246 +": "+ llList2CSV(llList2List(stack, 0, position)));
                        }
                    }
                    else if(b)
                        llSay(0, llList2CSV(llList2List(stack, help, ~-position))+": "+b + " - unkown command");
                    else if(help) llSay(0, llList2CSV(llList2List(stack, help, position) + "['start', 'stop', 'about', 'list']"));
                }
            }
            else if("group" == b){

            }
            else if(b)
                llSay(0, llList2CSV(llList2List(stack, help, ~-position))+": "+b + " - unkown command");
            else if(help) llSay(0, llList2CSV(llList2List(stack, help, position) + "[coordinator, test, group]"));
        }
        stack = [];
    }
    link_message(integer a, integer b, string c, key d)
    {
        if(1011 == b) //"COMM_DIGEST_FULL"
        {
            if(0x8 & mode) //"COMM_MODE_EMAIL_DIGEST"
            {
                llMessageLinked(LINK_THIS, 1101 + (slave = ((-~slave) % slaves)), c, d);
            }
            else if(0x20 & mode) //"COMM_MODE_HTTP_DIGEST"
            {
                llMessageLinked(LINK_THIS, 1201 + (slave = ((-~slave) % slaves)), c, d);
            }
            else if(0x40 & mode) //"COMM_MODE_IM"
            {
                llMessageLinked(LINK_THIS, 1301 + (slave = ((-~slave) % slaves)), c, d);
            }
        }
        else if(1000 == b) //"COMM_MSG"
        {
            if(0x1 & mode) //"COMM_MODE_SAY"
            {
                llSay(chat_chan, c);
            }
            else if(0x2 & mode) //"COMM_MODE_MSG_PROXY"
            {
                llSay(msg_proxy_chan, c);
            }
            else if(0x4 & mode) //"COMM_MODE_EMAIL_SINGLE"
            {
                llMessageLinked(LINK_THIS, 1101 + (slave = ((-~slave) % slaves)), c, d);
            }
            else if(0x28 & mode) //"COMM_MODE_DIGEST"
            {
                llMessageLinked(LINK_THIS, 1010, c, d);
            }
            else if(0x10 & mode) //"COMM_MODE_HTTP_SINGLE"
            {
                llMessageLinked(LINK_THIS, 1201 + (slave = ((-~slave) % slaves)), c, d);
            }
            else if(0x40 & mode) //"COMM_MODE_IM"
            {
                llMessageLinked(LINK_THIS, 1301 + (slave = ((-~slave) % slaves)), c, d);
            }
        }
    }
}

Slave & DB

Priority: 10 - Required by Spec

//////////////////////////////////////////////////
//
//	Coordinator Interface Slaves
//	Version 0.1 Alpha
//	ESL Compiled: "Mar 22 2007", "12:27:31"
//	Copyright (C) 2007  Linden Research, Inc
//	
//	http://lindenlab.com
//
//////////////////////////////////////////////////

//==================//
//      Source      //
//==================//


integer slave;
integer next = 0;

string url;
string mail;
key dialog;
key im;

list db;
integer size;

default
{
    state_entry()
    {
        slave = (integer)llList2String(llParseString2List(llGetScriptName(),[" "],[]), -1);
        llMessageLinked(LINK_THIS, 1500 + slave, (string)slave, "");
    }
    link_message(integer a, integer b, string c, key d)
    {
        if(1100 == b) //"COMM_EMAIL_SETUP"
            mail = d;
        else if(1200 == b) //"COMM_HTTP_SETUP"
            url = d;
        else if(1300 == b) //"COMM_IM_SETUP"
            im = d;
        else if(1400 == b) //"COMM_DIALOG_SETUP"
            dialog = d;
        else if(1020 == b) //"COMM_DB_GET"
        {
            if((b = ~llListFindList(db, [d])))
                llMessageLinked(LINK_THIS, 1021, llList2String(db, -b), d);//"COMM_DB_VALUE"
        }
        else if(1022 == b) //"COMM_DB_REMOVE"
        {
            if((b = ~llListFindList(db, [d])))
            {
                size -= llStringLength((string)llList2List(db, ~b, -b)) + 10;
                db = llDeleteSubList(db, ~b, -b);
            }
        }
        else if(1023 == b) //"COMM_DB_CLEAR"
            size = (integer)((string)(db = []));
        else if(1101 == (b -= slave)) //"COMM_EMAIL"
            llEmail(mail, c, d);
        else if(1201 == b) //"COMM_HTTP"
            llHTTPRequest( url, [], d );
        else if(1301 == b) //"COMM_IM"
            llInstantMessage(im, d);
        else if(1401 == b) //"COMM_DIALOG"
            llDialog(dialog, d, [], -1);
        else if(1501 == b) //"COMM_SLAVE"
            next = (integer)c;
        else if(1601 == b) //"COMM_DB_ADD"
        {
            if((integer)c != slave)
            {
                if(size < 6000)
                {
                    size += llStringLength(d) + 8;
                    c = llGetSubString(d, 0, 0);
                    if((b = -~llSubStringIndex(llDeleteSubString(d, 0, 0), c)))
                        db = (db = [(key)llDeleteSubString(d, b, 0), llDeleteSubString(d, 0, b)]) + db;
                }
                else
                    llMessageLinked(LINK_THIS, 1601 + next, (string)slave, d);
            }
            else
                llSay(DEBUG_CHANNEL, "FixMe #"+ (string)85 +": "+ "DB_FULL_ERROR()");
        }
    }
    http_response( key request_id, integer status, list metadata, string body )
    {
        ;
    }
}

Chat Interface - Input/Output

Priority: 10 - Required by Spec


Email Interface Handler - Input/Output

Priority: 9 - Required by Spec


Email Slaves


HTTP Interface - Output

Priority: 7 - Required by Spec


Dialog Interface Handler - Input/Output

Priority: 5 - Optional



Dialog Box Slaves


XML-RPC Interface - Input/Output?

Priority: 1 - Optional


State Handler

This script keeps track of the scripts state and handles messages from the IC (Interface Coordinator ). If the command cannot be parsed at that time because the script is in the wrong state, then an error message is returned to the IC. In the event of a test start command being sent, it passes the load command on to the TT (Test Tracker).


Test Tracker

The Test Tracker keeps track of test names, groups and test keys. It receives the command to start a test from the State Handler and configures the Test Runner.

list groups;
list uuids;
list tests; //[integer group_index, string name, integer inv_uuid_index]

Test Runner

The test runner receives its configuration information from the Test Tracker and actualy starts the tests specified. As the test information is returned it stores information in the Test Log Slaves.



Test Log Slaves

A simple database for storing test logs.