mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-02-18 08:33:41 +00:00
Added a querying API.
This commit is contained in:
parent
36f8fff888
commit
5a6f25f300
@ -1,4 +1,19 @@
|
||||
"""The HTTPS Santiago listener and sender."""
|
||||
"""The HTTPS Santiago listener and sender.
|
||||
|
||||
FIXME: use a reasonable RESTful API.
|
||||
|
||||
- https://appmecha.wordpress.com/2008/10/27/cherrypy-gae-routing-2/
|
||||
- http://tools.cherrypy.org/wiki/RestfulDispatch
|
||||
- http://docs.cherrypy.org/dev/refman/_cpdispatch.html
|
||||
- http://www.infoq.com/articles/rest-introduction
|
||||
- http://www.infoq.com/articles/rest-anti-patterns
|
||||
- http://stackoverflow.com/a/920181
|
||||
- http://docs.cherrypy.org/dev/progguide/REST.html
|
||||
|
||||
It's been about five times too long since I've looked at this sort of
|
||||
thing. Stupid everything-is-GET antipattern.
|
||||
|
||||
"""
|
||||
|
||||
from santiago import SantiagoListener, SantiagoSender
|
||||
|
||||
@ -7,6 +22,14 @@ import httplib, urllib, urlparse
|
||||
import sys
|
||||
import logging
|
||||
|
||||
def jsonify_tool_callback(*args, **kwargs):
|
||||
response = cherrypy.response
|
||||
response.headers['Content-Type'] = 'application/json'
|
||||
response.body = encoder.iterencode(response.body)
|
||||
|
||||
if cherrypy.__version__ < "3.2":
|
||||
cherrypy.tools.json_out = cherrypy.Tool('before_finalize', jsonify_tool_callback, priority=30)
|
||||
|
||||
class Listener(SantiagoListener):
|
||||
|
||||
def __init__(self, santiago, socket_port=0,
|
||||
@ -38,18 +61,53 @@ class Listener(SantiagoListener):
|
||||
logging.exception(e)
|
||||
|
||||
@cherrypy.expose
|
||||
def query(self, host, service):
|
||||
def learn(self, host, service):
|
||||
"""Request a resource from another Santiago client.
|
||||
|
||||
TODO: add request whitelisting.
|
||||
|
||||
"""
|
||||
if not cherrypy.request.remote.ip.startswith("127.0.0"):
|
||||
# TODO enforce restfulness, POST, and build a request form.
|
||||
# if not cherrypy.request.method == "POST":
|
||||
# return
|
||||
|
||||
if not cherrypy.request.remote.ip.startswith("127.0.0."):
|
||||
logging.debug("protocols.https.query: Request from non-local IP")
|
||||
return
|
||||
|
||||
self.santiago.query(host, service)
|
||||
return super(Listener, self).learn(host, service)
|
||||
|
||||
@cherrypy.expose
|
||||
@cherrypy.tools.json_out()
|
||||
def where(self, host, service):
|
||||
"""Show where a host is providing me services."""
|
||||
|
||||
if not cherrypy.request.remote.ip.startswith("127.0.0."):
|
||||
logging.debug("protocols.https.query: Request from non-local IP")
|
||||
return
|
||||
|
||||
return list(super(Listener, self).where(host, service))
|
||||
|
||||
@cherrypy.expose
|
||||
def provide(self, client, service, location):
|
||||
"""Provide a service for the client at the location."""
|
||||
|
||||
if not cherrypy.request.remote.ip.startswith("127.0.0."):
|
||||
logging.debug("protocols.https.query: Request from non-local IP")
|
||||
return
|
||||
|
||||
return super(Listener, self).provide(client, service, location)
|
||||
|
||||
@cherrypy.expose
|
||||
def pdb(self):
|
||||
"""Set a trace."""
|
||||
|
||||
if not cherrypy.request.remote.ip.startswith("127.0.0."):
|
||||
logging.debug("protocols.https.query: Request from non-local IP")
|
||||
return
|
||||
|
||||
import pdb; pdb.set_trace()
|
||||
|
||||
class Sender(SantiagoSender):
|
||||
|
||||
def __init__(self, santiago, proxy_host, proxy_port):
|
||||
|
||||
@ -171,6 +171,11 @@ class Santiago(object):
|
||||
|
||||
def learn_service(self, host, service, locations):
|
||||
"""Learn a service somebody else hosts for me."""
|
||||
if service not in self.consuming:
|
||||
self.consuming[service] = dict()
|
||||
|
||||
if host not in self.consuming[service]:
|
||||
self.consuming[service][host] = set()
|
||||
|
||||
if locations:
|
||||
self.consuming[service][host] = (
|
||||
@ -179,8 +184,15 @@ class Santiago(object):
|
||||
def provide_service(self, client, service, locations):
|
||||
"""Start hosting a service for somebody else."""
|
||||
|
||||
if client not in self.hosting:
|
||||
self.hosting[client] = dict()
|
||||
|
||||
if service not in self.hosting[client]:
|
||||
self.hosting[client][service] = set()
|
||||
|
||||
if locations:
|
||||
self.hosting[client][service].union(locations)
|
||||
self.hosting[client][service] = (
|
||||
self.hosting[client][service] | locations)
|
||||
|
||||
def get_host_locations(self, client, service):
|
||||
"""Return where I'm hosting the service for the client.
|
||||
@ -201,7 +213,6 @@ class Santiago(object):
|
||||
except KeyError as e:
|
||||
logging.exception(e)
|
||||
|
||||
|
||||
def query(self, host, service):
|
||||
"""Request a service from another Santiago.
|
||||
|
||||
@ -464,6 +475,7 @@ class Santiago(object):
|
||||
|
||||
self.requests[host].remove(service)
|
||||
# clean buffers
|
||||
# TODO clean up after 5 minutes to allow all hosts to reply?
|
||||
if not self.requests[host]:
|
||||
del self.requests[host]
|
||||
|
||||
@ -598,6 +610,29 @@ class SantiagoListener(SantiagoConnector):
|
||||
def incoming_request(self, request):
|
||||
self.santiago.incoming_request(request)
|
||||
|
||||
def where(self, host, service):
|
||||
"""Return where the named host provides me a service.
|
||||
|
||||
If no service is provided, return None.
|
||||
|
||||
TODO: unittest
|
||||
|
||||
"""
|
||||
return self.santiago.get_client_locations(host, service)
|
||||
|
||||
def learn(self, host, service):
|
||||
"""Request a service from another Santiago client.
|
||||
|
||||
TODO: add request whitelisting.
|
||||
|
||||
"""
|
||||
return self.santiago.query(host, service)
|
||||
|
||||
def provide(self, client, service, location):
|
||||
"""Provide a service for the client at the location."""
|
||||
|
||||
return self.santiago.provide_service(client, service, set([location]))
|
||||
|
||||
class SantiagoSender(SantiagoConnector):
|
||||
"""Generic Santiago Sender superclass.
|
||||
|
||||
@ -621,11 +656,9 @@ if __name__ == "__main__":
|
||||
"ssl_private_key": cert }, }
|
||||
senders = { "https": { "proxy_host": "localhost",
|
||||
"proxy_port": 8118} }
|
||||
hosting = { mykey: { "santiago": set( ["https://localhost:8080",
|
||||
"https://somestuff" ] )}}
|
||||
hosting = { mykey: { "santiago": set( ["https://localhost:8080"] )}}
|
||||
consuming = { "santiago": { mykey: set( ["https://localhost:8080"] )}}
|
||||
|
||||
# load the Santiago
|
||||
santiago = Santiago(listeners, senders,
|
||||
hosting, consuming,
|
||||
me=mykey)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user