import { Client , ClientEvent , IJsonPatch , MessageListener , Room } from "../internal" ; import * as notepack from "notepack.io" ; interface IChangeHandler { op : string ; filter : any [ ] ; handler : ( patch : IJsonPatch , params : any ) => void ; } export class LocalClient extends Client { public handlers : { [ event ] : any ; } = { } ; public listeners : { [ event ] : MessageListener [ ] ; } = { } ; constructor ( public room , auth = { } ) { super ( { roomId : room . id } ) ; this . auth = auth ; this . status = "connected" ; this . handlers = { _message : { } , _request : { } , _change : [ ] , } ; } public send ( type , data ) { if ( ! this . room . onMessage ) { return ; } this . room . onMessage ( this , type , data ) ; } public on ( event , listner ) { if ( ! this . listeners [ event ] ) { this . listeners [ event ] = [ ] ; } this . listeners [ event ] . push ( listner ) ; } public emit ( event , ... args ) { const onMessage = ( type , data ) : void => { this . handlers . _message [ type ] && this . handlers . _message [ type ] ( data ) ; } ; const onSnapshot = ( snapshot ) => { this . handlers . _snapshot && this . handlers . _snapshot ( snapshot ) ; } ; const onPatch = ( patch ) => { this . handlers . _patch && this . handlers . _patch ( patch ) ; const handlers = this . handlers . _change || [ ] ; const match = handlers . find ( ( handler ) => { if ( handler . op !== "*" && handler . op !== patch . op ) { return false ; } let path = handler . filter . map ( ( item ) => item . type === "param" ? "[a-zA-Z0-9_.]+" : item . name ) . join ( "\/" ) ; path = path . slice ( - 1 ) === "*" ? path . slice ( 0 , - 1 ) : ( path + "$" ) ; return new RegExp ( path ) . test ( patch . path ) ; } ) ; if ( match ) { const pathArr = patch . path . replace ( /^\/+|\/+$/g , "" ) . split ( "/" ) ; const params = { } ; match . filter . forEach ( ( item ) => { if ( item . type === "param" ) { params [ item . name ] = + pathArr [ item . index ] || pathArr [ item . index ] ; } } ) ; match . handler ( patch , params ) ; } } ; const onEncodedPatch = ( buffer ) => { onPatch ( notepack . decode ( buffer ) ) ; } ; switch ( event ) { case ClientEvent . snapshot : return onSnapshot ( ... args ) ; case ClientEvent . message : return onMessage ( ... args ) ; case ClientEvent . patch : return onPatch ( ... args ) ; case ClientEvent . encodedPatch : return onEncodedPatch ( ... args ) ; } } public onPatch ( handler ) { this . handlers . _patch = handler ; } public onSnapshot ( handler ) { this . handlers . _snapshot = handler ; } public onChange ( op , path , handler ) { const filter = path . replace ( /^\/+|\/+$/g , "" ) . split ( "/" ) . map ( ( item , index ) => { if ( item [ 0 ] === ":" ) { return { type : "param" , name : item . slice ( 1 ) , index } ; } else if ( item === "*" ) { return { type : "any" , index } ; } else { return { type : "const" , name : item , index } ; } } ) ; this . handlers . _change . push ( { op , filter , handler } ) ; } public join ( params ) { if ( this . room . locked ) { return ; } const id = Math . random ( ) . toString ( 32 ) . slice ( 3 ) ; this . room . clients . set ( id , this ) ; this . room . updateTrackingParams ( this , params ) ; this . room . updateCache ( ) ; } public terminate ( code ? , reason ? ) { if ( this . room . onLeave ) { this . room . onLeave ( this , true ) ; } this . room . stopTracking ( this ) ; this . room . clients . delete ( this . id ) ; this . room . updateCache ( ) ; } }