Dispenser delle Land Italiane (scripts)

Uno script che non funziona più

Recentemente il mio vecchio script per distribuire la notecard di OpenSource, basata sul sito sn.im per fare la reindirizzazione del HTTP-IN non ha funzionato + perchè evidentemente il sito sn.im ha cambiato modalità di chiamata delle API di sistema 😦

Ho quindi ri-cercato sulla guida ufficiale di LSL linden il metodo per fare un “dns” e da questa pagina http://wiki.secondlife.com/wiki/LSL_HTTP_server viene suggerita come PRIMA possibilità di usare Google App Engine, descritto in questa pagina del forum: http://forums-archive.secondlife.com/54/33/323981/1.html

Installare una Google App Engine application

Riassumendo le istruzioni vertono nello scaricare due file uno .yaml e uno python qui di seguito descritti, di installare google app engine e di deployare questa applicazione. La sequenza è la seguente:

  1. Registratevi qui  http://code.google.com/appengine/ per avere un free account
  2. Scaricate da qui http://www.python.org/download/releases/2.5.4/ python 2.5 e installatelo
  3. Scaricate da qui http://code.google.com/appengine/downloads.html il python SDK ed installatelo (verrà installato in una cartella di nome google_appengine)
  4.  Sotto quella cartella create una subcartella di nome lsl_dns e scaricateci i due programmi qui sotto [[ nota io rispetto all’originale http://home.comcast.net/~volfin/lsl-dns.zip ho fatto alcune modifiche per poter passare inworld il pathinfo e non solo la query string quindi basatevi sulla versione qui pubblicata
  5. Create una applicazione in google apps (https://appengine.google.com/) con un nome XXXXX  e sostituite il nome nel file yaml dove dice “application: XXXXX”
  6. Dalla cartella google_appengine scrivete il comando “appcfg.py update lsl_dns/” che provvede ad installare l’applicazione python

La teoria:

L’applicazione di google app engine supponiamo che si chiami XXXXX risponderà sulla URL  XXXXX.appspot.com con comandi del tipo

Per leggere un dns con un nome:

http://XXXXX.appspot.com/?type=retrieve&name=dispenser_land_italiane

Per inserire un dns

http://XXXXX.appspot.com/?type=add&url=URL&name=dispenser_land_italiane

type=update per aggiornare

Per usare implicitamente la redirezione passando pathinfo e query string:

http://XXXXX.appspot.com/dispenser_land_italiane/pathinfo?P1=a&P2=b

Ho modificato il sorgente python per poter propagare il pathinfo. La versione originale del forum propagava solo la query string. In coda trovate gli script da mettere nel repository centrale e nel dispenser da dare alla gente…

File: app.yaml

application: XXXXX
version: 1
runtime: python
api_version: 1

handlers:
- url: /.*
  script: dns.py

File: dns.py

import cgi
import urllib
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext import db

class Service(db.Model):
  name = db.StringProperty(multiline=False)
  url = db.StringProperty(multiline=False)

class MainPage(webapp.RequestHandler):
  def get(self):

     if self.request.get('type')=='add':  # Adding a new service to the DNS (You can also use Update but it won't tell you the service already exists)
          param2=self.request.get('name') #the Name the service will be known by
          param3=self.request.get('url') # the URL for the web service
          q = db.GqlQuery("SELECT * FROM Service WHERE name = :kk",kk=param2)
          count=q.count(2)

          if count==0 :  # the service doesn't exist, so add it.
              if param2=="" or param3=="" :
                  self.response.out.write('Error2')
              else:
                  newrec=Service(name=param2,url=param3)
                  newrec.put()
                  self.response.out.write('Added')
          else:
              self.response.out.write('Found')  # service already exists so announce that and do nothing

     elif self.request.get('type')=='remove': #removing a service
          param2=self.request.get('name')	 # the name the service is known by
          q = db.GqlQuery("SELECT * FROM Service WHERE name = :kk",kk=param2)
          count=q.count(2)

          if count==0 :
            self.response.out.write('None') # Service wasn't found
          else:
            results=q.fetch(10)
            db.delete(results)  # remove them all (just in case some how, some way, there is more than one service with the same name
            self.response.out.write('Removed')

     elif self.request.get('type')=='update':  # update an existing service. Note this creates a new service, or updates an existing one
          param2=self.request.get('name') #the Name the service will be known by
          param3=self.request.get('url') # the URL for the web service
          q = db.GqlQuery("SELECT * FROM Service WHERE name = :kk",kk=param2)
          count=q.count(2)

          if count!=0 :  # if record already exists, remove it
                results=q.fetch(10)
                db.delete(results)  # remove them all (just in case some how, some way, there is more than one service with the same name
          if param2=="" or param3=="" :
              self.response.out.write('Error2')
          else:
              newrec=Service(name=param2,url=param3) # add record, either replacing the deleted one, or adding a new one if it never existed
              newrec.put()
              if count!=0 :
                  self.response.out.write('Updated')
              else:
                  self.response.out.write('Added')

     elif self.request.get('type')=='retrieve': # get the current URL for a given service
          param2=self.request.get('name')	 # the name the service is known by
          q = db.GqlQuery("SELECT * FROM Service WHERE name = :kk",kk=param2)
          count=q.count(2)
          if count==0 :
                self.response.out.write('None') # Service wasn't found
          else:
                record=q.get()
                self.response.out.write(record.url) #print the URL
     elif self.request.get('type')=='list': # List the existing services
          q = db.GqlQuery("SELECT * FROM Service" )
          count=q.count()

          if count==0 :
              self.response.out.write('Empty') # Services weren't found
          else:
              results = q.fetch(1000)
              for result in results:
                 self.response.out.write(result.name+','+result.url+" ") # added url by Salahzar
              self.response.out.write('END')  # Cap the list

     else: self.response.out.write('Error')

class Redirector(webapp.RequestHandler):
  def get(self):
    service_name=self.request.path
    if service_name[-1]=='/' :
      service_name=service_name[1:-1] #remove leading and trailing slash
    else:
      service_name=service_name[1:]  # remove leading slash only
    # salahzar begin for passing on the pathinfo
    i=service_name.find("/")
    lastpath=''
    if(i>=0):
       lastpath=service_name[i+1:]
       service_name=service_name[0:i]
    # salahzar end

    #un-escape just in case you're Kinki :p
    service_name=urllib.unquote(service_name)
    #self.response.out.write("#"+service_name+"#:"+lastpath)

    q = db.GqlQuery("SELECT * FROM Service WHERE name = :kk",kk=service_name)
    count=q.count(2)
    if count==0 :
      self.response.out.write('None') # Service wasn't found
    else:
      record=q.get()  #get the URL we stored previously

      # salahzar in next lines added "/"+lastpath to be sure to pass on pathinfo
      if self.request.query_string != '' :
        self.redirect(urllib.unquote(record.url)+"/"+lastpath+'?'+self.request.query_string) # redirect to the HTTP-IN URL with arugments
      else:
        self.redirect(urllib.unquote(record.url)+"/"+lastpath) # redirect to the HTTP-IN URL

application = webapp.WSGIApplication(
                                     [('/', MainPage),
                                      ('/.*',Redirector)],
                                     debug=True)

def main():
  run_wsgi_app(application)

if __name__ == "__main__":
  main()

Sorgente repository centrale

//
// This dispenser is listening to calls to the httpin address
// using google apps which is http://XXXXX.appspot.com/key/name
// this is a slightly different version from http://forums-archive.secondlife.com/54/33/323981/1.html
// to allow for redirecting to internal path so we can avoid using get parameters
//
// This script is Creative Commons by Salahzar Stenvaag-nc-sa

string nick = "dispenser_land_italiane"; // this is the key, for instance dispenser_italian_lands
string baseurl = "http://XXXXX.appspot.com/";
integer DEBUG=1; // if you want to debug set this to 1

key requestid;
string url="";

// if debug is needed
debug(string str)
{
    if(DEBUG==1) llOwnerSay(str);
}

// send a correct response
send_response(key id, string body)
{
    llHTTPResponse(id, 200, body);
}

// This is NOT used here but can be to generate the first association
generate_snurl(string testo)
{
    string query = "type=add&url=" + llEscapeURL(testo)

        + "&name=" + llEscapeURL(nick);
        llSay(0,query);
        requestid=llHTTPRequest(baseurl+"?"+query,[],"");
        // requestid = llHTTPRequest(baseurl,[HTTP_METHOD,"POST", HTTP_MIMETYPE,"application/x-www-form-urlencoded"],query);
}

// Change snip with new url
update_snurl(string newurl)
{
    string query = "type=update&url=" + llEscapeURL(newurl)
        + "&name=" + llEscapeURL(nick)

        ;
        debug("baseurl: "+baseurl+" Query is : "+query);
        requestid=llHTTPRequest(baseurl+"?"+query,[],"");
//        requestid = llHTTPRequest(baseurl,[HTTP_METHOD,"POST", HTTP_MIMETYPE,"application/x-www-form-urlencoded"],query);
}

integer ownerlistener;
// ask for a new url
// (to avoid that erroneous rezzing will substitute the sn.im
// use llDialog to be really sure
setup()
{
    llRequestURL();
    return;
    ownerlistener=llListen(1,"",llGetOwner(),"");
    llDialog(llGetOwner(),"Please confirm you want to have this object running and SUBSTITUTING server for "+nick,["SUBSTITUTE"],1);
    url = "";
}

default
{
    state_entry()
    {
        llSetText("http://XXXXX.appspot.com/"+nick,<1,1,1>,1);

        setup();
    }
    listen(integer channel, string name, key id, string str)
    {
        llListenRemove(ownerlistener);
        if(str=="SUBSTITUTE") llRequestURL(); // will continue when URL has been assigned in http_request
    }

    on_rez(integer n)
    {
        setup();
    }

    changed(integer c)
    {
        if (c & (CHANGED_REGION | CHANGED_REGION_START | CHANGED_TELEPORT) )
        {
            setup();
        }
    }

    // triggers after setup() when arrives a new URL
    http_request(key id, string method, string body)
    {

        // new URL has been granted
        if (method == URL_REQUEST_GRANTED)
        {
            url = body;
            //generate_snurl(url); // if we need to generate the first time the url
            update_snurl(url);
            debug("Have been assigned the URL: "+url);
        }

        else if (method == URL_REQUEST_DENIED)
        {
            debug("Something went wrong, no url. " + body);
        }
        // here is the actual server part
        else if (method == "POST" || method=="GET")
        {
                debug("received body: "+body);
                string querystring = llGetHTTPHeader(id, "x-query-string");
                debug("query string: "+querystring);
                string pathinfo = llGetHTTPHeader(id, "x-path-info");
                debug("pathinfo: "+pathinfo);

                // parse the path separating the tokens
                list values=llParseString2List(pathinfo,["/"],[]);
                string av=llList2String(values,0);
                string avname=llList2String(values,1);

                // get the notecard to give
                string notecard=llGetInventoryName(INVENTORY_NOTECARD,0);

                // give the notecard to avatar
                llGiveInventory(av,notecard);
                send_response(id, avname+", you have been given the notecard "+notecard);
        }
        else
        {
            llHTTPResponse(id,405,"Unsupported method.");
        }
    }

    // receives back the result from sn.im
    http_response(key request_id, integer status, list metadata, string body)
    {
        integer i; debug("response is "+body);
        if (request_id == requestid)
        {
            integer i = llSubStringIndex(body,"");
            integer j = llSubStringIndex(body,"");
            integer length = j - i;
            if ( i != -1 )
            {

                string name = llGetSubString(body,i+4,j-1);

                llOwnerSay("Acknowledged change of " + name + " pointing to "+ url);
            }

        } else
            debug((string)status+" error");
    }
}

Sorgente giver


string url="http://XXXXX.appspot.com/dispenser_land_italiane";

debug(string str)
{
    llOwnerSay(str);
}
request(string post)
{
    llSay(0,"Post: "+url+" "+post);
    llHTTPRequest(url+post,[],"");
}

default
{
    touch_start(integer count)
    {
        integer i=0;
        for(i=0;i            request("/"+(string)llDetectedKey(i)+"/"+llKey2Name(llDetectedKey(i)));
    }
    http_response(key request_id,integer status, list metadata, string body)
    {
        llSay(0,body);
    }
}
Advertisements
This entry was posted in LSL, Scripting avanzato, Web. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s