break out more message components, use SidedMessage
This commit is contained in:
parent
05aa5ca76e
commit
181ef04a91
|
@ -52,6 +52,9 @@ TransitUsage = namedtuple("TransitUsage",
|
||||||
["started", "waiting_time", "total_time",
|
["started", "waiting_time", "total_time",
|
||||||
"total_bytes", "result"])
|
"total_bytes", "result"])
|
||||||
|
|
||||||
|
SidedMessage = namedtuple("SidedMessage", ["side", "phase", "body",
|
||||||
|
"server_rx", "msg_id"])
|
||||||
|
|
||||||
class Mailbox:
|
class Mailbox:
|
||||||
def __init__(self, app, db, blur_usage, log_requests, app_id, mailbox_id):
|
def __init__(self, app, db, blur_usage, log_requests, app_id, mailbox_id):
|
||||||
self._app = app
|
self._app = app
|
||||||
|
@ -93,8 +96,10 @@ class Mailbox:
|
||||||
" WHERE `app_id`=? AND `mailbox_id`=?"
|
" WHERE `app_id`=? AND `mailbox_id`=?"
|
||||||
" ORDER BY `server_rx` ASC",
|
" ORDER BY `server_rx` ASC",
|
||||||
(self._app_id, self._mailbox_id)).fetchall():
|
(self._app_id, self._mailbox_id)).fetchall():
|
||||||
messages.append({"phase": row["phase"], "body": row["body"],
|
sm = SidedMessage(side=row["side"], phase=row["phase"],
|
||||||
"server_rx": row["server_rx"], "id": row["msg_id"]})
|
body=row["body"], server_rx=row["server_rx"],
|
||||||
|
msg_id=row["msg_id"])
|
||||||
|
messages.append(sm)
|
||||||
return messages
|
return messages
|
||||||
|
|
||||||
def add_listener(self, handle, send_f, stop_f):
|
def add_listener(self, handle, send_f, stop_f):
|
||||||
|
@ -104,25 +109,23 @@ class Mailbox:
|
||||||
def remove_listener(self, handle):
|
def remove_listener(self, handle):
|
||||||
self._listeners.pop(handle)
|
self._listeners.pop(handle)
|
||||||
|
|
||||||
def broadcast_message(self, phase, body, server_rx, msgid):
|
def broadcast_message(self, sm):
|
||||||
for (send_f, stop_f) in self._listeners.values():
|
for (send_f, stop_f) in self._listeners.values():
|
||||||
send_f({"phase": phase, "body": body,
|
send_f(sm)
|
||||||
"server_rx": server_rx, "id": msgid})
|
|
||||||
|
|
||||||
def _add_message(self, side, phase, body, server_rx, msgid):
|
def _add_message(self, sm):
|
||||||
db = self._db
|
self._db.execute("INSERT INTO `messages`"
|
||||||
db.execute("INSERT INTO `messages`"
|
" (`app_id`, `mailbox_id`, `side`, `phase`, `body`,"
|
||||||
" (`app_id`, `mailbox_id`, `side`, `phase`, `body`,"
|
" `server_rx`, `msg_id`)"
|
||||||
" `server_rx`, `msg_id`)"
|
" VALUES (?,?,?,?,?, ?,?)",
|
||||||
" VALUES (?,?,?,?,?, ?,?)",
|
(self._app_id, self._mailbox_id, sm.side,
|
||||||
(self._app_id, self._mailbox_id, side, phase, body,
|
sm.phase, sm.body, sm.server_rx, sm.msg_id))
|
||||||
server_rx, msgid))
|
self._db.commit()
|
||||||
db.commit()
|
|
||||||
|
|
||||||
def add_message(self, side, phase, body, server_rx, msgid):
|
def add_message(self, sm):
|
||||||
self._add_message(side, phase, body, server_rx, msgid)
|
assert isinstance(sm, SidedMessage)
|
||||||
self.broadcast_message(phase, body, server_rx, msgid)
|
self._add_message(sm)
|
||||||
return self.get_messages() # for rendezvous_web.py POST /add
|
self.broadcast_message(sm)
|
||||||
|
|
||||||
def close(self, side, mood, when):
|
def close(self, side, mood, when):
|
||||||
assert isinstance(side, type(u"")), type(side)
|
assert isinstance(side, type(u"")), type(side)
|
||||||
|
|
|
@ -2,7 +2,7 @@ import json, time
|
||||||
from twisted.internet import reactor
|
from twisted.internet import reactor
|
||||||
from twisted.python import log
|
from twisted.python import log
|
||||||
from autobahn.twisted import websocket
|
from autobahn.twisted import websocket
|
||||||
from .rendezvous import CrowdedError
|
from .rendezvous import CrowdedError, SidedMessage
|
||||||
|
|
||||||
# The WebSocket allows the client to send "commands" to the server, and the
|
# The WebSocket allows the client to send "commands" to the server, and the
|
||||||
# server to send "responses" to the client. Note that commands and responses
|
# server to send "responses" to the client. Note that commands and responses
|
||||||
|
@ -63,7 +63,7 @@ from .rendezvous import CrowdedError
|
||||||
#
|
#
|
||||||
# -> {type: "open", mailbox: str} -> message
|
# -> {type: "open", mailbox: str} -> message
|
||||||
# sends old messages now, and subscribes to deliver future messages
|
# sends old messages now, and subscribes to deliver future messages
|
||||||
# <- {type: "message", message: {phase:, body:}} # body is hex
|
# <- {type: "message", side:, phase:, body:, msg_id:}} # body is hex
|
||||||
# -> {type: "add", phase: str, body: hex} # will send echo in a "message"
|
# -> {type: "add", phase: str, body: hex} # will send echo in a "message"
|
||||||
#
|
#
|
||||||
# -> {type: "close", mood: str} -> closed
|
# -> {type: "close", mood: str} -> closed
|
||||||
|
@ -191,12 +191,13 @@ class WebSocketRendezvous(websocket.WebSocketServerProtocol):
|
||||||
assert isinstance(mailbox_id, type(u""))
|
assert isinstance(mailbox_id, type(u""))
|
||||||
self._mailbox = self._app.open_mailbox(mailbox_id, self._side,
|
self._mailbox = self._app.open_mailbox(mailbox_id, self._side,
|
||||||
server_rx)
|
server_rx)
|
||||||
def _send(event):
|
def _send(sm):
|
||||||
self.send("message", message=event)
|
self.send("message", side=sm.side, phase=sm.phase,
|
||||||
|
body=sm.body, server_rx=sm.server_rx, id=sm.msg_id)
|
||||||
def _stop():
|
def _stop():
|
||||||
pass
|
pass
|
||||||
for old_message in self._mailbox.add_listener(self, _send, _stop):
|
for old_sm in self._mailbox.add_listener(self, _send, _stop):
|
||||||
_send(old_message)
|
_send(old_sm)
|
||||||
|
|
||||||
def handle_add(self, msg, server_rx):
|
def handle_add(self, msg, server_rx):
|
||||||
if not self._mailbox:
|
if not self._mailbox:
|
||||||
|
@ -206,8 +207,10 @@ class WebSocketRendezvous(websocket.WebSocketServerProtocol):
|
||||||
if "body" not in msg:
|
if "body" not in msg:
|
||||||
raise Error("missing 'body'")
|
raise Error("missing 'body'")
|
||||||
msgid = msg.get("id") # optional
|
msgid = msg.get("id") # optional
|
||||||
self._mailbox.add_message(self._side, msg["phase"], msg["body"],
|
sm = SidedMessage(side=self._side, phase=msg["phase"],
|
||||||
server_rx, msgid)
|
body=msg["body"], server_rx=server_rx,
|
||||||
|
msg_id=msgid)
|
||||||
|
self._mailbox.add_message(sm)
|
||||||
|
|
||||||
def handle_close(self, msg, server_rx):
|
def handle_close(self, msg, server_rx):
|
||||||
if not self._mailbox:
|
if not self._mailbox:
|
||||||
|
|
|
@ -10,7 +10,7 @@ from autobahn.twisted import websocket
|
||||||
from .. import __version__
|
from .. import __version__
|
||||||
from .common import ServerBase
|
from .common import ServerBase
|
||||||
from ..server import rendezvous, transit_server
|
from ..server import rendezvous, transit_server
|
||||||
from ..server.rendezvous import Usage
|
from ..server.rendezvous import Usage, SidedMessage
|
||||||
|
|
||||||
class Reachable(ServerBase, unittest.TestCase):
|
class Reachable(ServerBase, unittest.TestCase):
|
||||||
|
|
||||||
|
@ -254,7 +254,9 @@ class Server(ServerBase, unittest.TestCase):
|
||||||
app = self._rendezvous.get_app(u"appid")
|
app = self._rendezvous.get_app(u"appid")
|
||||||
mailbox_id = u"mid"
|
mailbox_id = u"mid"
|
||||||
m1 = app.open_mailbox(mailbox_id, u"side1", 0)
|
m1 = app.open_mailbox(mailbox_id, u"side1", 0)
|
||||||
m1.add_message(u"side1", u"phase", u"body", 1, u"msgid")
|
m1.add_message(SidedMessage(side=u"side1", phase=u"phase",
|
||||||
|
body=u"body", server_rx=1,
|
||||||
|
msg_id=u"msgid"))
|
||||||
msgs = self._messages(app)
|
msgs = self._messages(app)
|
||||||
self.assertEqual(len(msgs), 1)
|
self.assertEqual(len(msgs), 1)
|
||||||
self.assertEqual(msgs[0]["body"], u"body")
|
self.assertEqual(msgs[0]["body"], u"body")
|
||||||
|
@ -263,34 +265,43 @@ class Server(ServerBase, unittest.TestCase):
|
||||||
l2 = []; stop2 = []; stop2_f = lambda: stop2.append(True)
|
l2 = []; stop2 = []; stop2_f = lambda: stop2.append(True)
|
||||||
old = m1.add_listener("handle1", l1.append, stop1_f)
|
old = m1.add_listener("handle1", l1.append, stop1_f)
|
||||||
self.assertEqual(len(old), 1)
|
self.assertEqual(len(old), 1)
|
||||||
self.assertEqual(old[0]["body"], u"body")
|
self.assertEqual(old[0].side, u"side1")
|
||||||
|
self.assertEqual(old[0].body, u"body")
|
||||||
|
|
||||||
m1.add_message(u"side1", u"phase2", u"body2", 1, u"msgid")
|
m1.add_message(SidedMessage(side=u"side1", phase=u"phase2",
|
||||||
|
body=u"body2", server_rx=1,
|
||||||
|
msg_id=u"msgid"))
|
||||||
self.assertEqual(len(l1), 1)
|
self.assertEqual(len(l1), 1)
|
||||||
self.assertEqual(l1[0]["body"], u"body2")
|
self.assertEqual(l1[0].body, u"body2")
|
||||||
old = m1.add_listener("handle2", l2.append, stop2_f)
|
old = m1.add_listener("handle2", l2.append, stop2_f)
|
||||||
self.assertEqual(len(old), 2)
|
self.assertEqual(len(old), 2)
|
||||||
|
|
||||||
m1.add_message(u"side1", u"phase3", u"body3", 1, u"msgid")
|
m1.add_message(SidedMessage(side=u"side1", phase=u"phase3",
|
||||||
|
body=u"body3", server_rx=1,
|
||||||
|
msg_id=u"msgid"))
|
||||||
self.assertEqual(len(l1), 2)
|
self.assertEqual(len(l1), 2)
|
||||||
self.assertEqual(l1[-1]["body"], u"body3")
|
self.assertEqual(l1[-1].body, u"body3")
|
||||||
self.assertEqual(len(l2), 1)
|
self.assertEqual(len(l2), 1)
|
||||||
self.assertEqual(l2[-1]["body"], u"body3")
|
self.assertEqual(l2[-1].body, u"body3")
|
||||||
|
|
||||||
m1.remove_listener("handle1")
|
m1.remove_listener("handle1")
|
||||||
|
|
||||||
m1.add_message(u"side1", u"phase4", u"body4", 1, u"msgid")
|
m1.add_message(SidedMessage(side=u"side1", phase=u"phase4",
|
||||||
|
body=u"body4", server_rx=1,
|
||||||
|
msg_id=u"msgid"))
|
||||||
self.assertEqual(len(l1), 2)
|
self.assertEqual(len(l1), 2)
|
||||||
self.assertEqual(l1[-1]["body"], u"body3")
|
self.assertEqual(l1[-1].body, u"body3")
|
||||||
self.assertEqual(len(l2), 2)
|
self.assertEqual(len(l2), 2)
|
||||||
self.assertEqual(l2[-1]["body"], u"body4")
|
self.assertEqual(l2[-1].body, u"body4")
|
||||||
|
|
||||||
m1._shutdown()
|
m1._shutdown()
|
||||||
self.assertEqual(stop1, [])
|
self.assertEqual(stop1, [])
|
||||||
self.assertEqual(stop2, [True])
|
self.assertEqual(stop2, [True])
|
||||||
|
|
||||||
# message adds are not idempotent: clients filter duplicates
|
# message adds are not idempotent: clients filter duplicates
|
||||||
m1.add_message(u"side1", u"phase", u"body", 1, u"msgid")
|
m1.add_message(SidedMessage(side=u"side1", phase=u"phase",
|
||||||
|
body=u"body", server_rx=1,
|
||||||
|
msg_id=u"msgid"))
|
||||||
msgs = self._messages(app)
|
msgs = self._messages(app)
|
||||||
self.assertEqual(len(msgs), 5)
|
self.assertEqual(len(msgs), 5)
|
||||||
self.assertEqual(msgs[-1]["body"], u"body")
|
self.assertEqual(msgs[-1]["body"], u"body")
|
||||||
|
@ -654,17 +665,21 @@ class WebSocketAPI(ServerBase, unittest.TestCase):
|
||||||
self.assertEqual(err[u"error"], u"open requires 'mailbox'")
|
self.assertEqual(err[u"error"], u"open requires 'mailbox'")
|
||||||
|
|
||||||
mb1 = app.open_mailbox(u"mb1", u"side2", 0)
|
mb1 = app.open_mailbox(u"mb1", u"side2", 0)
|
||||||
mb1.add_message(u"side2", u"phase", u"body", 0, u"msgid")
|
mb1.add_message(SidedMessage(side=u"side2", phase=u"phase",
|
||||||
|
body=u"body", server_rx=0,
|
||||||
|
msg_id=u"msgid"))
|
||||||
|
|
||||||
c1.send(u"open", mailbox=u"mb1")
|
c1.send(u"open", mailbox=u"mb1")
|
||||||
m = yield c1.next_non_ack()
|
m = yield c1.next_non_ack()
|
||||||
self.assertEqual(m[u"type"], u"message")
|
self.assertEqual(m[u"type"], u"message")
|
||||||
self.assertEqual(m[u"message"][u"body"], u"body")
|
self.assertEqual(m[u"body"], u"body")
|
||||||
|
|
||||||
mb1.add_message(u"side2", u"phase2", u"body2", 0, u"msgid")
|
mb1.add_message(SidedMessage(side=u"side2", phase=u"phase2",
|
||||||
|
body=u"body2", server_rx=0,
|
||||||
|
msg_id=u"msgid"))
|
||||||
m = yield c1.next_non_ack()
|
m = yield c1.next_non_ack()
|
||||||
self.assertEqual(m[u"type"], u"message")
|
self.assertEqual(m[u"type"], u"message")
|
||||||
self.assertEqual(m[u"message"][u"body"], u"body2")
|
self.assertEqual(m[u"body"], u"body2")
|
||||||
|
|
||||||
c1.send(u"open", mailbox=u"mb1")
|
c1.send(u"open", mailbox=u"mb1")
|
||||||
err = yield c1.next_non_ack()
|
err = yield c1.next_non_ack()
|
||||||
|
@ -701,10 +716,10 @@ class WebSocketAPI(ServerBase, unittest.TestCase):
|
||||||
c1.send(u"add", phase=u"phase", body=u"body")
|
c1.send(u"add", phase=u"phase", body=u"body")
|
||||||
m = yield c1.next_non_ack() # echoed back
|
m = yield c1.next_non_ack() # echoed back
|
||||||
self.assertEqual(m[u"type"], u"message")
|
self.assertEqual(m[u"type"], u"message")
|
||||||
self.assertEqual(m[u"message"][u"body"], u"body")
|
self.assertEqual(m[u"body"], u"body")
|
||||||
|
|
||||||
self.assertEqual(len(l1), 1)
|
self.assertEqual(len(l1), 1)
|
||||||
self.assertEqual(l1[0][u"body"], u"body")
|
self.assertEqual(l1[0].body, u"body")
|
||||||
|
|
||||||
@inlineCallbacks
|
@inlineCallbacks
|
||||||
def test_close(self):
|
def test_close(self):
|
||||||
|
|
Loading…
Reference in New Issue
Block a user