From 855bec95d58dfc452219f55c5b193ac50c90fa5e Mon Sep 17 00:00:00 2001 From: Alex Potsides Date: Fri, 26 Apr 2024 12:55:26 +0100 Subject: [PATCH] feat: add server.clean method (#830) Like `factory.clean`, `server.clean` shuts down any running Kubo nodes created by the server and removes references to them. --- src/endpoint/routes.ts | 5 +-- src/endpoint/server.ts | 31 ++++++++++++----- src/index.ts | 4 +-- test/create.spec.ts | 66 ++++++++++++++++++++++++++++++++++++ test/endpoint/routes.node.ts | 12 +++---- 5 files changed, 95 insertions(+), 23 deletions(-) diff --git a/src/endpoint/routes.ts b/src/endpoint/routes.ts index 38d80e1f..01f1565a 100644 --- a/src/endpoint/routes.ts +++ b/src/endpoint/routes.ts @@ -26,9 +26,7 @@ const badRequest = (err: Error & { stdout?: string }): void => { throw boom.badRequest(msg) } -const nodes: Record = {} - -export default (server: Server, createFactory: () => Factory | Promise): void => { +export default (server: Server, ipfsd: Factory, nodes: Record): void => { /** * Spawn a controller */ @@ -38,7 +36,6 @@ export default (server: Server, createFactory: () => Factory | Promise) handler: async (request) => { const options: any = request.payload ?? {} try { - const ipfsd = await createFactory() const id = nanoid() nodes[id] = await ipfsd.spawn({ ...options, diff --git a/src/endpoint/server.ts b/src/endpoint/server.ts index 61c52358..56e2539f 100644 --- a/src/endpoint/server.ts +++ b/src/endpoint/server.ts @@ -1,10 +1,6 @@ import Hapi from '@hapi/hapi' import routes from './routes.js' -import type { Factory } from '../index.js' - -interface CreateFactory { - (): Factory -} +import type { Node, Factory } from '../index.js' export interface ServerInit { port?: number @@ -19,14 +15,16 @@ class Server { private server: Hapi.Server | null public port: number public host: string - private readonly createFactory: CreateFactory + private readonly ipfsd: Factory + public readonly nodes: Record - constructor (options: ServerInit = { port: 43134, host: 'localhost' }, createFactory: CreateFactory) { + constructor (options: ServerInit = { port: 43134, host: 'localhost' }, factory: Factory) { this.options = options this.server = null this.port = this.options.port ?? 43134 this.host = this.options.host ?? 'localhost' - this.createFactory = createFactory + this.ipfsd = factory + this.nodes = {} } /** @@ -42,7 +40,7 @@ class Server { } }) - routes(this.server, this.createFactory) + routes(this.server, this.ipfsd, this.nodes) await this.server.start() @@ -56,6 +54,21 @@ class Server { if (this.server != null) { await this.server.stop(options) } + + await this.clean() + } + + /** + * Stop any nodes created by this server + */ + async clean (): Promise { + await this.ipfsd.clean() + + // remove references to nodes + for (const key of Object.getOwnPropertyNames(this.nodes)) { + // eslint-disable-next-line @typescript-eslint/no-dynamic-delete + delete this.nodes[key] + } } } diff --git a/src/index.ts b/src/index.ts index 37e71723..e0ec22b7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -286,7 +286,5 @@ export const createServer = (options?: number | { port: number }, factoryOptions return new Server({ port, host: '127.0.0.1' - }, () => { - return createFactory(factoryOptions, factoryOverrides) - }) + }, createFactory(factoryOptions, factoryOverrides)) } diff --git a/test/create.spec.ts b/test/create.spec.ts index 0428511e..c679744a 100644 --- a/test/create.spec.ts +++ b/test/create.spec.ts @@ -172,4 +172,70 @@ describe('`createServer`', () => { }) await node.stop() }) + + it('should clean server', async () => { + if (!isNode && !isElectronMain) { + return + } + + server = createServer(33333, { + type: 'kubo', + test: true, + disposable: false, + rpc: createKuboRPCClient, + bin: isNode ? kubo.path() : undefined + }) + await server.start() + + const factory = createFactory({ + endpoint: `http://127.0.0.1:${server.port}` + }) + + const node = await factory.spawn({ + type: 'kubo', + remote: true, + rpc: createKuboRPCClient + }) + + await expect(node.api.isOnline()).to.eventually.be.true() + expect(Object.keys(server.nodes)).to.have.lengthOf(1) + + await server.clean() + + await expect(node.api.isOnline()).to.eventually.be.false() + expect(Object.keys(server.nodes)).to.have.lengthOf(0) + }) + + it('should clean server on stop', async () => { + if (!isNode && !isElectronMain) { + return + } + + server = createServer(44444, { + type: 'kubo', + test: true, + disposable: false, + rpc: createKuboRPCClient, + bin: isNode ? kubo.path() : undefined + }) + await server.start() + + const factory = createFactory({ + endpoint: `http://127.0.0.1:${server.port}` + }) + + const node = await factory.spawn({ + type: 'kubo', + remote: true, + rpc: createKuboRPCClient + }) + + await expect(node.api.isOnline()).to.eventually.be.true() + expect(Object.keys(server.nodes)).to.have.lengthOf(1) + + await server.stop() + + await expect(node.api.isOnline()).to.eventually.be.false() + expect(Object.keys(server.nodes)).to.have.lengthOf(0) + }) }) diff --git a/test/endpoint/routes.node.ts b/test/endpoint/routes.node.ts index efd802d7..f73212be 100644 --- a/test/endpoint/routes.node.ts +++ b/test/endpoint/routes.node.ts @@ -17,13 +17,11 @@ describe('routes', function () { before(async () => { server = new Hapi.Server({ port: 43134 }) - routes(server, async () => { - return createFactory({ - type: 'kubo', - rpc: createKuboRPCClient, - bin: isNode ? kubo.path() : undefined - }) - }) + routes(server, createFactory({ + type: 'kubo', + rpc: createKuboRPCClient, + bin: isNode ? kubo.path() : undefined + }), {}) }) after(async () => {