import RAL from '../common/ral' ; import { Disposable } from '../common/disposable' ; import { Message } from '../common/messages' ; import { Emitter } from '../common/events' ; import { ContentTypeEncoderOptions , ContentTypeDecoderOptions } from '../common/encoding' ; import { AbstractMessageBuffer } from '../common/messageBuffer' ; class MessageBuffer extends AbstractMessageBuffer { private static readonly emptyBuffer : Uint8Array = new Uint8Array ( 0 ) ; private asciiDecoder : TextDecoder ; constructor ( encoding = 'utf-8' ) { super ( encoding ) ; this . asciiDecoder = new TextDecoder ( 'ascii' ) ; } protected emptyBuffer ( ) { return MessageBuffer . emptyBuffer ; } protected fromString ( value , _encoding ) { return ( new TextEncoder ( ) ) . encode ( value ) ; } protected toString ( value , encoding ) { if ( encoding === 'ascii' ) { return this . asciiDecoder . decode ( value ) ; } else { return ( new TextDecoder ( encoding ) ) . decode ( value ) ; } } protected asNative ( buffer , length ? ) { if ( length === undefined ) { return buffer ; } else { return buffer . slice ( 0 , length ) ; } } protected allocNative ( length ) { return new Uint8Array ( length ) ; } } class ReadableStreamWrapper implements RAL . ReadableStream { private _onData : Emitter < Uint8Array > ; private _messageListener : ( event : MessageEvent ) => void ; constructor ( private socket ) { this . _onData = new Emitter < Uint8Array > ( ) ; this . _messageListener = ( event ) => { const blob = event . data as Blob ; blob . arrayBuffer ( ) . then ( ( buffer ) => { this . _onData . fire ( new Uint8Array ( buffer ) ) ; } , ( ) => { RAL ( ) . console . error ( `Converting blob to array buffer failed.` ) ; } ) ; } ; this . socket . addEventListener ( 'message' , this . _messageListener ) ; } public onClose ( listener ) { this . socket . addEventListener ( 'close' , listener ) ; return Disposable . create ( ( ) => this . socket . removeEventListener ( 'close' , listener ) ) ; } public onError ( listener ) { this . socket . addEventListener ( 'error' , listener ) ; return Disposable . create ( ( ) => this . socket . removeEventListener ( 'error' , listener ) ) ; } public onEnd ( listener ) { this . socket . addEventListener ( 'end' , listener ) ; return Disposable . create ( ( ) => this . socket . removeEventListener ( 'end' , listener ) ) ; } public onData ( listener ) { return this . _onData . event ( listener ) ; } } class WritableStreamWrapper implements RAL . WritableStream { constructor ( private socket ) { } public onClose ( listener ) { this . socket . addEventListener ( 'close' , listener ) ; return Disposable . create ( ( ) => this . socket . removeEventListener ( 'close' , listener ) ) ; } public onError ( listener ) { this . socket . addEventListener ( 'error' , listener ) ; return Disposable . create ( ( ) => this . socket . removeEventListener ( 'error' , listener ) ) ; } public onEnd ( listener ) { this . socket . addEventListener ( 'end' , listener ) ; return Disposable . create ( ( ) => this . socket . removeEventListener ( 'end' , listener ) ) ; } public write ( data , encoding ? ) { if ( typeof data === 'string' ) { if ( encoding !== undefined && encoding !== 'utf-8' ) { throw new Error ( `In a Browser environments only utf-8 text encoding is supported. But got encoding: ${ encoding }` ) ; } this . socket . send ( data ) ; } else { this . socket . send ( data ) ; } return Promise . resolve ( ) ; } public end ( ) { this . socket . close ( ) ; } } interface RIL extends RAL { readonly stream : { readonly asReadableStream : ( stream : WebSocket ) => RAL . ReadableStream ; readonly asWritableStream : ( stream : WebSocket ) => RAL . WritableStream ; } ; } const _textEncoder = new TextEncoder ( ) ; const _ril = Object . freeze < RIL > ( { messageBuffer : Object . freeze ( { create : ( encoding ) => new MessageBuffer ( encoding ) } ) , applicationJson : Object . freeze ( { encoder : Object . freeze ( { name : 'application/json' , encode : ( msg , options ) : Promise < Uint8Array > => { if ( options . charset !== 'utf-8' ) { throw new Error ( `In a Browser environments only utf-8 text encoding is supported. But got encoding: ${ options . charset }` ) ; } return Promise . resolve ( _textEncoder . encode ( JSON . stringify ( msg , undefined , 0 ) ) ) ; } } ) , decoder : Object . freeze ( { name : 'application/json' , decode : ( buffer , options ) : Promise < Message > => { if ( ! ( buffer instanceof Uint8Array ) ) { throw new Error ( `In a Browser environments only Uint8Arrays are supported.` ) ; } return Promise . resolve ( JSON . parse ( new TextDecoder ( options . charset ) . decode ( buffer ) ) ) ; } } ) } ) , stream : Object . freeze ( { asReadableStream : ( socket ) => new ReadableStreamWrapper ( socket ) , asWritableStream : ( socket ) => new WritableStreamWrapper ( socket ) } ) , console : console , timer : Object . freeze ( { setTimeout ( callback , ms , ... args ) { const handle = setTimeout ( callback , ms , ... args ) ; return { dispose : ( ) => clearTimeout ( handle ) } ; } , setImmediate ( callback , ... args ) { const handle = setTimeout ( callback , 0 , ... args ) ; return { dispose : ( ) => clearTimeout ( handle ) } ; } , setInterval ( callback , ms , ... args ) { const handle = setInterval ( callback , ms , ... args ) ; return { dispose : ( ) => clearInterval ( handle ) } ; } , } ) } ) ; function RIL ( ) { return _ril ; } namespace RIL { export function install ( ) { RAL . install ( _ril ) ; } } export default RIL ;