Skip to content

Instantly share code, notes, and snippets.

@aurynn
Created April 9, 2014 20:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aurynn/10309304 to your computer and use it in GitHub Desktop.
Save aurynn/10309304 to your computer and use it in GitHub Desktop.
# Shamelessly stolen from the Twisted site
from twisted.internet import protocol, reactor, defer
from twisted.protocols.basic import LineReceiver
from twisted.internet.endpoints import TCP4ServerEndpoint
import json
class JsonEchoServer(LineReceiver):
"""
Implements the server-side mechanisms
"""
def __init__(self, *args):
# LineReceiver.__init__(self, *args)
self.acks = {}
self.msgid = 0
self.exposed = {
"acknowledge": self.acknowledge,
"message" : self.message
}
def connectionMade(self):
print "Connected!"
self.message(**{"from": "server",
"message": "connected"})
def acknowledge(self, reply, blob):
pass
def sendCall(self, method, *args, **kwargs):
blob = {
"call": method,
"id": self.msgid,
"args": args,
"kwargs": kwargs
}
self.sendLine(
json.dumps(blob)
)
self.acks[self.msgid] = {"blob": blob, "deferred": defer.Deferred()}
self.acks[self.msgid]["deferred"].addCallback( self.acknowledge, blob )
df = self.acks[self.msgid]["deferred"]
self.msgid += 1
return df
def message(self, **kwargs):
df = self.sendCall("message",
**{"from": "Echo Server",
"message": "%s said '%s'" % ( kwargs["from"], kwargs["message"] )
}
)
def message(m):
print "Got reply: m"
df.addCallback(message)
return df
def sendReply(self, reply, msgid):
blob = {"reply": reply,
"id": msgid
}
self.sendLine(json.dumps(blob))
def sendError(self, message, id_):
blob = {"error": True,
"message": message,
"id": id_
}
self.sendLine(json.dumps(blob))
def reply(self, m):
# receives a reply from a remote host
msgid = m["id"]
if msgid not in self.acks:
# error
return self.sendError("no such id %s" % msgid, msgid)
df = self.acks[msgid]["deferred"]
df.callback(m)
def lineReceived(self, line):
"""Receives a line from our remote"""
print "Line!"
m = None
try:
m = json.loads(line)
except json.JSONDecodeError as e:
self.sendCall(json.dumps(
{
"error": True,
"message": "json parse error {error}".format(e)}
))
print "received non-json-decodable string"
return
# Implementing the RPC system.
if "call" in m:
if m["call"] in self.exposed:
method = self.exposed[ m["call"] ]
reply = method(*m["args"], **m["kwargs"])
self.sendReply(reply, m["id"])
else:
self.sendCall("error", "no method {method}".format(m["call"]), m["id"])
elif "reply" in m:
self.reply(m)
elif "error" in m:
print "Couldn't call remote method: %s" % m["message"]
class EchoFactory(protocol.Factory):
def buildProtocol(self, addr):
e = JsonEchoServer()
return e
endpoint = TCP4ServerEndpoint(reactor, 1235)
endpoint.listen(EchoFactory())
reactor.run()
@aurynn
Copy link
Author

aurynn commented Apr 9, 2014

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment