From 0299acfb6edf7d54ed112834a2b639567f782ab4 Mon Sep 17 00:00:00 2001 From: Lars-Dominik Braun Date: Sun, 5 May 2019 15:08:57 +0200 Subject: irc: Switch job id’s to proquints MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- crocoite/irc.py | 45 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 4 deletions(-) (limited to 'crocoite') 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) -- cgit v1.2.3