diff options
author | Lars-Dominik Braun <lars@6xq.net> | 2019-05-05 15:08:57 +0200 |
---|---|---|
committer | Lars-Dominik Braun <lars@6xq.net> | 2019-05-05 18:55:44 +0200 |
commit | 0299acfb6edf7d54ed112834a2b639567f782ab4 (patch) | |
tree | 34de533758665c6a108953f17d76d77700d76958 /crocoite | |
parent | e21e16d753f6a7ba787fdb3a3cd1ef504de7f69a (diff) | |
download | crocoite-0299acfb6edf7d54ed112834a2b639567f782ab4.tar.gz crocoite-0299acfb6edf7d54ed112834a2b639567f782ab4.tar.bz2 crocoite-0299acfb6edf7d54ed112834a2b639567f782ab4.zip |
irc: Switch job id’s to proquints
They’re easier to read and remember for humans. Plus we don’t really
need 128 bits of randomness. Time-based id’s are fine here.
Diffstat (limited to 'crocoite')
-rw-r--r-- | crocoite/irc.py | 45 |
1 files changed, 41 insertions, 4 deletions
diff --git a/crocoite/irc.py b/crocoite/irc.py index c9b8cd7..8e7061a 100644 --- a/crocoite/irc.py +++ b/crocoite/irc.py @@ -22,7 +22,7 @@ IRC bot “chromebot” """ -import asyncio, argparse, uuid, json, tempfile +import asyncio, argparse, json, tempfile, time, random from datetime import datetime from urllib.parse import urlsplit from enum import IntEnum, unique @@ -86,13 +86,45 @@ class Status(IntEnum): aborted = 3 finished = 4 +# see https://arxiv.org/html/0901.4016 on how to build proquints (human +# pronouncable unique ids) +toConsonant = 'bdfghjklmnprstvz' +toVowel = 'aiou' + +def u16ToQuint (v): + """ Transform a 16 bit unsigned integer into a single quint """ + assert 0 <= v < 2**16 + # quints are “big-endian” + return ''.join ([ + toConsonant[(v>>(4+2+4+2))&0xf], + toVowel[(v>>(4+2+4))&0x3], + toConsonant[(v>>(4+2))&0xf], + toVowel[(v>>4)&0x3], + toConsonant[(v>>0)&0xf], + ]) + +def uintToQuint (v, length=2): + """ Turn any integer into a proquint with fixed length """ + assert 0 <= v < 2**(length*16) + + return '-'.join (reversed ([u16ToQuint ((v>>(x*16))&0xffff) for x in range (length)])) + +def makeJobId (): + """ Create job id from time and randomness source """ + # allocate 48 bits for the time (in milliseconds) and add 16 random bits + # at the end (just to be sure) for a total of 64 bits. Should be enough to + # avoid collisions. + randbits = 16 + stamp = (int (time.time ()*1000) << randbits) | random.randint (0, 2**randbits-1) + return uintToQuint (stamp, 4) + class Job: """ Archival job """ __slots__ = ('id', 'stats', 'rstats', 'started', 'finished', 'nick', 'status', 'process', 'url') def __init__ (self, url, nick): - self.id = str (uuid.uuid4 ()) + self.id = makeJobId () self.stats = {} self.rstats = {} self.started = datetime.utcnow () @@ -441,8 +473,13 @@ class Chromebot (ArgparseBot): reply (f'{args.url} cannot be queued: {msg}') return - j = Job (args.url, user.name) - assert j.id not in self.jobs, 'duplicate job id' + # make sure the job id is unique. Since ids are time-based we can just + # wait. + while True: + j = Job (args.url, user.name) + if j.id not in self.jobs: + break + time.sleep (0.01) self.jobs[j.id] = j logger = self.logger.bind (job=j.id) |