11from __future__ import annotations
22
33import asyncio
4- import binascii
54import contextlib
6- import os
75import time
8- from hashlib import blake2b
96from typing import TYPE_CHECKING , Generic , Literal , cast
107from typing_extensions import (
118 Any ,
3128from duron ._core .stream import ObserverStream , Stream , StreamWriter
3229from duron ._loop import EventLoop , create_loop
3330from duron .codec import Codec , JSONValue
34- from duron .log import is_entry
31+ from duron .log import decode_id , derive_id , encode_id , is_entry , random_id
3532from duron .typing import Unspecified , inspect_function
3633
3734if TYPE_CHECKING :
@@ -257,7 +254,7 @@ async def _invoke_prelude(
257254 if init_params ["version" ] != _CURRENT_VERSION :
258255 msg = "version mismatch"
259256 raise RuntimeError (msg )
260- loop .set_key (_decode_id (init_params ["seed" ]))
257+ loop .set_key (decode_id (init_params ["seed" ]))
261258 extra_kwargs : dict [str , object ] = {}
262259 for name , type_ , dtype in job_fn .inject :
263260 with ctx .metadata ({"param.name" : name }):
@@ -423,7 +420,7 @@ async def handle_message(
423420 pending_info = self ._pending_task .pop (e ["promise_id" ], None )
424421 task_info = self ._tasks .get (e ["promise_id" ], None )
425422
426- id_ = _decode_id (e ["promise_id" ])
423+ id_ = decode_id (e ["promise_id" ])
427424
428425 return_type : TypeHint [Any ] = Unspecified
429426 if pending_info is not None :
@@ -454,7 +451,7 @@ async def handle_message(
454451 msg = f"Invalid promise/complete entry: { e !r} "
455452 raise ValueError (msg )
456453 elif e ["type" ] == "stream/create" :
457- id_ = _decode_id (e ["id" ])
454+ id_ = decode_id (e ["id" ])
458455 if e ["id" ] not in self ._streams :
459456 self ._loop .post_completion (
460457 id_ , exception = ValueError ("Stream not found" )
@@ -463,7 +460,7 @@ async def handle_message(
463460 self ._loop .post_completion (id_ , result = e ["id" ])
464461 self ._pending_ops .discard (id_ )
465462 elif e ["type" ] == "stream/emit" :
466- id_ = _decode_id (e ["id" ])
463+ id_ = decode_id (e ["id" ])
467464 if e ["stream_id" ] not in self ._streams :
468465 self ._loop .post_completion (
469466 id_ , exception = ValueError ("Stream not found" )
@@ -478,7 +475,7 @@ async def handle_message(
478475 self ._loop .post_completion (id_ , result = None )
479476 self ._pending_ops .discard (id_ )
480477 elif e ["type" ] == "stream/complete" :
481- id_ = _decode_id (e ["id" ])
478+ id_ = decode_id (e ["id" ])
482479 if e ["stream_id" ] not in self ._streams :
483480 self ._loop .post_completion (
484481 id_ , exception = ValueError ("Stream not found" )
@@ -495,7 +492,7 @@ async def handle_message(
495492 _ = self ._streams .pop (e ["stream_id" ], None )
496493 self ._pending_ops .discard (id_ )
497494 elif e ["type" ] == "barrier" :
498- id_ = _decode_id (e ["id" ])
495+ id_ = decode_id (e ["id" ])
499496 self ._loop .post_completion (id_ , result = offset )
500497 self ._pending_ops .discard (id_ )
501498
@@ -524,7 +521,7 @@ async def enqueue_op(self, id_: bytes, fut: OpFuture[object]) -> None:
524521 case FnCall ():
525522 promise_create_entry : PromiseCreateEntry = {
526523 "ts" : self .now (),
527- "id" : _encode_id (id_ ),
524+ "id" : encode_id (id_ ),
528525 "type" : "promise/create" ,
529526 }
530527 if op .metadata :
@@ -538,11 +535,12 @@ async def enqueue_op(self, id_: bytes, fut: OpFuture[object]) -> None:
538535 await self .enqueue_log (promise_create_entry )
539536
540537 async def cb () -> None :
538+ now_us = self .now ()
541539 entry : PromiseCompleteEntry = {
542- "ts" : self . now () ,
543- "id" : _encode_id ( id_ , ack = True ),
540+ "ts" : now_us ,
541+ "id" : encode_id ( derive_id ( id_ ) ),
544542 "type" : "promise/complete" ,
545- "promise_id" : _encode_id (id_ ),
543+ "promise_id" : encode_id (id_ ),
546544 }
547545 try :
548546 result = op .callable (* op .args , ** op .kwargs )
@@ -558,7 +556,7 @@ async def cb() -> None:
558556
559557 def done (f : OpFuture [object ]) -> None :
560558 if f .cancelled ():
561- sid = _encode_id (f .id )
559+ sid = encode_id (f .id )
562560 if self ._pending_task .get (sid , None ):
563561 # pending task cancelled
564562 pass
@@ -568,14 +566,14 @@ def done(f: OpFuture[object]) -> None:
568566 _ = task .get_loop ().call_soon (task .cancel )
569567
570568 fut .add_done_callback (done )
571- sid = _encode_id (id_ )
569+ sid = encode_id (id_ )
572570 if self ._running :
573571 self ._tasks [sid ] = (asyncio .create_task (cb ()), op .return_type )
574572 else :
575573 self ._pending_task [sid ] = (cb , op .return_type )
576574
577575 case StreamCreate ():
578- stream_id = _encode_id (id_ )
576+ stream_id = encode_id (id_ )
579577
580578 # Determine which observer to use
581579 ob = [op .observer ] if op .observer else []
@@ -599,7 +597,7 @@ def done(f: OpFuture[object]) -> None:
599597 case StreamEmit ():
600598 stream_emit_entry : StreamEmitEntry = {
601599 "ts" : self .now (),
602- "id" : _encode_id (id_ ),
600+ "id" : encode_id (id_ ),
603601 "stream_id" : op .stream_id ,
604602 "type" : "stream/emit" ,
605603 "value" : self ._codec .encode_json (op .value ),
@@ -609,7 +607,7 @@ def done(f: OpFuture[object]) -> None:
609607 if op .exception :
610608 stream_close_entry_err : StreamCompleteEntry = {
611609 "ts" : self .now (),
612- "id" : _encode_id (id_ ),
610+ "id" : encode_id (id_ ),
613611 "stream_id" : op .stream_id ,
614612 "type" : "stream/complete" ,
615613 "error" : _encode_error (op .exception ),
@@ -618,27 +616,27 @@ def done(f: OpFuture[object]) -> None:
618616 else :
619617 stream_close_entry : StreamCompleteEntry = {
620618 "ts" : self .now (),
621- "id" : _encode_id (id_ ),
619+ "id" : encode_id (id_ ),
622620 "stream_id" : op .stream_id ,
623621 "type" : "stream/complete" ,
624622 }
625623 await self .enqueue_log (stream_close_entry )
626624 case Barrier ():
627625 barrier_entry : BarrierEntry = {
628626 "ts" : self .now (),
629- "id" : _encode_id (id_ ),
627+ "id" : encode_id (id_ ),
630628 "type" : "barrier" ,
631629 }
632630 await self .enqueue_log (barrier_entry , flush = True )
633631 case ExternalPromiseCreate ():
634632 promise_create_entry = {
635633 "ts" : self .now (),
636- "id" : _encode_id (id_ ),
634+ "id" : encode_id (id_ ),
637635 "type" : "promise/create" ,
638636 }
639637 if op .metadata :
640638 promise_create_entry ["metadata" ] = op .metadata
641- self ._tasks [_encode_id (id_ )] = (asyncio .Future (), op .return_type )
639+ self ._tasks [encode_id (id_ )] = (asyncio .Future (), op .return_type )
642640 await self .enqueue_log (promise_create_entry )
643641 case _:
644642 assert_never (op )
@@ -653,9 +651,10 @@ async def complete_external_promise(
653651 if id_ not in self ._tasks :
654652 msg = "Promise not found"
655653 raise ValueError (msg )
654+ now_us = self .now ()
656655 entry : PromiseCompleteEntry = {
657- "ts" : self . now () ,
658- "id" : _encode_id ( _decode_id ( id_ ), ack = True ),
656+ "ts" : now_us ,
657+ "id" : encode_id ( derive_id ( decode_id ( id_ )) ),
659658 "type" : "promise/complete" ,
660659 "promise_id" : id_ ,
661660 }
@@ -723,21 +722,8 @@ async def close_stream(
723722 return cnt
724723
725724
726- def _encode_id (id_ : bytes , * , ack : bool = False ) -> str :
727- if ack :
728- id_ = blake2b (
729- id_ ,
730- digest_size = 12 ,
731- ).digest ()
732- return binascii .b2a_base64 (id_ , newline = False ).decode ()
733-
734-
735- def _decode_id (encoded : str ) -> bytes :
736- return binascii .a2b_base64 (encoded )
737-
738-
739725def _generate_id () -> str :
740- return _encode_id ( os . urandom ( 12 ))
726+ return encode_id ( random_id ( ))
741727
742728
743729def _encode_error (error : BaseException ) -> ErrorInfo :
0 commit comments