Dispenser delle Land Italiane (scripts)

Published on

in

, ,

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);
    }
}

Leave a comment


Benvenuto su Salahzar.com

Qui trovi analisi critiche sull’intelligenza artificiale e le sue implicazioni sociali, scritte da chi viene da una impostazione umanistica e ha passato vent’anni a costruire mondi virtuali prima che diventassero “metaverso”.

Niente hype da Silicon Valley o entusiasmi acritici: sul tavolo ci sono le contraddizioni dell’innovazione tecnologica, i suoi miti fondativi, le narrazioni che usiamo per darle senso. Dai diari ucronici (storie alternative come strumento per capire i nostri bias cognitivi) alle newsletter settimanali sugli sviluppi dell’AI che richiedono aggiornamenti continui perché i trimestri sono già preistoria.

Se cerchi guide su come “fare soldi con ChatGPT” o liste di prompt miracolosi, sei nel posto sbagliato. Se invece ti interessa capire cosa sta succedendo davvero – tra hype, opportunità concrete e derive distopiche – sei nel posto giusto.

Umanesimo digitale senza retorica, analisi senza paternalismi, ironia senza cinismo.


Join the Club

Stay updated with our latest tips and other news by joining our newsletter.