Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implementing Startable and propagating stop() #309

Merged
merged 2 commits into from
Jan 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/domain/buildingBlocks/Pluto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,13 @@ export namespace Pluto {
* preferred underlying storage technology, most appropriate for your use case.
*/
export interface Pluto {
// TODO apply breaking change below
// export interface Pluto extends Startable.IController {
/**
* Pluto initialise function
*/
start(): Promise<void>;
stop?(): Promise<void>;

/**
* create a Backup object from the stored data
Expand Down
1 change: 1 addition & 0 deletions src/domain/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * as Backup from "./backup";
export * as Protocols from "./protocols";
export * from "./models";
export * from "./protocols";
export * from "./buildingBlocks/Apollo";
Expand Down
82 changes: 82 additions & 0 deletions src/domain/protocols/Startable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/**
* Define controls for managing entity lifecycle.
*/
export namespace Startable {
/**
* states for a Startable entity
*/
export enum State {
STOPPED = "stopped",
STARTING = "starting",
RUNNING = "running",
STOPPING = "stopping",
}

/**
* define the structure of a Startable entity
*/
export interface IController {
/**
* current status of the entity
*/
state: State;
/**
* handle the startup of an entity
*
* updates `state` according to lifecycle
*
* @returns {Promise<State>}
*/
start(): Promise<State>;
/**
* handle the teardown of an entity
*
* updates `state` according to lifecycle
*
* @returns {Promise<State>}
*/
stop(): Promise<State>;
}

export abstract class Controller implements IController {
public state = State.STOPPED;

/**
* internal method to define specific startup routine
*
* used by `start()` internally
*
* implement with `protected` to keep hidden from class interface
*/
protected abstract _start(): Promise<void>;

/**
* internal method to define teardown routine
*
* used by `stop()` internally
*
* implement with `protected` to keep hidden from class interface
*/
protected abstract _stop(): Promise<void>;

async start(): Promise<State> {
if (this.state === Startable.State.STOPPED) {
this.state = Startable.State.STARTING;
await this._start();
this.state = Startable.State.RUNNING;
}

return this.state;
}

async stop(): Promise<State> {
if (this.state === Startable.State.RUNNING) {
this.state = Startable.State.STOPPING;
await this._stop();
this.state = Startable.State.STOPPED;
}

return this.state;
}
}
}
1 change: 1 addition & 0 deletions src/domain/protocols/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from "./KeyRestoration";
export * from "./Startable";
51 changes: 12 additions & 39 deletions src/edge-agent/Agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,13 @@ import * as Domain from "../domain";
import Apollo from "../apollo";
import Castor from "../castor";
import Pollux from "../pollux";
import { Startable } from "../domain/protocols/Startable";
import { AgentBackup } from "./Agent.Backup";
import { SignWithDID } from "./didFunctions/Sign";
import { CreatePrismDID } from "./didFunctions/CreatePrismDID";
import { FetchApi } from "./helpers/FetchApi";
import { Task } from "../utils/tasks";

enum AgentState {
STOPPED = "stopped",
STARTING = "starting",
RUNNING = "running",
STOPPING = "stopping",
}
import { notNil } from "../utils";

/**
* Edge agent implementation
Expand All @@ -22,14 +17,7 @@ enum AgentState {
* @class Agent
* @typedef {Agent}
*/
export default class Agent {
/**
* Agent state
*
* @public
* @type {AgentState}
*/
public state: AgentState = AgentState.STOPPED;
export default class Agent extends Startable.Controller {
public backup: AgentBackup;
public readonly pollux: Pollux;

Expand All @@ -50,6 +38,7 @@ export default class Agent {
public readonly seed: Domain.Seed = apollo.createRandomSeed().seed,
public readonly api: Domain.Api = new FetchApi(),
) {
super();
this.pollux = new Pollux(apollo, castor);
this.backup = new AgentBackup(this);
}
Expand Down Expand Up @@ -83,33 +72,17 @@ export default class Agent {
return agent;
}

/**
* Asyncronously start the agent
*
* @async
* @returns {Promise<AgentState>}
*/
async start(): Promise<AgentState> {
if (this.state === AgentState.STOPPED) {
this.state = AgentState.STARTING;
await this.pluto.start();
await this.pollux.start();
}

return this.state;
protected async _start() {
await this.pluto.start();
await this.pollux.start();
}

/**
* Asyncronously stop the agent and any side task that is running
*
* @async
* @returns {Promise<void>}
*/
async stop(): Promise<void> {
if (this.state !== AgentState.RUNNING) {
return;
protected async _stop() {
await this.pollux.stop();

if (notNil(this.pluto.stop)) {
await this.pluto.stop();
}
this.state = AgentState.STOPPED;
}

/**
Expand Down
68 changes: 19 additions & 49 deletions src/edge-agent/didcomm/Agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,8 @@
import { ParsePrismInvitation } from "./ParsePrismInvitation";
import { ParseInvitation } from "./ParseInvitation";
import { HandleOOBInvitation } from "./HandleOOBInvitation";

enum AgentState {
STOPPED = "stopped",
STARTING = "starting",
RUNNING = "running",
STOPPING = "stopping",
}
import { Startable } from "../../domain/protocols/Startable";
import { notNil } from "../../utils";

/**
* Edge agent implementation
Expand All @@ -52,14 +47,7 @@
* @class Agent
* @typedef {Agent}
*/
export default class DIDCommAgent {
/**
* Agent state
*
* @public
* @type {AgentState}
*/
public state: AgentState = AgentState.STOPPED;
export default class DIDCommAgent extends Startable.Controller {
public backup: AgentBackup;
public readonly pollux: Pollux;

Expand All @@ -80,8 +68,9 @@
public readonly connectionManager: ConnectionsManager,
public readonly seed: Domain.Seed = apollo.createRandomSeed().seed,
public readonly api: Domain.Api = new FetchApi(),
options?: AgentOptions

Check warning on line 71 in src/edge-agent/didcomm/Agent.ts

View workflow job for this annotation

GitHub Actions / Build and test

'options' is defined but never used. Allowed unused args must match /^_/u
) {
super();
this.pollux = new Pollux(apollo, castor);
this.backup = new AgentBackup(this);
}
Expand Down Expand Up @@ -148,36 +137,26 @@
return agent;
}


/**
* Asyncronously start the agent
*
* @async
* @returns {Promise<AgentState>}
*/
async start(): Promise<AgentState> {
if (this.state !== AgentState.STOPPED) {
return this.state;
}

protected async _start() {
try {
this.state = AgentState.STARTING;
await this.pluto.start();
await this.pollux.start();
await this.connectionManager.startMediator();
} catch (e) {
}
catch (e) {
if (e instanceof Domain.AgentError.NoMediatorAvailableError) {
const hostDID = await this.createNewPeerDID([], false);

await this.connectionManager.registerMediator(hostDID);

} else throw e;
}
else {
throw e;
}
}

if (this.connectionManager.mediationHandler.mediator !== undefined) {
await this.connectionManager.startFetchingMessages(5);
this.state = AgentState.RUNNING;
} else {
}
else {
throw new Domain.AgentError.MediationRequestFailedError("Mediation failed");
}

Expand All @@ -187,25 +166,16 @@
const linkSecret = new Domain.LinkSecret(secret);
await this.pluto.storeLinkSecret(linkSecret);
}

return this.state;
}

/**
* Asyncronously stop the agent and any side task that is running
*
* @async
* @returns {Promise<void>}
*/
async stop(): Promise<void> {
if (this.state !== AgentState.RUNNING) {
return;
}
this.state = AgentState.STOPPING;
protected async _stop() {
await this.connectionManager.stopAllEvents();
await this.connectionManager.stopFetchingMessages();
// await this.agent.stop();
this.state = AgentState.STOPPED;
await this.pollux.stop();

if (notNil(this.pluto.stop)) {
await this.pluto.stop();
}
}

/**
Expand Down
36 changes: 14 additions & 22 deletions src/edge-agent/oidc/Agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ import { AuthorizationRequest } from "./protocols/AuthorizationRequest";
import { TokenResponse } from "./protocols/TokenResponse";
import { TokenRequest } from "./protocols/TokenRequest";
import { CredentialRequest } from "./protocols/CredentialRequest";
import { Startable } from "../../domain/protocols/Startable";
import { FetchApi } from "../helpers/FetchApi";
import { Task } from "../../utils/tasks";
import * as DIDfns from "../didFunctions";
import * as Tasks from "./tasks";
import * as Errors from "./errors";
import { JsonObj, expect } from "../../utils";
import { JsonObj, expect, notNil } from "../../utils";

/**
* https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html
Expand All @@ -24,20 +25,11 @@ class Connection {
public readonly issuerMeta: OIDC.IssuerMetadata,
public readonly scopes: string[],
public readonly tokenResponse: TokenResponse,
) { }
) {}
}

// TODO make startable interface
enum AgentState {
STOPPED = "stopped",
STARTING = "starting",
RUNNING = "running",
STOPPING = "stopping",
}

export class OIDCAgent {
export class OIDCAgent extends Startable.Controller {
private connections: Connection[] = [];
public state = AgentState.STOPPED;
public readonly pollux: Pollux;

constructor(
Expand All @@ -47,6 +39,7 @@ export class OIDCAgent {
public readonly seed?: Domain.Seed,
public readonly api?: Domain.Api,
) {
super();
this.pollux = new Pollux(apollo, castor);
this.seed = seed ?? apollo.createRandomSeed().seed;
this.api = api ?? new FetchApi();
Expand Down Expand Up @@ -81,18 +74,17 @@ export class OIDCAgent {
return agent;
}

async start() {
if (this.state === AgentState.STOPPED) {
this.state = AgentState.STARTING;
await this.pluto.start();
await this.pollux.start();
this.state = AgentState.RUNNING;
}
return this.state;
protected async _start() {
await this.pluto.start();
await this.pollux.start();
}

async stop(): Promise<void> {
this.state = AgentState.STOPPED
protected async _stop() {
await this.pollux.stop();

if (notNil(this.pluto.stop)) {
await this.pluto.stop();
}
}

private runTask<T>(task: Task<T>): Promise<T> {
Expand Down
Loading
Loading