WIP
This commit is contained in:
parent
5994eb11d4
commit
0e72422ffa
|
@ -17,7 +17,11 @@ CREATE TABLE `nameplates`
|
|||
`id` VARCHAR,
|
||||
`mailbox_id` VARCHAR, -- really a foreign key
|
||||
`side1` VARCHAR, -- side name, or NULL
|
||||
`side2` VARCHAR -- side name, or NULL
|
||||
`side2` VARCHAR, -- side name, or NULL
|
||||
-- timing data
|
||||
`started` INTEGER, -- time when nameplace was opened
|
||||
`second` INTEGER, -- time when second side opened
|
||||
`closed` INTEGER -- time when closed
|
||||
);
|
||||
CREATE INDEX `nameplates_idx` ON `nameplates` (`app_id`, `id`);
|
||||
CREATE INDEX `nameplates_mailbox_idx` ON `nameplates` (`app_id`, `mailbox_id`);
|
||||
|
@ -30,10 +34,6 @@ CREATE TABLE `mailboxes`
|
|||
`id` VARCHAR,
|
||||
`side1` VARCHAR -- side name, or NULL
|
||||
`side2` VARCHAR -- side name, or NULL
|
||||
-- timing data for the (optional) linked nameplate
|
||||
`nameplate_started` INTEGER, -- time when related nameplace was opened
|
||||
`nameplate_second` INTEGER, -- time when second side opened
|
||||
`nameplate_closed` INTEGER, -- time when closed
|
||||
-- timing data for the mailbox itself
|
||||
`started` INTEGER, -- time when opened
|
||||
`second` INTEGER, -- time when second side opened
|
||||
|
|
|
@ -17,7 +17,7 @@ RELEASE = u"_release"
|
|||
|
||||
def get_sides(row):
|
||||
return set([s for s in [row["side1"], row["side2"]] if s])
|
||||
def make_sides(side1, side2):
|
||||
def make_sides(sides):
|
||||
return list(sides) + [None] * (2 - len(sides))
|
||||
def generate_mailbox_id():
|
||||
return base64.b32encode(os.urandom(8)).lower().strip("=")
|
||||
|
@ -270,7 +270,7 @@ class AppNamespace:
|
|||
" WHERE `app_id`=?", (self._app_id,))
|
||||
return set([row["id"] for row in c.fetchall()])
|
||||
|
||||
def find_available_nameplate_id(self):
|
||||
def _find_available_nameplate_id(self):
|
||||
claimed = self.get_nameplate_ids()
|
||||
for size in range(1,4): # stick to 1-999 for now
|
||||
available = set()
|
||||
|
@ -288,6 +288,12 @@ class AppNamespace:
|
|||
return id
|
||||
raise ValueError("unable to find a free nameplate-id")
|
||||
|
||||
def allocate_nameplate(self, side, when):
|
||||
nameplate_id = self._find_available_nameplate_id()
|
||||
mailbox_id = self.claim_nameplate(self, nameplate_id, side, when)
|
||||
del mailbox_id # ignored, they'll learn it from claim()
|
||||
return nameplate_id
|
||||
|
||||
def _get_mailbox_id(self, nameplate_id):
|
||||
row = self._db.execute("SELECT `mailbox_id` FROM `nameplates`"
|
||||
" WHERE `app_id`=? AND `id`=?",
|
||||
|
@ -295,36 +301,81 @@ class AppNamespace:
|
|||
return row["mailbox_id"]
|
||||
|
||||
def claim_nameplate(self, nameplate_id, side, when):
|
||||
# when we're done:
|
||||
# * there will be one row for the nameplate
|
||||
# * side1 or side2 will be populated
|
||||
# * started or second will be populated
|
||||
# * a mailbox id will be created, but not a mailbox row
|
||||
# (ids are randomly unique, so we can defer creation until 'open')
|
||||
assert isinstance(nameplate_id, type(u"")), type(nameplate_id)
|
||||
assert isinstance(side, type(u"")), type(side)
|
||||
db = self._db
|
||||
rows = db.execute("SELECT * FROM `nameplates`"
|
||||
" WHERE `app_id`=? AND `id`=?",
|
||||
(self._app_id, nameplate_id))
|
||||
if rows:
|
||||
mailbox_id = rows[0]["mailbox_id"]
|
||||
row = db.execute("SELECT * FROM `nameplates`"
|
||||
" WHERE `app_id`=? AND `id`=?",
|
||||
(self._app_id, nameplate_id)).fetchone()
|
||||
if row:
|
||||
mailbox_id = row["mailbox_id"]
|
||||
sides = [row["side1"], row["sides2"]]
|
||||
if side not in sides:
|
||||
if sides[0] and sides[1]:
|
||||
raise XXXERROR("crowded")
|
||||
sides[1] = side
|
||||
db.execute("UPDATE `nameplates` SET "
|
||||
"`side1`=?, `side2`=?, `mailbox_id`=?, `second`=?"
|
||||
" WHERE `app_id`=? AND `id`=?",
|
||||
(sides[0], sides[1], mailbox_id, when,
|
||||
self._app_id, nameplate_id))
|
||||
else:
|
||||
if self._log_requests:
|
||||
log.msg("creating nameplate#%s for app_id %s" %
|
||||
(nameplate_id, self._app_id))
|
||||
mailbox_id = UUID()
|
||||
db.execute("INSERT INTO `mailboxes`"
|
||||
" (`app_id`, `id`)"
|
||||
" VALUES(?,?)",
|
||||
(self._app_id, mailbox_id))
|
||||
mailbox_id = generate_mailbox_id()
|
||||
db.execute("INSERT INTO `nameplates`"
|
||||
" (`app_id`, `id`, `mailbox_id`, `side1`, `side2`)"
|
||||
" (`app_id`, `id`, `mailbox_id`, `side1`, `started`)"
|
||||
" VALUES(?,?,?,?,?)",
|
||||
(self._app_id, nameplate_id, mailbox_id, None, None))
|
||||
(self._app_id, nameplate_id, mailbox_id, side, when))
|
||||
db.commit()
|
||||
return mailbox_id
|
||||
|
||||
nameplate = Nameplate(self._app_id, self._db, nameplate_id, mailbox_id)
|
||||
nameplate.claim(side, when)
|
||||
return nameplate
|
||||
def release_nameplate(self, nameplate_id, side, when):
|
||||
# when we're done:
|
||||
# * in the nameplate row, side1 or side2 will be removed
|
||||
# * if the nameplate is now unused:
|
||||
# * mailbox.nameplate_closed will be populated
|
||||
# * the nameplate row will be removed
|
||||
assert isinstance(nameplate_id, type(u"")), type(nameplate_id)
|
||||
assert isinstance(side, type(u"")), type(side)
|
||||
db = self._db
|
||||
row = db.execute("SELECT * FROM `nameplates`"
|
||||
" WHERE `app_id`=? AND `id`=?",
|
||||
(self._app_id, nameplate_id)).fetchone()
|
||||
if not row:
|
||||
return
|
||||
sides = get_sides(row)
|
||||
if side not in sides:
|
||||
return
|
||||
sides.discard(side)
|
||||
if sides:
|
||||
s12 = make_sides(sides)
|
||||
db.execute("UPDATE `nameplates` SET `side1`=?, `side2`=?"
|
||||
" WHERE `app_id`=? AND `id`=?",
|
||||
(s12[0], s12[1], self._app_id, nameplate_id))
|
||||
else:
|
||||
db.execute("DELETE FROM `nameplates`"
|
||||
" WHERE `app_id`=? AND `id`=?",
|
||||
(self._app_id, nameplate_id))
|
||||
self._summarize_nameplate(row)
|
||||
|
||||
def claim_channel(self, channelid, side):
|
||||
def open_mailbox(self, channelid, side):
|
||||
assert isinstance(channelid, type(u"")), type(channelid)
|
||||
channel = self.get_channel(channelid)
|
||||
channel.claim(side)
|
||||
return channel
|
||||
# some of this overlaps with open() on a new mailbox
|
||||
db.execute("INSERT INTO `mailboxes`"
|
||||
" (`app_id`, `id`, `nameplate_started`, `started`)"
|
||||
" VALUES(?,?,?,?)",
|
||||
(self._app_id, mailbox_id, when, when))
|
||||
|
||||
def get_channel(self, channelid):
|
||||
assert isinstance(channelid, type(u""))
|
||||
|
|
|
@ -155,31 +155,28 @@ class WebSocketRendezvous(websocket.WebSocketServerProtocol):
|
|||
def handle_allocate(self, server_rx):
|
||||
if self._did_allocate:
|
||||
raise Error("You already allocated one channel, don't be greedy")
|
||||
nameplate_id = self._app.find_available_nameplate_id()
|
||||
nameplate_id = self._app.allocate_nameplate(self._side, server_rx)
|
||||
assert isinstance(nameplate_id, type(u""))
|
||||
self._did_allocate = True
|
||||
self._nameplate = self._app.claim_nameplate(nameplate_id, self._side,
|
||||
server_rx)
|
||||
self.send("nameplate", nameplate=nameplate_id)
|
||||
|
||||
def handle_claim(self, msg, server_rx):
|
||||
if "nameplate" not in msg:
|
||||
raise Error("claim requires 'nameplate'")
|
||||
nameplate_id = msg["nameplate"]
|
||||
self._nameplate_id = nameplate_id
|
||||
assert isinstance(nameplate_id, type(u"")), type(nameplate)
|
||||
if self._nameplate and self._nameplate.get_id() != nameplate_id:
|
||||
raise Error("claimed nameplate doesn't match allocated nameplate")
|
||||
self._nameplate = self._app.claim_nameplate(nameplate_id, self._side,
|
||||
server_rx)
|
||||
mailbox_id = self._nameplate.get_mailbox_id()
|
||||
mailbox_id = self._app.claim_nameplate(nameplate_id, self._side,
|
||||
server_rx)
|
||||
self.send("mailbox", mailbox=mailbox_id)
|
||||
|
||||
def handle_release(self, server_rx):
|
||||
if not self._nameplate:
|
||||
if not self._nameplate_id:
|
||||
raise Error("must claim a nameplate before releasing it")
|
||||
|
||||
deleted = self._nameplate.release(self._side, server_rx)
|
||||
self._nameplate = None
|
||||
deleted = self._app.release_nameplate(self._nameplate_id,
|
||||
self._side, server_rx)
|
||||
self._nameplate_id = None
|
||||
|
||||
|
||||
def handle_open(self, msg):
|
||||
|
|
Loading…
Reference in New Issue
Block a user