/* eslint-disable @typescript-eslint/no-namespace */ import { createMachineRunner } from '@actyx/machine-runner' import { SwarmProtocol } from '@actyx/machine-runner' import { MachineEvent } from '@actyx/machine-runner' import { Actyx, Tags } from '@actyx/sdk' const pickUp = MachineEvent.design('pickUp').withPayload<{ id: string chassisId: string fromPos: string }>() const deliver = MachineEvent.design('deliver').withPayload<{ toPos: string }>() const reserved = MachineEvent.design('reserved').withPayload<{ robot: string; score: number }>() const confirmed = MachineEvent.design('confirmed').withPayload<{ winner: string }>() const atSource = MachineEvent.design('atSource').withoutPayload() const placed = MachineEvent.design('placed').withoutPayload() const atDestination = MachineEvent.design('atDestination').withoutPayload() const taken = MachineEvent.design('taken').withoutPayload() const transportOrderEvents = [ pickUp, deliver, reserved, confirmed, atSource, placed, atDestination, taken, ] as const const transportOrder = SwarmProtocol.make('transportOrder', transportOrderEvents) const TOForRobot = transportOrder.makeMachine('robot') namespace ForRobot { type Order = { id: string; chassisId: string; fromPos: string; toPos: string; robot: string } type OrderScores = Order & { scores: { robot: string; score: number }[] } export const Initial = TOForRobot.designState('Initial').withPayload<{ robot: string }>().finish() export const Open = TOForRobot.designState('Open') .withPayload() .command('reserve', [reserved], (ctx, score: number) => [{ robot: ctx.self.robot, score }]) .command('confirm', [confirmed], (_ctx, winner: string) => [{ winner }]) .finish() export const Assigned = TOForRobot.designState('Assigned') .withPayload() .command('arrive', [atSource], (_ctx) => [{}]) .finish() export const Transporting = TOForRobot.designState('Transporting') .withPayload() .command('arrive', [atDestination], (_ctx) => [{}]) .finish() export const Done = TOForRobot.designEmpty('Done').finish() Initial.react([pickUp, deliver], Open, (ctx, p, d) => ({ ...ctx.self, ...p.payload, ...d.payload, scores: [], })) Open.react([reserved], Open, (ctx, r) => { ctx.self.scores.push(r.payload) return ctx.self }) Open.react([confirmed], Assigned, (ctx, c) => { const { scores, ...rest } = ctx.self return { ...rest, winner: c.payload.winner } }) Assigned.react([atSource, placed], Transporting, (ctx, _a, _p) => ctx.self) Transporting.react([atDestination, taken], Done, (ctx, _a, _t) => ({})) } const actyx = await Actyx.of({ appId: 'com.example.jonthebeach', displayName: 'J on the Beach', version: '0.0.1', }) const tags = transportOrder.tagWithEntityId('4711') const machine = createMachineRunner(actyx, tags, ForRobot.Initial, { robot: 'agv1' }) let IamWinner = false for await (const state of machine) { if (state.is(ForRobot.Open)) { const open = state.cast() open.payload.scores.find((s) => s.robot === open.payload.robot) || open.commands?.reserve(1) } else if (state.is(ForRobot.Assigned)) { const assigned = state.cast() IamWinner = assigned.payload.winner === assigned.payload.robot if (!IamWinner) break // TODO: add the actual robot control part here for driving to the source assigned.commands?.arrive() } else if (state.is(ForRobot.Transporting)) { if (!IamWinner) break const transporting = state.cast() // TODO: add the actual robot control part here for driving to the destination transporting.commands?.arrive() } else if (state.is(ForRobot.Done)) { break // this will clean up the Actyx subscription as well } }