char/avril
(wip) why'd you have to go and make things so complicaaaaated?
git clone https://git.t4t.associates/char/avril
e9b1b43
main
1const portPost = MessagePort . prototype . postMessage ; 2const portClose = MessagePort . prototype . close ; 3const readerClosed = descriptor ( ReadableDefaultReader . prototype , "closed" ) ! 4. get as () => Promise < void >; 5 6function send ( port :Port , value :RequestPacket | ReplyPacket ) :unknown { 7return apply ( portPost , port , [ value ]); 8} 9function disconnect ( port :Port ) :void { 10apply ( portClose , port , []); 11} 12function prepareWireStream ( _state :unknown , source :object ) :StreamRecord { 13const record :StreamRecord = { source, readable :null , writable :null }; 14if ( descriptor ( source , "_readableStreamController" )) { 15record . kind = "readable" ; 16record . readable = source as ReadableResource ; 17} else if ( descriptor ( source , "_writableStreamController" )) { 18record . kind = "writable" ; 19record . writable = source as WritableResource ; 20} else if ( descriptor ( source , "_transformStreamController" )) { 21record . kind = "transform" ; 22record . readable = ownValue ( source , "_readable" ) as ReadableResource ; 23record . writable = ownValue ( source , "_writable" ) as WritableResource ; 24} else throw dataCloneError ( "Invalid transferable stream" ); 25validateRecord ( record ); 26if ( record . readable ) record . readPair = op_port_pair (); 27if ( record . writable ) record . writePair = op_port_pair (); 28return record ; 29} 30function serveStream ( 31port :Port , 32resource :Reader | Writer , 33readable :boolean , 34) :void { 35let finished = false , disconnected = false , active = 0 ; 36function finish () { 37finished = true ; 38if ( active === 0 && ! disconnected ) { 39disconnected = true ; 40disconnect ( port ); 41} 42} 43const closed = invoke ( readable ?readerClosed :writerClosed , resource ); 44then ( closed , undefined , ( error ) => { 45if ( ! disconnected ) { 46send ( port , [ null , false , cloneError ( error )]); 47disconnected = true ; 48disconnect ( port ); 49} 50}); 51setPortCloseHandler ( port , () => { 52if ( ! disconnected ) { 53disconnected = true ; 54const reason = dataCloneError ( "Transferred stream endpoint closed" ); 55markPromiseHandled ( 56invoke ( readable ?cancelReader :abortWriter , resource , [ reason ]), 57); 58disconnect ( port ); 59} 60}); 61addListener ( port , "message" , ( event ) => { 62if ( finished || disconnected ) return ; 63const packet = messageData ( event ) as RequestPacket ; 64const id = packet [ 0 ], command = packet [ 1 ], value = packet [ 2 ]; 65active ++ ; 66let operation ; 67try { 68if ( readable ) { 69operation = command === "read" 70 ?invoke ( read , resource ) 71 :invoke ( cancelReader , resource , [ value ]); 72} else { 73operation = command === "write" 74 ?invoke ( write , resource , [ value ]) 75 :command === "close" 76 ?invoke ( closeWriter , resource ) 77 :invoke ( abortWriter , resource , [ value ]); 78} 79} catch ( error ) { 80operation = safePromiseReject ( error ); 81} 82then ( safePromiseResolve ( operation ), ( result ) => { 83active -- ; 84if ( disconnected ) return ; 85try { 86send ( port , [ id , true , result ]); 87} catch ( error ) { 88markPromiseHandled ( 89invoke ( readable ?cancelReader :abortWriter , resource , [ error ]), 90); 91send ( port , [ id , false , cloneError ( error )]); 92finish (); 93return ; 94} 95if ( 96finished || command === "cancel" || command === "close" || 97command === "abort" || 98( readable && ( result as ReadResult | undefined )?. done ) 99) finish (); 100}, ( error ) => { 101active -- ; 102if ( ! disconnected ) { 103send ( port , [ id , false , cloneError ( error )]); 104finish (); 105} 106}); 107}); 108startPort ( port ); 109} 110function commitWireStream ( 111_state :unknown , 112_source :object , 113record :StreamRecord , 114) :void { 115if ( record . readable ) { 116record . reader = acquireReader ( record . readable ); 117op_port_move ( record . readPair ! [ 1 ]); 118serveStream ( adoptPort ( record . readPair ! [ 0 ]), record . reader , true ); 119} 120if ( record . writable ) { 121record . writer = acquireWriter ( record . writable ); 122op_port_move ( record . writePair ! [ 1 ]); 123serveStream ( adoptPort ( record . writePair ! [ 0 ]), record . writer , false ); 124} 125} 126function streamClient ( id :number ) { 127const port = adoptPort ( id ), 128pending = new Map < 129number , 130{ resolve ( value :unknown ) :void ; reject ( reason :unknown ) :void } 131>(); 132let next = 0 , ended = false , onerror :(( reason :unknown ) => void ) | undefined ; 133function fail ( error :unknown ) :void { 134if ( ended ) return ; 135ended = true ; 136mapForEach ( pending , ( entry ) => entry . reject ( error )); 137mapClear ( pending ); 138onerror ?.( error ); 139disconnect ( port ); 140} 141setPortCloseHandler ( 142port , 143() => fail ( dataCloneError ( "Transferred stream endpoint closed" )), 144); 145addListener ( port , "message" , ( event ) => { 146const packet = messageData ( event ) as ReplyPacket ; 147const id = packet [ 0 ], ok = packet [ 1 ], value = packet [ 2 ]; 148if ( id === null ) { 149fail ( value ); 150return ; 151} 152const entry = mapGet ( pending , id ); 153if ( ! entry ) return ; 154mapDelete ( pending , id ); 155if ( ok ) entry . resolve ( value ); 156else entry . reject ( value ); 157}); 158startPort ( port ); 159return { 160set onerror ( callback :( reason :unknown ) => void ) { 161onerror = callback ; 162}, 163request < C extends RequestPacket [ 1 ] > ( 164command :C , 165value ?:unknown , 166) :Promise < C extends "read" ?ReadResult :void > { 167if ( ended ) { 168return safePromiseReject ( 169dataCloneError ( "Transferred stream endpoint closed" ), 170); 171} 172const id = next ++ ; 173return safeNewPromise < C extends "read" ?ReadResult :void >( 174( resolve , reject ) => { 175mapSet ( pending , id , { 176resolve :resolve as ( value :unknown ) => void , 177 reject, 178}); 179try { 180send ( port , [ id , command , value ]); 181const retain = () => 182then ( referencePort ( port ), () => { 183if ( ! ended && mapGet ( pending , id )) retain (); 184}); 185retain (); 186} catch ( error ) { 187fail ( error ); 188} 189}, 190); 191}, 192close () { 193ended = true ; 194disconnect ( port ); 195}, 196}; 197} 198function decodeWireStream ( packet :StreamPacket ) :StreamResource { 199const kind = packet [ 0 ], 200readId = packet [ 1 ], 201writeId = packet [ 2 ], 202writableClosed = packet [ 3 ]; 203let readable , writable ; 204if ( readId !== null ) { 205const client = streamClient ( readId ); 206readable = new Readable ({ 207start ( controller ) { 208client . onerror = ( error ) => controller . error ( error ); 209}, 210pull ( controller ) { 211return then ( client . request ( "read" ), ( result ) => { 212if ( result . done ) { 213controller . close (); 214client . close (); 215} else controller . enqueue ( result . value ); 216}); 217}, 218cancel ( reason ) { 219return then ( 220client . request ( "cancel" , reason ), 221() => client . close (), 222( error ) => { 223client . close (); 224throw error ; 225}, 226); 227}, 228}, { highWaterMark :0 }); 229} 230if ( writeId !== null ) { 231const client = streamClient ( writeId ); 232writable = new Writable ( 233writableClosed ?{} :{ 234start ( controller ) { 235client . onerror = ( error ) => controller . error ( error ); 236}, 237write ( chunk ) { 238return client . request ( "write" , chunk ); 239}, 240close () { 241return then ( client . request ( "close" ), () => client . close ()); 242}, 243abort ( reason ) { 244return then ( client . request ( "abort" , reason ), () => client . close ()); 245}, 246}, 247); 248if ( writableClosed ) { 249markPromiseHandled ( invoke ( closeStream , writable )); 250client . close (); 251} 252} 253if ( kind === "readable" ) return readable ! ; 254if ( kind === "writable" ) return writable ! ; 255const transform = new Transform (); 256define ( transform , "_readable" , { value :readable }); 257define ( transform , "_writable" , { value :writable }); 258return transform ; 259} 260registerWire < undefined , StreamPacket , StreamRecord >({ 261name :"Stream" , 262accepts :( value ) => 263!! ( 264descriptor ( value , "_readableStreamController" ) || 265descriptor ( value , "_writableStreamController" ) || 266descriptor ( value , "_transformStreamController" ) 267), 268encode :( 269_state , 270_source , 271record , 272) => [ 273record . kind ! , 274record . readPair ?.[ 1 ] ?? null , 275record . writePair ?.[ 1 ] ?? null , 276record . writableState === "closed" , 277], 278decode :decodeWireStream , 279prepare :prepareWireStream , 280validate :( _state , _source , record ) => validateRecord ( record ), 281commit :commitWireStream , 282rollback :( _state , _source , record ) => { 283const pairs = [ record . readPair , record . writePair ]; 284for ( let i = 0 ; i < pairs . length ; i ++ ) { 285const pair = pairs [ i ]; 286if ( pair ) { 287op_port_close ( pair [ 0 ]); 288op_port_close ( pair [ 1 ]); 289} 290} 291}, 292});