import { Props } from "./props" ; import * as messages from "./messages" ; import processRegistry from "./processRegistry" ; import { IStrategy , ISupervisor , DefaultStrategy } from "./supervision" ; import { RestartStatistics } from "./restartStatistics" ; import { PID } from "./pid" ; import { IActor , done } from "./actor" ; import { IMessageInvoker } from "./invoker" ; export interface IContext extends IMessageInvoker , ISupervisor { Children : PID [ ] ; Message : any ; Parent ? : PID ; Self : PID ; Sender : PID ; Tell ( target , message ) : void ; Request ( target , message ) : void ; RequestPromise ( target , message ) : Promise < void > ; Respond ( message ) : void ; Spawn ( props ) : PID ; SpawnPrefix ( props , prefix ) : PID ; SpawnNamed ( props , name ) : PID ; } export class LocalContext implements IContext { private restartStatistics : RestartStatistics ; private restarting : boolean ; private stopping : boolean ; private Actor : IActor ; private _behavior : Function [ ] = [ ] ; private _receive : Function ; public Children : PID [ ] = [ ] ; public Self : PID ; public Message : any ; public Sender : PID ; constructor ( private producer , private supervisorStrategy , public Parent ? ) { this . _incarnateActor ( ) ; } InvokeSystemMessage ( message ) { if ( message instanceof messages . Started ) { return this . InvokeUserMessage ( message ) ; } if ( message instanceof messages . Stop ) { return this . _handleStop ( ) ; } if ( message instanceof messages . Terminated ) { return this . _handleTerminated ( message ) ; } if ( message instanceof messages . Failure ) { this . _handleFailure ( message ) ; } if ( message instanceof messages . Restart ) { return this . _handleRestart ( ) ; } return done ; } InvokeUserMessage ( message ) { return this . _processMessage ( message ) ; } Tell ( target , message ) { target . Tell ( message ) ; } Request ( target , message ) { target . Request ( message , this . Self ) ; } RequestPromise ( target , message , timeoutMs ? ) { return target . RequestPromise ( message , timeoutMs ) ; } Respond ( message ) { return this . Sender . Tell ( message ) ; } EscalateFailure ( exception , who ) { if ( ! who ) { who = this . Self ; } if ( this . restartStatistics == undefined ) { this . restartStatistics = new RestartStatistics ( ) ; } if ( ! this . Parent ) { DefaultStrategy . HandleFailure ( this , who , this . restartStatistics , exception ) ; } else { var failure = new messages . Failure ( who , exception , this . restartStatistics ) ; this . Self . SendSystemMessage ( messages . SuspendMailbox . Instance ) ; this . Parent . SendSystemMessage ( failure ) ; } } RestartChildren ( ... pids ) { for ( var i = 0 ; i < pids . length ; i ++ ) { pids [ i ] . SendSystemMessage ( messages . Restart . Instance ) ; } } StopChildren ( ... pids ) { for ( var i = 0 ; i < pids . length ; i ++ ) { pids [ i ] . SendSystemMessage ( messages . Stop . Instance ) ; } } ResumeChildren ( ... pids ) { for ( var i = 0 ; i < pids . length ; i ++ ) { pids [ i ] . SendSystemMessage ( messages . ResumeMailbox . Instance ) ; } } Spawn ( props ) { var name = processRegistry . NextId ( ) ; return this . SpawnNamed ( props , name ) ; } SpawnPrefix ( props , prefix ) { var name = prefix + processRegistry . NextId ( ) ; return this . SpawnNamed ( props , name ) ; } SpawnNamed ( props , name ) { let pid = props . Spawn ( this . Self . Id + '/' + name , this . Self ) ; this . Children . push ( pid ) ; return pid ; } SetBehavior ( receive ) { this . _behavior = [ ] ; this . PushBehavior ( receive ) ; } PushBehavior ( receive ) { this . _behavior . push ( receive ) ; this . _receive = receive ; } PopBehavior ( receive ? ) { if ( this . _behavior . length <= 1 ) { throw "Cannot pop actor's last behavior" ; } this . _behavior . pop ( ) ; this . _receive = this . _behavior [ this . _behavior . length - 1 ] ; } _incarnateActor ( ) { this . Actor = this . producer ( ) ; this . SetBehavior ( this . Actor . Receive . bind ( this . Actor ) ) ; } async _handleStop ( ) { this . restarting = false ; this . stopping = true ; await this . InvokeUserMessage ( messages . Stopping . Instance ) ; if ( this . Children && this . Children . length > 0 ) { for ( var i = 0 ; i < this . Children . length ; i ++ ) { this . Children [ i ] . Stop ( ) ; } } await this . _tryRestartOrTerminate ( ) ; } async _handleTerminated ( terminated ) { this . Children . splice ( this . Children . indexOf ( terminated . Who ) , 1 ) ; await this . InvokeUserMessage ( terminated ) ; await this . _tryRestartOrTerminate ( ) ; } _handleFailure ( failure ) { this . supervisorStrategy . HandleFailure ( this , failure . Who , failure . RestartStatistics , failure . Reason ) ; } async _handleRestart ( ) { this . stopping = false ; this . restarting = true ; await this . InvokeUserMessage ( messages . Restarting . Instance ) ; if ( this . Children && this . Children . length > 0 ) { for ( var i = 0 ; i < this . Children . length ; i ++ ) { this . Children [ i ] . Stop ( ) ; } } await this . _tryRestartOrTerminate ; } _tryRestartOrTerminate ( ) { if ( this . Children && this . Children . length > 0 ) { return ; } if ( this . restarting ) { return this . _restart ( ) ; } if ( this . stopping ) { return this . _stopped ( ) ; } } _restart ( ) { this . _incarnateActor ( ) ; this . Self . SendSystemMessage ( messages . ResumeMailbox . Instance ) ; return this . InvokeUserMessage ( messages . Started ) ; } _stopped ( ) { processRegistry . Remove ( this . Self ) ; return this . InvokeUserMessage ( messages . Stopped . Instance ) ; } _processMessage ( message ) { if ( message instanceof messages . MessageSender ) { this . Message = message . Message ; this . Sender = message . Sender ; } else { this . Message = message ; } return this . _receive ( this ) ; } }