mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-05-13 10:30:16 +00:00
Started moving protocol-specific out of Santiago.
This commit is contained in:
parent
2f3741f7a3
commit
7c35b58363
@ -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 = """\
|
|
||||||
<html><head><title>Use it right.</title></head><body>
|
|
||||||
|
|
||||||
<p>Nice try, now try again with a request like:</p>
|
|
||||||
<p>http://localhost:8080/serve/(requester)/(server)/(service)</p>
|
|
||||||
|
|
||||||
<dl>
|
|
||||||
<dt>requster</dt><dd>james, ian</dd>
|
|
||||||
<dt>server</dt><dd>nick</dd>
|
|
||||||
<dt>service</dt><dd>wiki, web</dd>
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
<p>This'll get you good results:</p>
|
|
||||||
<code><a href="http://localhost:8080/serve/james/wiki/nick">
|
|
||||||
http://localhost:8080/serve/james/wiki/nick</a></code>
|
|
||||||
|
|
||||||
<p>See the <code>serving_to</code>, <code>serving_what</code>, and
|
|
||||||
<code>me</code> variables.</p>
|
|
||||||
|
|
||||||
</body></html>"""
|
|
||||||
|
|
||||||
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))
|
|
||||||
@ -29,15 +29,14 @@ We also don't:
|
|||||||
- Use a reasonable data-store.
|
- Use a reasonable data-store.
|
||||||
- Have a decent control mechanism.
|
- Have a decent control mechanism.
|
||||||
|
|
||||||
|
FIXME: Split into protocol-specific listeners and senders.
|
||||||
FIXME: add that whole pgp thing.
|
FIXME: add that whole pgp thing.
|
||||||
FIXME: remove @cherrypy.expose from everything but index.
|
FIXME: remove @cherrypy.expose from everything but index.
|
||||||
TODO: add doctests
|
TODO: add doctests
|
||||||
|
|
||||||
"""
|
"""
|
||||||
import cherrypy
|
|
||||||
from collections import defaultdict as DefaultDict
|
from collections import defaultdict as DefaultDict
|
||||||
#import gnupg
|
import gnupg
|
||||||
import httplib, urllib
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -54,10 +53,8 @@ def load_data(server, item):
|
|||||||
FIXME: use withsqlite instead.
|
FIXME: use withsqlite instead.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
data = ""
|
|
||||||
with open("%s_%s" % (server, item)) as infile:
|
with open("%s_%s" % (server, item)) as infile:
|
||||||
data = eval(infile.read())
|
return eval(infile.read())
|
||||||
return data
|
|
||||||
|
|
||||||
|
|
||||||
class SimpleSantiago(object):
|
class SimpleSantiago(object):
|
||||||
@ -103,6 +100,20 @@ class SimpleSantiago(object):
|
|||||||
def _create_listeners(self):
|
def _create_listeners(self):
|
||||||
"""Iterates through each known protocol creating listeners for all."""
|
"""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():
|
for protocol in self.listeners.iterkeys():
|
||||||
method = "_create_%s_listener" % protocol
|
method = "_create_%s_listener" % protocol
|
||||||
|
|
||||||
@ -111,25 +122,6 @@ class SimpleSantiago(object):
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
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):
|
def am_i(self, server):
|
||||||
"""Verify whether this server is the specified server."""
|
"""Verify whether this server is the specified server."""
|
||||||
|
|
||||||
@ -166,7 +158,6 @@ class SimpleSantiago(object):
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@cherrypy.expose
|
|
||||||
def query(self, host, service):
|
def query(self, host, service):
|
||||||
"""Request a service from another Santiago.
|
"""Request a service from another Santiago.
|
||||||
|
|
||||||
@ -178,7 +169,7 @@ class SimpleSantiago(object):
|
|||||||
self.request(host, self.me, host, self.me,
|
self.request(host, self.me, host, self.me,
|
||||||
service, None, self.get_client_locations(host, "santiago"))
|
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):
|
service, locations, reply_to):
|
||||||
"""Send a request to another Santiago service.
|
"""Send a request to another Santiago service.
|
||||||
|
|
||||||
@ -188,40 +179,15 @@ class SimpleSantiago(object):
|
|||||||
# best guess reply_to if we don't know.
|
# best guess reply_to if we don't know.
|
||||||
reply_to = reply_to or self.get_host_locations(to, "santiago")
|
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"):
|
for destination in self.get_client_locations(to, "santiago"):
|
||||||
getattr(self, destination.split(":")[0] + "_request") \
|
getattr(self, destination.split(":")[0] + "_request")(request)
|
||||||
(from_, to, host, client,
|
|
||||||
service, locations, destination, reply_to)
|
|
||||||
|
|
||||||
def https_request(self, from_, to, host, client,
|
def incoming_request(self, **kwargs):
|
||||||
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):
|
|
||||||
"""Provide a service to a client.
|
"""Provide a service to a client.
|
||||||
|
|
||||||
This tag doesn't do any real processing, it just catches and hides
|
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
|
Attempt to contact the other Santiago and ask it to reply both to the
|
||||||
original host as well as me.
|
original host as well as me.
|
||||||
|
|
||||||
|
TODO: add tests.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self.request(self.me, to, host, client,
|
self.request(self.me, to, host, client,
|
||||||
service, reply_to)
|
service, reply_to)
|
||||||
@ -343,14 +311,13 @@ class SimpleSantiago(object):
|
|||||||
self.learn_service(host, service, locations)
|
self.learn_service(host, service, locations)
|
||||||
self.requests[host].remove(service)
|
self.requests[host].remove(service)
|
||||||
|
|
||||||
@cherrypy.expose
|
|
||||||
def save_server(self):
|
def save_server(self):
|
||||||
"""Save all operational data to files.
|
"""Save all operational data to files.
|
||||||
|
|
||||||
Save all files with the ``self.me`` prefix.
|
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)
|
name = "%s_%s" % (self.me, datum)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -359,6 +326,18 @@ class SimpleSantiago(object):
|
|||||||
except:
|
except:
|
||||||
pass
|
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__":
|
if __name__ == "__main__":
|
||||||
# FIXME: convert this to the withsqlite setup.
|
# FIXME: convert this to the withsqlite setup.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user