Skip to content

Commit

Permalink
feat: Add rest client mode to xstate-machine-persistence, allowing to…
Browse files Browse the repository at this point in the history
… process local events but delegate the execution to a REST server
  • Loading branch information
nklomp committed Mar 8, 2024
1 parent 782e8d9 commit 02c5e12
Show file tree
Hide file tree
Showing 5 changed files with 29 additions and 16 deletions.
2 changes: 2 additions & 0 deletions packages/xstate-persistence/agent.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ constants:
# please use your own X25519 key, this is only an example
secretKey: 29739248cad1bd1a0fc4d9b75cd4d2990de535baf5caadfdf8d8f86664aa830c
methods:
- emit
- machineStateInit
- machineStateGet
- machineStatePersist
- machineStatesFindActive
- machineStatesDeleteExpired
Expand Down
2 changes: 0 additions & 2 deletions packages/xstate-persistence/src/__tests__/localAgent.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { DataSource } from 'typeorm'
import { createObjects, getConfig } from '@sphereon/ssi-sdk.agent-config'

jest.setTimeout(30000)

import machineStatePersistenceAgentLogic from './shared/MachineStatePersistenceAgentLogic'

let dbConnection: Promise<DataSource>
Expand Down
8 changes: 5 additions & 3 deletions packages/xstate-persistence/src/__tests__/restAgent.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,9 @@ import express, { Router } from 'express'
import { Server } from 'http'
import { DataSource } from 'typeorm'
import { createObjects, getConfig } from '@sphereon/ssi-sdk.agent-config'
import { IMachineStatePersistence } from '../index'
import { IMachineStatePersistence, MachineStatePersistence, MachineStatePersistEventType } from '../index'
import xStatePersistenceAgentLogic from './shared/MachineStatePersistenceAgentLogic'

jest.setTimeout(60000)

const port = 3003
const basePath = '/agent'

Expand All @@ -23,6 +21,10 @@ const getAgent = (options?: IAgentOptions) =>
createAgent<IMachineStatePersistence>({
...options,
plugins: [
new MachineStatePersistence({
eventTypes: [MachineStatePersistEventType.EVERY],
isRESTClient: true,
}),
new AgentRestClient({
url: 'http://localhost:' + port + basePath,
enabledMethods: serverAgent.availableMethods(),
Expand Down
31 changes: 21 additions & 10 deletions packages/xstate-persistence/src/agent/MachineStatePersistence.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { IAbstractMachineStateStore, StoreMachineStateInfo } from '@sphereon/ssi-sdk.data-store'
import { IAgentPlugin } from '@veramo/core'
import * as console from 'console'
import Debug from 'debug'
import { v4 as uuidv4 } from 'uuid'
import { deserializeMachineState, machineStateToStoreInfo } from '../functions'

import {
DeleteExpiredStatesArgs,
DeleteStateResult,
FindActiveStatesArgs,
IMachineStatePersistence,
InitMachineStateArgs,
MachineStateDeleteArgs,
MachineStateGetArgs,
Expand All @@ -19,7 +22,6 @@ import {
RequiredContext,
schema,
} from '../index'
import { FindActiveStatesArgs, IMachineStatePersistence } from '../types'

const debug = Debug('sphereon:ssi-sdk:machine-state:xstate-persistence')

Expand All @@ -32,19 +34,20 @@ const debug = Debug('sphereon:ssi-sdk:machine-state:xstate-persistence')
*/
export class MachineStatePersistence implements IAgentPlugin {
readonly schema = schema.IMachineStatePersistence
readonly methods: IMachineStatePersistence
readonly methods: IMachineStatePersistence | {}
readonly eventTypes: Array<string>
readonly store: IAbstractMachineStateStore
private readonly _store?: IAbstractMachineStateStore

constructor(opts: MachineStatePersistOpts) {
const { store, eventTypes } = opts

this.store = store
this.eventTypes = eventTypes

if (!this.store) {
get store(): IAbstractMachineStateStore {
if (!this._store) {
throw Error('No store available in options')
}
return this._store
}

constructor(opts: MachineStatePersistOpts) {
const { store, eventTypes, isRESTClient } = opts
this.eventTypes = eventTypes
this.methods = {
machineStatesFindActive: this.machineStatesFindActive.bind(this),
machineStatesDeleteExpired: this.machineStatesDeleteExpired.bind(this),
Expand All @@ -53,6 +56,14 @@ export class MachineStatePersistence implements IAgentPlugin {
machineStateGet: this.machineStateGet.bind(this),
machineStateDelete: this.machineStateDelete.bind(this),
}
this._store = store
if (isRESTClient) {
// Methods are delegated to the REMOTE Agent. We need the above eventTypes however, to ensure the local eventBus works
// We do set the store, because we might have some local and some remote methods
return
} else if (!store) {
throw Error('No store available in options')
}
}

public async onEvent(event: MachineStatePersistEvent, context: RequiredContext): Promise<void> {
Expand Down
2 changes: 1 addition & 1 deletion packages/xstate-persistence/src/types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { IMachineStatePersistence } from './IMachineStatePersistence'
* @property {IAbstractMachineStateStore} store - The store used to persist the machine state.
* @property {Array<string>} eventTypes - The types of events to be persisted.
*/
export type MachineStatePersistOpts = { store: IAbstractMachineStateStore; eventTypes: Array<string> }
export type MachineStatePersistOpts = { store?: IAbstractMachineStateStore; eventTypes: Array<string>; isRESTClient?: boolean }

/**
* Enum representing the types of machine state persist events.
Expand Down

0 comments on commit 02c5e12

Please sign in to comment.