import { Logger } from 'pino' ; import { unreachable } from '@statechannels/wallet-core' ; import { Transaction } from 'knex' ; import { Bytes32 } from '../type-aliases' ; import { ChannelOpener , WaitingFor as ChannelOpenerWaitingFor } from '../protocols/channel-opener' ; import { ChannelCloser , WaitingFor as ChannelCloserWaitingFor } from '../protocols/channel-closer' ; import { Store } from '../engine/store' ; import { EngineResponse } from '../engine/engine-response' ; import { ChallengeSubmitter , WaitingFor as ChallengeSubmitterWaitingFor , } from '../protocols/challenge-submitter' ; import { ChannelDefunder , WaitingFor as DefundChannelWaitingFor } from '../protocols/defund-channel' ; import { WalletObjective , ObjectiveModel } from '../models/objective' ; import { ObjectiveManagerParams } from './types' ; import { CloseChannelObjective } from './close-channel' ; export enum Nothing { ToWaitFor = '' } export type WaitingFor = 'approval' | ChannelOpenerWaitingFor | ChannelCloserWaitingFor | ChallengeSubmitterWaitingFor | DefundChannelWaitingFor | Nothing ; export interface Cranker < O extends WalletObjective > { crank : ( objective : O , response : EngineResponse , tx : Transaction ) => Promise < WaitingFor | Nothing > ; } export class ObjectiveManager { private store : Store ; private logger : Logger ; private timingMetrics : boolean ; static create ( params ) { return new this ( params ) ; } private constructor ( { store , logger , timingMetrics } ) { this . store = store ; this . logger = logger ; this . timingMetrics = timingMetrics ; } param objectiveId param response async crank ( objectiveId , response ) { return this . store . transaction ( async ( tx ) => { const objective = await this . store . getAndLockObjective ( objectiveId , tx ) ; let waitingFor ; switch ( objective . type ) { case 'OpenChannel' : waitingFor = await this . channelOpener . crank ( objective , response , tx ) ; break ; case 'CloseChannel' : waitingFor = await this . channelCloser . crank ( objective , response , tx ) ; break ; case 'SubmitChallenge' : waitingFor = await this . challengeSubmitter . crank ( objective , response , tx ) ; break ; case 'DefundChannel' : waitingFor = await this . channelDefunder . crank ( objective , response , tx ) ; break ; default : unreachable ( objective ) ; } if ( objective . waitingFor != waitingFor ) { await ObjectiveModel . updateWaitingFor ( objectiveId , waitingFor , tx ) ; } } ) ; } private get channelDefunder ( ) : ChannelDefunder { return ChannelDefunder . create ( this . store , this . logger , this . timingMetrics ) ; } private get challengeSubmitter ( ) : ChallengeSubmitter { return ChallengeSubmitter . create ( this . store , this . logger , this . timingMetrics ) ; } private get channelOpener ( ) : ChannelOpener { return ChannelOpener . create ( this . store , this . logger , this . timingMetrics ) ; } private get channelCloser ( ) : ChannelCloser { return ChannelCloser . create ( this . store , this . logger , this . timingMetrics ) ; } public async commenceCloseChannel ( channelId , response ) { return CloseChannelObjective . commence ( channelId , response , this . store ) ; } }