Jump to content
Sign in to follow this  
Estelle Pienaar

LSL HTTP server/example for a notecard sending server

Recommended Posts

I am putting this concrete example for an LSL http server up here as a reaction to a forum thread: 

I have changed an existing script of mine as a proof of concept in order to provide a concrete example how an http bridge could work in this concrete use case. When I learned to script http servers and how to send a php message to an object in Second Life, I found it very tiresome. I have not found one single working concrete example, only code snippets. There are also almost no detailed example how to use the method "POST" with an html request, most use "GET". It was especially hard for me to get my head around the PHP side of things as I had never used php before. (Disclaimer: I have not yet tested these scripts, there might be a showstopping bug somewhere. Also my PHP scripts are very basic. As far as I know they are safe to be used in the presented use case as no one can change the data sent to your SQL database. But in different use cases malicious code could be injected to your database.)

A. Let's start with the SQL database and create a table for storing the URL of our server (a scripted object in Second Life):

CREATE TABLE SERVERURL (
    Instance int,
    ObjectName varchar(255),
    ObjectKey varchar(36),
    URL varchar(255),
    
);

B. Here is the LSL script for the server prim: It does 3 things: (1) Request an URL; (2) It sends the latest URL via a PHP script (see C.) to the SQL database table SERVERURL (see A.); (3) If a client terminal sends a http request to the the server prim, it will send all containing notecards to the clients:

string objectName;
string objectKey;
string url;

key requestKey;

setup(){
    objectName = llGetObjectName();
    objectKey = llGetKey();
    llRequestURL();}

default
{
    state_entry()
    
    {
        setup();
        llSetText("Server: Loading", <1.0, 1.0, 1.0>, 1.0);
    }
    
    on_rez(integer n)
    {
        setup();
    }
  
    changed(integer c) 
    {
        if ((c & ((CHANGED_REGION | CHANGED_REGION_START) | CHANGED_TELEPORT))) 
        {
            setup();
        }
    }
http_request(key id,string method,string body) 
    {

///////////////////////////////////////////////////////
//Below we receive the answer for our URL-request. This URL will later be used by the terminals to request the notecards. 

        if ((method == URL_REQUEST_GRANTED)) 
          	{
            url = body;
            llSay(0, "I received a new URL: " + url);
            llSetText("Server: Online", <1.0, 1.0, 1.0>, 1.0); 
//Sending the received URL and other information to SQL database///////////
    //Packing info//
            string URL = "http://your-database-address.com/myURL.php";
            list parameters = [HTTP_METHOD,"POST",HTTP_MIMETYPE, "application/x-www-form-urlencoded"];
            string bodySend = "objectName="+ objectName+"&objectKey="+objectKey+"&Newurl="+url;
    //End packing information//
 
    //send the info
        	requestKey = llHTTPRequest(URL, parameters,bodySend);
        	//llOwnerSay("Debugging: Sending the following information to DB: " + bodySend;
//End of sending information to database/////////////////
            
        	}
        else  if ((method == URL_REQUEST_DENIED)) {
            llOwnerSay("Something went wrong, no url. " + body);
            llSetText("Server: Offline", <1.0, 1.0, 1.0>, 1.0);

//End of code block for receiving and sending an URL 
/////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
//The incoming requests of the terminals, to receive notecards will arrive here: 

        }
        else  if ((method == "POST")) 
            {
            //llOwnerSay("Debugging: I received a message from '" + (string)id + "': " + body);
            
        /* I use the following code block if the script receives several information packets in the body of one html request. The information packets are seperated by '&'. As there is only one information sent for the purpouse of this example, it is not needed here.
            list temp = llParseString2List(body,["&"],[]);
            string msg1 = llList2String(temp,0);
            string msg2 = llList2String(temp,1);
            string msg3 = llList2String(temp,2);
        */
            
            if (body == "sendmeNotecard")
                {
            //llOwnerSay("Debugging: Message 'sendmeNotecard' received.");
            integer z = llGetInventoryNumber( INVENTORY_NOTECARD );
            integer f = (z-1);

                if (z == 0)    
                    {
                    //The server prim does not contain notecards and sends this information to the client terminal
          			llHTTPResponse(id,200,("msg received, server has no NC"));
                    }
                else if (z > 0)
                    {
          			//The server prim contains z notecards and sends the information to the client terminal that it will receive them.
                    llHTTPResponse(id,200,("The server will now send " + (string)z + " Notecards."));
                    
                    //Sending z notecards in a loop.
          			integer p;
                    for (p=1;p<=z;p++)
                        {
                        llGiveInventory( id, llGetInventoryName(INVENTORY_NOTECARD, f) );
                        f +=1; 
                        }
                    }
                }
            else
                {
                //The client terminal or another prim has sent an message to the URL that is different to "sendmeNotecard".
                llOwnerSay("Debugging : unexpected php message: " + body);
                llHTTPResponse(id,200,("The server received an unexpected message."));
                }                                
        }
         
        else  
            {
            llHTTPResponse(id,405,"Method unsupported");
            llOwnerSay("Debugging: Method for http_request unsupported");
        	}
    }

 http_response( key request_id, integer status, list metadata, string body )

  {        
// The PHP script will send its response here after it has processed the new URL.     
    if (request_id == requestKey)

        {
    llOwnerSay("Debugging: The http_response from the database when registering the url is:" + body);
        }                               
  }

}

C. This PHP script creates a new entry or sends an update of the URL to the SQL table:

<?php

//You need to insert your specific data for "DB_HOSTNAME","DB_USERNAME","DB_PASSWORD","DB_DATABASE"
$con=mysqli_connect("DB_HOSTNAME","DB_USERNAME","DB_PASSWORD","DB_DATABASE");

// Check connection
if (mysqli_connect_errno()) {
  echo "Failed to connect to MySQL: " . mysqli_connect_error();
    //you need to exit the script, if there is an error
    exit();
}

//Set the variables (with incoming information)
//Disclaimer: Depending on the use case, this is not a safe method to secure incoming variables from injection
$objectName = mysqli_real_escape_string($con, $_POST['objectName']); 
$objectKey = mysqli_real_escape_string($con, $_POST['objectKey']); 
$Newurl = mysqli_real_escape_string($con, $_POST['Newurl']);

//The following function checks if the object has already been entered in the database table
$query = mysqli_query($con,"SELECT * FROM SERVERURL WHERE ObjectName = '$objectName'");
$row_cnt = mysqli_num_rows($query); //Counts the entries:


	if ($row_cnt == 0) //the object has not been registered in the table so far
	{
      	//we now create an entry for the object details and the URL
        $sql="INSERT INTO SERVERURL (ObjectName, ObjectKey, URL) VALUES ('$objectName','$objectKey','$Newurl')";

		if (mysqli_query($con, $sql)) {
    		echo "DNS record created.";
		} else {
    		echo "Error creating DNS record: " . mysqli_error($con);
		}   
    }

    else //the object has already been registered in the table, so we only need to update the URL
    
    {
        $query1 = mysqli_query($con, "UPDATE SERVERURL SET URL = '$Newurl', ObjectKey = '$objectKey' WHERE  ObjectName = '$objectName' " );

        //Response to the server prim. If "0" rows in the database are affected, something has gone wrong... 
        echo "Affected rows: " . mysqli_affected_rows($con); 
    }

//close connection to database
mysqli_close($con); ?>

D. Now that the URL of the server prim is stored in the database the LSL script of the client terminals can (1) ask the database for the URL (see E.) and (2) send a request for the notecards to the server prim:

string serverURL;
string serverName = "Put the object name of your server here.";

key requestKey;
key requestKey1;

default
{
    state_entry()
    {
        llSay(0, "Hello, my friend!");
    }

    touch_start(integer total_number)
    {
    //Asking for Server URL at database///////////
        //Packing info//
        string URL = "http://your-database-address.com/getURL.php";
        list parameters = [HTTP_METHOD,"POST",HTTP_MIMETYPE, "application/x-www-form-urlencoded"];
        string bodySend = serverName;
        //End packing info//
 
        //send the request
        requestKey = llHTTPRequest(URL, parameters,bodySend);
        //llOwnerSay("Debugging: Send html-request" + (string)URL + (string)hudName);
    //End of asking for Server URL///////////////// 
    }

     http_response( key request_id, integer status, list metadata, string body )

  	{ 
      
    if (request_id == requestKey)
            {
    		serverURL = body;
    		//llOwnerSay("Debugging: The database gave the following URL for the server prim: " + body + ".");

   	//////////Sending html_request to server prim//////////
        	//Packing info//
        	string URL = serverURL;
        	list parameters = [HTTP_METHOD,"POST",HTTP_MIMETYPE, "application/x-www-form-urlencoded"];
        	string bodySend = "sendmeNotecard";
        	//End packing info//
 
        	//send the request//
        	requestKey1 = llHTTPRequest(URL, parameters,bodySend);
        	//llOwnerSay("Debugging: Send html-request" + (string)URL + bodySend);
    //////////End sending html_request to server////////
    		}
    if (request_id == requestKey1)

    		if (body == "msg received, server has no NC")
    			{
    		llOwnerSay("The server has no new notecards.");
    			}
    		else if (body == "The server received an unexpected message.")
    			{
    		llOwnerSay("An error has occured in the communication with the server.");
    			}    			
    		else
    			{
    		llOwnerSay(body);
    		//the server prim will now send notecards.    		
    			}
    }

}

E. The terminals send their request for the server URL via this php script to the database:

<?php

//You need to insert your specific data for "DB_HOSTNAME","DB_USERNAME","DB_PASSWORD","DB_DATABASE"

$con=mysqli_connect("DB_HOSTNAME","DB_USERNAME","DB_PASSWORD","DB_DATABASE");

// Check connection
if (mysqli_connect_errno()) {
  echo "Failed to connect to MySQL: " . mysqli_connect_error();
    //you need to exit the script, if there is an error
    exit();
}

//Set the variables (with incoming data); Disclaimer: For other use cases, this not a secure method against injection.
$objectName = mysqli_real_escape_string($con, $_POST['objectName']); 


		//With this function we select the URL for the prim server with the specific object name frotm the database
		$sql = "SELECT URL FROM SERVERURL WHERE ObjectName = '$objectName' ";
        $query=mysqli_query($con,$sql);
        
            //Fetch the URL from the returned information array
            while($output = mysqli_fetch_array( $query )) {

            // send the selected URL in the returned body to the terminal 
                echo $output['URL']; }

//close connection to database
mysqli_close($con); ?>

That's it. A rather basic http server - terminal script environment.

Edited by Estelle Pienaar
  • Like 1

Share this post


Link to post
Share on other sites

Unfortunately it seems not to be possible to change a post after too many edits? Too bad. I have now verified the scripts and found a few things that needed changing. So please use the two updated LSL scripts from below:

LSL Server Script (B)

string objectName;
string objectKey;
string url;

key requestKey;

setup(){
    objectName = llGetObjectName();
    objectKey = llGetKey();
    llRequestURL();}

default
{
    state_entry()
    
    {
        setup();
        llSetText("Server: Loading", <1.0, 1.0, 1.0>, 1.0);
    }
    
    on_rez(integer n)
    {
        setup();
    }
  
    changed(integer c) 
    {
        if ((c & ((CHANGED_REGION | CHANGED_REGION_START) | CHANGED_TELEPORT))) 
        {
            setup();
        }
    }
http_request(key id,string method,string body) 
    {

///////////////////////////////////////////////////////
//Below we receive the answer for our URL-request. This URL will later be used by the terminals to request the notecards. 

        if ((method == URL_REQUEST_GRANTED)) 
          	{
            url = body;
            llSay(0, "I received a new URL: " + url);
            llSetText("Server: Online", <1.0, 1.0, 1.0>, 1.0); 
//Sending the received URL and other information to SQL database///////////
    //Packing info//
            string URL = "http://your-database-address.com/myURL.php";
            list parameters = [HTTP_METHOD,"POST",HTTP_MIMETYPE, "application/x-www-form-urlencoded"];
            string bodySend = "objectName="+ objectName+"&objectKey="+objectKey+"&Newurl="+url;
    //End packing information//
 
    //send the info
        	requestKey = llHTTPRequest(URL, parameters,bodySend);
        	//llOwnerSay("Debugging: Sending the following information to DB: " + bodySend;
//End of sending information to database/////////////////
            
        	}
        else  if ((method == URL_REQUEST_DENIED)) {
            llOwnerSay("Something went wrong, no url. " + body);
            llSetText("Server: Offline", <1.0, 1.0, 1.0>, 1.0);

//End of code block for receiving and sending an URL 
/////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
//The incoming requests of the terminals, to receive notecards will arrive here: 

        }
        else  if ((method == "POST")) 
            {
            //llOwnerSay("Debugging: I received a message from '" + (string)id + "': " + body);
            
        //I use the following code block to seperate information packets with the seperator '~' 
            list temp = llParseString2List(body,["~"],[]);
            string msg1 = llList2String(temp,0);
            string msg2 = llList2String(temp,1);
    
            
            if (msg1 == "sendmeNotecard")
                {
            key sendKey = msg2;
            //llOwnerSay("Debugging: Message 'sendmeNotecard' received.");
            integer z = llGetInventoryNumber( INVENTORY_NOTECARD );
            integer f = 0;

                if (z == 0)    
                    {
                    //The server prim does not contain notecards and sends this information to the client terminal
          			llHTTPResponse(id,200,("msg received, server has no NC"));
                    }
                else if (z > 0)
                    {
          			//The server prim contains z notecards and sends the information to the client terminal that it will receive them.
                    llHTTPResponse(id,200,("The server will now send " + (string)z + " Notecards."));
                    
                    //Sending z notecards in a loop.
          			integer p;
                    for (p=1;p<=z;p++)
                        {
                        llGiveInventory( sendKey, llGetInventoryName(INVENTORY_NOTECARD, f) );
                        f +=1; 
                        }
                    }
                }
            else
                {
                //The client terminal or another prim has sent an message to the URL that is different to "sendmeNotecard".
                llOwnerSay("Debugging : unexpected php message: " + body);
                llHTTPResponse(id,200,("The server received an unexpected message."));
                }                                
        }
         
        else  
            {
            llHTTPResponse(id,405,"Method unsupported");
            llOwnerSay("Debugging: Method for http_request unsupported");
        	}
    }

 http_response( key request_id, integer status, list metadata, string body )

  {        
// The PHP script will send its response here after it has processed the new URL.     
    if (request_id == requestKey)

        {
    llOwnerSay("Debugging: The http_response from the database when registering the url is:" + body);
        }                               
  }

}

LSL client terminal script (D):

string objectKey;
string serverURL;
string serverName = "Put the object name of your server here."; //don't forget to put the real name in here!

key requestKey;
key requestKey1;

default
{
    state_entry()
    {
        llSay(0, "Hello, my friend!");
		objectKey = llGetKey();
    }

    touch_start(integer total_number)
    {
    //Asking for Server URL at database///////////
        //Packing info//
        string URL = "http://your-database-address.com/getURL.php";
        list parameters = [HTTP_METHOD,"POST",HTTP_MIMETYPE, "application/x-www-form-urlencoded"];
        string bodySend =  "objectName="+ serverName;
        //End packing info//
 
        //send the request
        requestKey = llHTTPRequest(URL, parameters,bodySend);
        //llOwnerSay("Debugging: Send html-request" + (string)URL + (string)hudName);
    //End of asking for Server URL///////////////// 
    }

     http_response( key request_id, integer status, list metadata, string body )

  	{ 
      
    if (request_id == requestKey)
            {
    		serverURL = body;
    		//llOwnerSay("Debugging: The database gave the following URL for the server prim: " + body + ".");

   	//////////Sending html_request to server prim//////////
        	//Packing info//
        	string URL = serverURL;
        	list parameters = [HTTP_METHOD,"POST",HTTP_MIMETYPE, "application/x-www-form-urlencoded"];
        	 string bodySend = "sendmeNotecard~" + (string)objectKey ;
        	//End packing info//
 
        	//send the request//
        	requestKey1 = llHTTPRequest(URL, parameters,bodySend);
        	//llOwnerSay("Debugging: Send html-request" + (string)URL + bodySend);
    //////////End sending html_request to server////////
    		}
    if (request_id == requestKey1)

    		if (body == "msg received, server has no NC")
    			{
    		llOwnerSay("The server has no new notecards.");
    			}
    		else if (body == "The server received an unexpected message.")
    			{
    		llOwnerSay("An error has occured in the communication with the server.");
    			}    			
    		else
    			{
    		llOwnerSay(body);
    		//the server prim will now send notecards.    		
    			}
    }

}

 

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this  

×
×
  • Create New...