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:
- Registratevi qui http://code.google.com/appengine/ per avere un free account
- Scaricate da qui http://www.python.org/download/releases/2.5.4/ python 2.5 e installatelo
- Scaricate da qui http://code.google.com/appengine/downloads.html il python SDK ed installatelo (verrà installato in una cartella di nome google_appengine)
- 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
- 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”
- 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