From 7c35b583632b7e3bbc3e2400a5b6bb66408f4f79 Mon Sep 17 00:00:00 2001 From: Nick Daly Date: Sun, 1 Apr 2012 01:29:38 -0500 Subject: [PATCH] Started moving protocol-specific out of Santiago. --- ugly_hacks/santiago/protocols/http.py | 97 ------------------------ ugly_hacks/santiago/simple_santiago.py | 101 ++++++++++--------------- 2 files changed, 40 insertions(+), 158 deletions(-) delete mode 100644 ugly_hacks/santiago/protocols/http.py diff --git a/ugly_hacks/santiago/protocols/http.py b/ugly_hacks/santiago/protocols/http.py deleted file mode 100644 index df9b3a4a0..000000000 --- a/ugly_hacks/santiago/protocols/http.py +++ /dev/null @@ -1,97 +0,0 @@ -import cherrypy -import santiago -from simplejson import JSONEncoder - -encoder = JSONEncoder() - - -# dirty hacks for Debian Squeeze (stable) -# ======================================= - -def fix_old_cherrypy(): - """Make Squeeze's CherryPy forward-compatible.""" - - for y in range(0,3): - for x in range(0, 7): - print "WARNING", - print "" - - print("You're using an old CherryPy version! We're faking it!") - print("Expect the unexpected! Raar!") - - def jsonify_tool_callback(*args, **kwargs): - response = cherrypy.response - response.headers['Content-Type'] = 'application/json' - response.body = encoder.iterencode(response.body) - - cherrypy.tools.json_out = cherrypy.Tool('before_finalize', jsonify_tool_callback, priority=30) - -if cherrypy.__version__ < "3.2": - fix_old_cherrypy() - - -# actual HTTP Santiago classes. -# ============================= - -class SantiagoHttpListener(santiago.SantiagoListener): - """Listens for connections on the HTTP protocol.""" - - DEFAULT_RESPONSE = """\ -Use it right. - -

Nice try, now try again with a request like:

-

http://localhost:8080/serve/(requester)/(server)/(service)

- -
-
requster
james, ian
-
server
nick
-
service
wiki, web
-
- -

This'll get you good results:

- - http://localhost:8080/serve/james/wiki/nick - -

See the serving_to, serving_what, and - me variables.

- -""" - - def __init__(self, instance, location="localhost:8080"): - super(SantiagoHttpListener, self).__init__(instance, location) - self.socket_port = location.rpartition(":")[2] - - @cherrypy.expose - @cherrypy.tools.json_out() - def serve(self, key=None, service=None, server=None, hops=3, santiagi=None): - """Handles an incoming request.""" - - return super(SantiagoHttpListener, self).serve( - key, service, server, hops, santiagi) - - @cherrypy.expose - def index(self): - """Do nothing, unless we're debugging.""" - - if santiago.DEBUG: - return self.DEFAULT_RESPONSE - - -class SantiagoHttpSender(santiago.SantiagoSender): - """Responsible for answering HTTP requests.""" - - import urllib, urllib2 - - @cherrypy.tools.json_out() - def proxy(self, key, service, server, hops=3): - """Forwards on a request to another Santiago.""" - - return super(SantiagoHttpSender, self).proxy(key, service, server, hops) - - @cherrypy.tools.json_out() - def send(self): - """Send messages to other Santiagi.""" - - for message in super(SantiagoSender, self).send(): - if message["location"].startswith("http"): - urllib2.Request(message["location"],urllib.urlencode(message)) diff --git a/ugly_hacks/santiago/simple_santiago.py b/ugly_hacks/santiago/simple_santiago.py index 7433394ff..d846e24e6 100644 --- a/ugly_hacks/santiago/simple_santiago.py +++ b/ugly_hacks/santiago/simple_santiago.py @@ -29,15 +29,14 @@ We also don't: - Use a reasonable data-store. - Have a decent control mechanism. +FIXME: Split into protocol-specific listeners and senders. FIXME: add that whole pgp thing. FIXME: remove @cherrypy.expose from everything but index. TODO: add doctests """ -import cherrypy from collections import defaultdict as DefaultDict -#import gnupg -import httplib, urllib +import gnupg import sys try: @@ -54,10 +53,8 @@ def load_data(server, item): FIXME: use withsqlite instead. """ - data = "" with open("%s_%s" % (server, item)) as infile: - data = eval(infile.read()) - return data + return eval(infile.read()) class SimpleSantiago(object): @@ -103,6 +100,20 @@ class SimpleSantiago(object): def _create_listeners(self): """Iterates through each known protocol creating listeners for all.""" + # FIXME: Split into protocol-specific listeners and senders. + + # def configure_gui(self): + # """Launch the gui specified in the launcher's config files. + # + # """ + # gui_name = self.config.get(self.META_DATA, "gui") + # import_name = "guis.%(gui_name)s.gemrb_gui_%(gui_name)s" % locals() + # __import__(import_name) # TODO import every gui in the gui dir until one succeeds + # + # gui_module = sys.modules[import_name] + # + # self.gui = gui_module.Gui(self) + for protocol in self.listeners.iterkeys(): method = "_create_%s_listener" % protocol @@ -111,25 +122,6 @@ class SimpleSantiago(object): except KeyError: pass - def _create_http_listener(self, *args, **kwargs): - """Register an HTTP listener. - - Merely a wrapper for _create_https_listener. - - """ - self._create_https_listener(*args, **kwargs) - - def _create_https_listener(self, socket_port=0, - ssl_certificate="", ssl_private_key=""): - """Registers an HTTPS listener.""" - - cherrypy.server.socket_port = socket_port - cherrypy.server.ssl_certificate = ssl_certificate - cherrypy.server.ssl_private_key = ssl_private_key - - # reach deep into the voodoo to actually serve the index - SimpleSantiago.index.__dict__["exposed"] = True - def am_i(self, server): """Verify whether this server is the specified server.""" @@ -166,7 +158,6 @@ class SimpleSantiago(object): except KeyError: pass - @cherrypy.expose def query(self, host, service): """Request a service from another Santiago. @@ -178,7 +169,7 @@ class SimpleSantiago(object): self.request(host, self.me, host, self.me, service, None, self.get_client_locations(host, "santiago")) - def request(self, from_, to, host, client, + def outgoing_request(self, from_, to, host, client, service, locations, reply_to): """Send a request to another Santiago service. @@ -188,40 +179,15 @@ class SimpleSantiago(object): # best guess reply_to if we don't know. reply_to = reply_to or self.get_host_locations(to, "santiago") + request = self.gpg.sign_encrypt({ + "from": from_, "to": to, "host": host, "client": client, + "service": service, "locations": locations or "", + "reply_to": reply_to}) + for destination in self.get_client_locations(to, "santiago"): - getattr(self, destination.split(":")[0] + "_request") \ - (from_, to, host, client, - service, locations, destination, reply_to) + getattr(self, destination.split(":")[0] + "_request")(request) - def https_request(self, from_, to, host, client, - service, locations, destination, reply_to): - """Send an HTTPS request to each Santiago client. - - Don't queue, just immediately send the reply to each location we know. - - It's both simple and as reliable as possible. - - TODO: pgp sign and encrypt - - """ - params = urllib.urlencode( - {"from": from_, "to": to, "host": host, "client": client, - "service": service, "locations": locations or "", - "reply_to": reply_to}) - - proxy = self.senders["https"] - - # TODO: Does HTTPSConnection require the cert and key? - # Is the fact that the server has it sufficient? I think so. - connection = httplib.HTTPSConnection(destination.split("//")[1]) - - if sys.version_info >= (2, 7): - connection.set_tunnel(proxy["host"], proxy["port"]) - - connection.request("GET", "/?%s" % params) - connection.close() - - def index(self, **kwargs): + def incoming_request(self, **kwargs): """Provide a service to a client. This tag doesn't do any real processing, it just catches and hides @@ -309,6 +275,8 @@ class SimpleSantiago(object): Attempt to contact the other Santiago and ask it to reply both to the original host as well as me. + TODO: add tests. + """ self.request(self.me, to, host, client, service, reply_to) @@ -343,14 +311,13 @@ class SimpleSantiago(object): self.learn_service(host, service, locations) self.requests[host].remove(service) - @cherrypy.expose def save_server(self): """Save all operational data to files. Save all files with the ``self.me`` prefix. """ - for datum in ("hosting", "consuming", "listeners", "senders"): + for datum in ("hosting", "consuming"): name = "%s_%s" % (self.me, datum) try: @@ -359,6 +326,18 @@ class SimpleSantiago(object): except: pass +class SantiagoListener(object): + """Generic Santiago Listener superclass.""" + + def __init__(self, santiago): + self.santiago = santiago + +class SantiagoSender(object): + """Generic Santiago Sender superclass.""" + + def __init__(self, santiago): + self.santiago = santiago + if __name__ == "__main__": # FIXME: convert this to the withsqlite setup.