server: summarize transfers, store in DB
This commit is contained in:
parent
26c7008c23
commit
4f0dde9529
|
@ -18,3 +18,18 @@ CREATE TABLE `messages`
|
|||
`when` INTEGER
|
||||
);
|
||||
CREATE INDEX `messages_idx` ON `messages` (`appid`, `channelid`);
|
||||
|
||||
CREATE TABLE `usage`
|
||||
(
|
||||
`started` INTEGER, -- seconds since epoch, rounded to one day
|
||||
`result` VARCHAR, -- happy, scary, lonely, errory, pruney
|
||||
-- "happy": both sides close with mood=happy
|
||||
-- "scary": any side closes with mood=scary (bad MAC, probably wrong pw)
|
||||
-- "lonely": any side closes with mood=lonely (no response from 2nd side)
|
||||
-- "errory": any side closes with mood=errory (other errors)
|
||||
-- "pruney": channels which get pruned for inactivity
|
||||
-- "crowded": three or more sides were involved
|
||||
`total_time` INTEGER, -- seconds from start to closed, or None
|
||||
`waiting_time` INTEGER -- seconds from start to 2nd side appearing, or None
|
||||
);
|
||||
CREATE INDEX `usage_idx` ON `usage` (`started`);
|
||||
|
|
|
@ -274,9 +274,72 @@ class Channel:
|
|||
return True
|
||||
return False
|
||||
|
||||
def _store_summary(self, summary):
|
||||
(started, result, total_time, waiting_time) = summary
|
||||
self._db.execute("INSERT INTO `usage`"
|
||||
" (`started`, `result`, `total_time`, `waiting_time`)"
|
||||
" VALUES (?,?,?,?)",
|
||||
(started, result, total_time, waiting_time))
|
||||
self._db.commit()
|
||||
|
||||
def _summarize(self, messages, delete_time):
|
||||
all_sides = set([m["side"] for m in messages])
|
||||
if len(all_sides) == 0:
|
||||
log.msg("_summarize was given zero messages") # shouldn't happen
|
||||
return
|
||||
|
||||
started = min([m["when"] for m in messages])
|
||||
# 'total_time' is how long the channel was occupied. That ends now,
|
||||
# both for channels that got pruned for inactivity, and for channels
|
||||
# that got pruned because of two DEALLOCATE messages
|
||||
total_time = delete_time - started
|
||||
|
||||
if len(all_sides) == 1:
|
||||
return (started, "lonely", total_time, None)
|
||||
if len(all_sides) > 2:
|
||||
# TODO: it'll be useful to have more detail here
|
||||
return (started, "crowded", total_time, None)
|
||||
|
||||
# exactly two sides were involved
|
||||
A_side = sorted(messages, key=lambda m: m["when"])[0]["side"]
|
||||
B_side = list(all_sides - set([A_side]))[0]
|
||||
|
||||
# How long did the first side wait until the second side showed up?
|
||||
first_A = min([m["when"] for m in messages if m["side"] == A_side])
|
||||
first_B = min([m["when"] for m in messages if m["side"] == B_side])
|
||||
waiting_time = first_B - first_A
|
||||
|
||||
# now, were all sides closed? If not, this is "pruney"
|
||||
A_deallocs = [m for m in messages
|
||||
if m["phase"] == DEALLOCATE and m["side"] == A_side]
|
||||
B_deallocs = [m for m in messages
|
||||
if m["phase"] == DEALLOCATE and m["side"] == B_side]
|
||||
if not A_deallocs or not B_deallocs:
|
||||
return (started, "pruney", total_time, None)
|
||||
|
||||
# ok, both sides closed. figure out the mood
|
||||
A_mood = A_deallocs[0]["body"]
|
||||
B_mood = B_deallocs[0]["body"]
|
||||
mood = "errory"
|
||||
if A_mood == u"happy" and B_mood == u"happy":
|
||||
mood = "happy"
|
||||
if A_mood == u"lonely" or B_mood == u"lonely":
|
||||
mood = "lonely"
|
||||
if A_mood == u"errory" or B_mood == u"errory":
|
||||
mood = "errory"
|
||||
if A_mood == u"scary" or B_mood == u"scary":
|
||||
mood = "scary"
|
||||
return (started, mood, total_time, waiting_time)
|
||||
|
||||
def delete_and_summarize(self):
|
||||
# TODO: summarize usage, write into DB
|
||||
db = self._db
|
||||
c = self._db.execute("SELECT * FROM `messages`"
|
||||
" WHERE `appid`=? AND `channelid`=?"
|
||||
" ORDER BY `when`",
|
||||
(self._appid, self._channelid))
|
||||
messages = c.fetchall()
|
||||
summary = self._summarize(messages, time.time())
|
||||
self._store_summary(summary)
|
||||
db.execute("DELETE FROM `messages`"
|
||||
" WHERE `appid`=? AND `channelid`=?",
|
||||
(self._appid, self._channelid))
|
||||
|
|
|
@ -8,6 +8,7 @@ from twisted.internet.threads import deferToThread
|
|||
from twisted.web.client import getPage, Agent, readBody
|
||||
from .. import __version__
|
||||
from .common import ServerBase
|
||||
from ..servers import relay_server
|
||||
from ..twisted.eventsource_twisted import EventSource
|
||||
|
||||
class Reachable(ServerBase, unittest.TestCase):
|
||||
|
@ -354,3 +355,61 @@ class OneEventAtATime:
|
|||
def disconnected(self, why):
|
||||
self.disconnected_d.callback((why,))
|
||||
|
||||
class Summary(unittest.TestCase):
|
||||
def test_summarize(self):
|
||||
c = relay_server.Channel(None, None, None, None, None)
|
||||
A = relay_server.ALLOCATE
|
||||
D = relay_server.DEALLOCATE
|
||||
|
||||
messages = [{"when": 1, "side": "a", "phase": A}]
|
||||
self.failUnlessEqual(c._summarize(messages, 2),
|
||||
(1, "lonely", 1, None))
|
||||
|
||||
messages = [{"when": 1, "side": "a", "phase": A},
|
||||
{"when": 2, "side": "a", "phase": D, "body": "lonely"},
|
||||
]
|
||||
self.failUnlessEqual(c._summarize(messages, 3),
|
||||
(1, "lonely", 2, None))
|
||||
|
||||
messages = [{"when": 1, "side": "a", "phase": A},
|
||||
{"when": 2, "side": "b", "phase": A},
|
||||
{"when": 3, "side": "c", "phase": A},
|
||||
]
|
||||
self.failUnlessEqual(c._summarize(messages, 4),
|
||||
(1, "crowded", 3, None))
|
||||
|
||||
base = [{"when": 1, "side": "a", "phase": A},
|
||||
{"when": 2, "side": "a", "phase": "pake", "body": "msg1"},
|
||||
{"when": 10, "side": "b", "phase": "pake", "body": "msg2"},
|
||||
{"when": 11, "side": "b", "phase": "data", "body": "msg3"},
|
||||
{"when": 20, "side": "a", "phase": "data", "body": "msg4"},
|
||||
]
|
||||
def make_moods(A_mood, B_mood):
|
||||
return base + [
|
||||
{"when": 21, "side": "a", "phase": D, "body": A_mood},
|
||||
{"when": 30, "side": "b", "phase": D, "body": B_mood},
|
||||
]
|
||||
|
||||
self.failUnlessEqual(c._summarize(make_moods("happy", "happy"), 41),
|
||||
(1, "happy", 40, 9))
|
||||
|
||||
self.failUnlessEqual(c._summarize(make_moods("scary", "happy"), 41),
|
||||
(1, "scary", 40, 9))
|
||||
self.failUnlessEqual(c._summarize(make_moods("happy", "scary"), 41),
|
||||
(1, "scary", 40, 9))
|
||||
|
||||
self.failUnlessEqual(c._summarize(make_moods("lonely", "happy"), 41),
|
||||
(1, "lonely", 40, 9))
|
||||
self.failUnlessEqual(c._summarize(make_moods("happy", "lonely"), 41),
|
||||
(1, "lonely", 40, 9))
|
||||
|
||||
self.failUnlessEqual(c._summarize(make_moods("errory", "happy"), 41),
|
||||
(1, "errory", 40, 9))
|
||||
self.failUnlessEqual(c._summarize(make_moods("happy", "errory"), 41),
|
||||
(1, "errory", 40, 9))
|
||||
|
||||
# scary trumps other moods
|
||||
self.failUnlessEqual(c._summarize(make_moods("scary", "lonely"), 41),
|
||||
(1, "scary", 40, 9))
|
||||
self.failUnlessEqual(c._summarize(make_moods("scary", "errory"), 41),
|
||||
(1, "scary", 40, 9))
|
||||
|
|
Loading…
Reference in New Issue
Block a user