WIP
This commit is contained in:
parent
5994eb11d4
commit
0e72422ffa
|
@ -17,7 +17,11 @@ CREATE TABLE `nameplates`
|
||||||
`id` VARCHAR,
|
`id` VARCHAR,
|
||||||
`mailbox_id` VARCHAR, -- really a foreign key
|
`mailbox_id` VARCHAR, -- really a foreign key
|
||||||
`side1` VARCHAR, -- side name, or NULL
|
`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_idx` ON `nameplates` (`app_id`, `id`);
|
||||||
CREATE INDEX `nameplates_mailbox_idx` ON `nameplates` (`app_id`, `mailbox_id`);
|
CREATE INDEX `nameplates_mailbox_idx` ON `nameplates` (`app_id`, `mailbox_id`);
|
||||||
|
@ -30,10 +34,6 @@ CREATE TABLE `mailboxes`
|
||||||
`id` VARCHAR,
|
`id` VARCHAR,
|
||||||
`side1` VARCHAR -- side name, or NULL
|
`side1` VARCHAR -- side name, or NULL
|
||||||
`side2` 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
|
-- timing data for the mailbox itself
|
||||||
`started` INTEGER, -- time when opened
|
`started` INTEGER, -- time when opened
|
||||||
`second` INTEGER, -- time when second side opened
|
`second` INTEGER, -- time when second side opened
|
||||||
|
|
|
@ -17,7 +17,7 @@ RELEASE = u"_release"
|
||||||
|
|
||||||
def get_sides(row):
|
def get_sides(row):
|
||||||
return set([s for s in [row["side1"], row["side2"]] if s])
|
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))
|
return list(sides) + [None] * (2 - len(sides))
|
||||||
def generate_mailbox_id():
|
def generate_mailbox_id():
|
||||||
return base64.b32encode(os.urandom(8)).lower().strip("=")
|
return base64.b32encode(os.urandom(8)).lower().strip("=")
|
||||||
|
@ -270,7 +270,7 @@ class AppNamespace:
|
||||||
" WHERE `app_id`=?", (self._app_id,))
|
" WHERE `app_id`=?", (self._app_id,))
|
||||||
return set([row["id"] for row in c.fetchall()])
|
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()
|
claimed = self.get_nameplate_ids()
|
||||||
for size in range(1,4): # stick to 1-999 for now
|
for size in range(1,4): # stick to 1-999 for now
|
||||||
available = set()
|
available = set()
|
||||||
|
@ -288,6 +288,12 @@ class AppNamespace:
|
||||||
return id
|
return id
|
||||||
raise ValueError("unable to find a free nameplate-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):
|
def _get_mailbox_id(self, nameplate_id):
|
||||||
row = self._db.execute("SELECT `mailbox_id` FROM `nameplates`"
|
row = self._db.execute("SELECT `mailbox_id` FROM `nameplates`"
|
||||||
" WHERE `app_id`=? AND `id`=?",
|
" WHERE `app_id`=? AND `id`=?",
|
||||||
|
@ -295,36 +301,81 @@ class AppNamespace:
|
||||||
return row["mailbox_id"]
|
return row["mailbox_id"]
|
||||||
|
|
||||||
def claim_nameplate(self, nameplate_id, side, when):
|
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(nameplate_id, type(u"")), type(nameplate_id)
|
||||||
|
assert isinstance(side, type(u"")), type(side)
|
||||||
db = self._db
|
db = self._db
|
||||||
rows = db.execute("SELECT * FROM `nameplates`"
|
row = db.execute("SELECT * FROM `nameplates`"
|
||||||
" WHERE `app_id`=? AND `id`=?",
|
" WHERE `app_id`=? AND `id`=?",
|
||||||
(self._app_id, nameplate_id))
|
(self._app_id, nameplate_id)).fetchone()
|
||||||
if rows:
|
if row:
|
||||||
mailbox_id = rows[0]["mailbox_id"]
|
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:
|
else:
|
||||||
if self._log_requests:
|
if self._log_requests:
|
||||||
log.msg("creating nameplate#%s for app_id %s" %
|
log.msg("creating nameplate#%s for app_id %s" %
|
||||||
(nameplate_id, self._app_id))
|
(nameplate_id, self._app_id))
|
||||||
mailbox_id = UUID()
|
mailbox_id = generate_mailbox_id()
|
||||||
db.execute("INSERT INTO `mailboxes`"
|
|
||||||
" (`app_id`, `id`)"
|
|
||||||
" VALUES(?,?)",
|
|
||||||
(self._app_id, mailbox_id))
|
|
||||||
db.execute("INSERT INTO `nameplates`"
|
db.execute("INSERT INTO `nameplates`"
|
||||||
" (`app_id`, `id`, `mailbox_id`, `side1`, `side2`)"
|
" (`app_id`, `id`, `mailbox_id`, `side1`, `started`)"
|
||||||
" VALUES(?,?,?,?,?)",
|
" 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)
|
def release_nameplate(self, nameplate_id, side, when):
|
||||||
nameplate.claim(side, when)
|
# when we're done:
|
||||||
return nameplate
|
# * 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)
|
assert isinstance(channelid, type(u"")), type(channelid)
|
||||||
channel = self.get_channel(channelid)
|
channel = self.get_channel(channelid)
|
||||||
channel.claim(side)
|
channel.claim(side)
|
||||||
return channel
|
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):
|
def get_channel(self, channelid):
|
||||||
assert isinstance(channelid, type(u""))
|
assert isinstance(channelid, type(u""))
|
||||||
|
|
|
@ -155,31 +155,28 @@ class WebSocketRendezvous(websocket.WebSocketServerProtocol):
|
||||||
def handle_allocate(self, server_rx):
|
def handle_allocate(self, server_rx):
|
||||||
if self._did_allocate:
|
if self._did_allocate:
|
||||||
raise Error("You already allocated one channel, don't be greedy")
|
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""))
|
assert isinstance(nameplate_id, type(u""))
|
||||||
self._did_allocate = True
|
self._did_allocate = True
|
||||||
self._nameplate = self._app.claim_nameplate(nameplate_id, self._side,
|
|
||||||
server_rx)
|
|
||||||
self.send("nameplate", nameplate=nameplate_id)
|
self.send("nameplate", nameplate=nameplate_id)
|
||||||
|
|
||||||
def handle_claim(self, msg, server_rx):
|
def handle_claim(self, msg, server_rx):
|
||||||
if "nameplate" not in msg:
|
if "nameplate" not in msg:
|
||||||
raise Error("claim requires 'nameplate'")
|
raise Error("claim requires 'nameplate'")
|
||||||
nameplate_id = msg["nameplate"]
|
nameplate_id = msg["nameplate"]
|
||||||
|
self._nameplate_id = nameplate_id
|
||||||
assert isinstance(nameplate_id, type(u"")), type(nameplate)
|
assert isinstance(nameplate_id, type(u"")), type(nameplate)
|
||||||
if self._nameplate and self._nameplate.get_id() != nameplate_id:
|
mailbox_id = self._app.claim_nameplate(nameplate_id, self._side,
|
||||||
raise Error("claimed nameplate doesn't match allocated nameplate")
|
server_rx)
|
||||||
self._nameplate = self._app.claim_nameplate(nameplate_id, self._side,
|
|
||||||
server_rx)
|
|
||||||
mailbox_id = self._nameplate.get_mailbox_id()
|
|
||||||
self.send("mailbox", mailbox=mailbox_id)
|
self.send("mailbox", mailbox=mailbox_id)
|
||||||
|
|
||||||
def handle_release(self, server_rx):
|
def handle_release(self, server_rx):
|
||||||
if not self._nameplate:
|
if not self._nameplate_id:
|
||||||
raise Error("must claim a nameplate before releasing it")
|
raise Error("must claim a nameplate before releasing it")
|
||||||
|
|
||||||
deleted = self._nameplate.release(self._side, server_rx)
|
deleted = self._app.release_nameplate(self._nameplate_id,
|
||||||
self._nameplate = None
|
self._side, server_rx)
|
||||||
|
self._nameplate_id = None
|
||||||
|
|
||||||
|
|
||||||
def handle_open(self, msg):
|
def handle_open(self, msg):
|
||||||
|
|
Loading…
Reference in New Issue
Block a user