module import { Map , List } from "immutable" ; import _ from "lodash" ; import { Disposable } from "rx" ; import Server from "./server" ; import { State } from "./internals/Store" ; export interface NodeState { parent ? : number ; previous ? : number ; next ? : number ; isGroup : boolean ; head ? : number ; tail ? : number ; synthDef ? : string ; } enum Key { NODE_WATCHER = "NODE_WATCHER" , NODES = "NODES" , CALLBACKS = "CALLBACKS" , ON_NODE_GO = "ON_NODE_GO" , ON_NODE_END = "ON_NODE_END" } param { Server } server returns { Rx . Disposable } export function watchNodeNotifications ( server ) { const re = /^\/n_(go|end|on|off|move|info)$/ ; const stream = server . receive . filter ( msg => ! ! msg [ 0 ] . match ( re ) ) ; const dispose = stream . subscribe ( msg => { const cmd = msg [ 0 ] ; const r = _responders [ cmd ] ; if ( r ) { r ( server , msg . slice ( 1 ) ) ; } } ) ; return dispose ; } param { Server } server param { String } id param { int } nodeID param { Function } handler returns { Function } export function onNodeGo ( server , id , nodeID , handler ) { return _registerHandler ( Key . ON_NODE_GO , server , id , nodeID , handler ) ; } param { Server } server param { String } id param { int } nodeID returns { Promise } export function whenNodeGo ( server , id , nodeID ) { return new Promise ( resolve => { onNodeGo ( server , id , nodeID , ( ) => resolve ( nodeID ) ) ; } ) ; } param { Server } server param { String } id param { int } nodeID param { Function } handler returns { Function } export function onNodeEnd ( server , id , nodeID , handler ) { return _registerHandler ( Key . ON_NODE_END , server , id , nodeID , handler ) ; } export param { Server } server param { string } id param { number } nodeID returns { Promise < number > } export function whenNodeEnd ( server , id , nodeID ) { return new Promise ( resolve => { onNodeEnd ( server , id , nodeID , ( ) => resolve ( nodeID ) ) ; } ) ; } private export function updateNodeState ( server , nodeID , nodeState ) { server . state . mutate ( Key . NODE_WATCHER , ( state ) => { return state . mergeIn ( [ Key . NODES , String ( nodeID ) ] , Map ( ) , nodeState ) ; } ) ; } private function _registerHandler ( type , server , id , nodeID , handler ) { const dispose = ( ) : void => { _disposeHandler ( type , server , id , nodeID ) ; } ; server . state . mutate ( Key . NODE_WATCHER , state => { const handlerId = id + ":" + nodeID ; return state . mergeDeep ( { [ Key . CALLBACKS ] : { [ handlerId ] : ( ... args ) => { if ( type === Key . ON_NODE_GO || type === Key . ON_NODE_END ) { dispose ( ) ; } handler ( ... args ) ; } , } , } ) . updateIn ( [ type , String ( nodeID ) ] , List ( ) , list => list . push ( handlerId ) ) ; } ) ; return dispose ; } private function _disposeHandler ( type , server , id , nodeID ) { server . state . mutate ( Key . NODE_WATCHER , state => { const handlerId = id + ":" + nodeID ; return state . deleteIn ( [ Key . CALLBACKS , handlerId ] ) . updateIn ( [ type , String ( nodeID ) ] , List ( ) , list => list . filter ( hid => hid !== handlerId ) ) ; } ) ; } private function _handlersFor ( server , type , nodeID ) { return server . state . getIn ( [ Key . NODE_WATCHER , type , String ( nodeID ) ] , List ( ) ) . map ( handlerId => { return server . state . getIn ( [ Key . NODE_WATCHER , Key . CALLBACKS , handlerId ] , null ) ; } ) ; } private function _saveNodeState ( server , set , msg ) { const nodeID = msg [ 0 ] ; const isGroup = msg [ 4 ] > 0 ; let nodeState = { parent : msg [ 1 ] , previous : msg [ 2 ] , next : msg [ 3 ] , isGroup : isGroup , head : isGroup ? msg [ 5 ] : null , tail : isGroup ? msg [ 6 ] : null , } ; nodeState = _ . assign ( nodeState , set ) ; updateNodeState ( server , nodeID , nodeState ) ; } private function _callNodeHandlers ( server , eventType , nodeID ) { _handlersFor ( server , eventType , nodeID ) . forEach ( h => h ( nodeID ) ) ; } private const _responders = { "/n_go" : ( server , args ) => { _saveNodeState ( server , { isPlaying : true , isRunning : true , } , args ) ; _callNodeHandlers ( server , Key . ON_NODE_GO , args [ 0 ] ) ; } , "/n_end" : ( server , args ) => { const nodeID = args [ 0 ] ; server . state . mutate ( Key . NODE_WATCHER , state => { return state . deleteIn ( [ Key . NODES , String ( nodeID ) ] ) ; } ) ; _callNodeHandlers ( server , Key . ON_NODE_END , nodeID ) ; } , "/n_on" : ( server , args ) => { _saveNodeState ( server , { isRunning : true , } , args ) ; } , "/n_off" : ( server , args ) => { _saveNodeState ( server , { isRunning : false , } , args ) ; } , "/n_info" : ( server , args ) => { _saveNodeState ( server , { } , args ) ; } , "/n_move" : ( server , args ) => { _saveNodeState ( server , { } , args ) ; } , } ;