diff --git a/src/index.ts b/src/index.ts index a37a8c43..37e71723 100644 --- a/src/index.ts +++ b/src/index.ts @@ -158,7 +158,7 @@ export interface Node } -export interface NodeOptions { +export interface NodeOptions { /** * The type of controller */ @@ -193,13 +193,6 @@ export interface NodeOptions { */ args?: string[] - /** - * How long to wait before force killing a daemon in ms - * - * @default 5000 - */ - forceKillTimeout?: number - /** * Init options */ @@ -209,6 +202,16 @@ export interface NodeOptions { * Start options */ start?: StartOptions + + /** + * Stop options + */ + stop?: StopOptions + + /** + * Clean options + */ + clean?: CleanOptions } export interface NodeOptionsOverrides { diff --git a/src/kubo/client.ts b/src/kubo/client.ts index 548d6586..b91c2faf 100644 --- a/src/kubo/client.ts +++ b/src/kubo/client.ts @@ -1,4 +1,4 @@ -import type { KuboNode, KuboInfo, KuboInitOptions, KuboOptions, KuboStartOptions } from './index.js' +import type { KuboNode, KuboInfo, KuboInitOptions, KuboOptions, KuboStartOptions, KuboStopOptions } from './index.js' import type { PeerInfo } from '@libp2p/interface' import type { KuboRPCClient } from 'kubo-rpc-client' @@ -23,6 +23,7 @@ export default class KuboClient implements KuboNode { private _api?: KuboRPCClient private readonly initArgs?: KuboInitOptions private readonly startArgs?: KuboStartOptions + private readonly stopArgs?: KuboStopOptions constructor (options: KuboClientInit) { if (options.rpc == null) { @@ -43,6 +44,10 @@ export default class KuboClient implements KuboNode { if (options.start != null && typeof options.start !== 'boolean') { this.startArgs = options.start } + + if (options.stop != null) { + this.stopArgs = options.stop + } } get api (): KuboRPCClient { @@ -102,9 +107,16 @@ export default class KuboClient implements KuboNode { this._api = this.options.rpc(info.api) } - async stop (): Promise { + async stop (args?: KuboStopOptions): Promise { const response = await fetch(`${this.endpoint}/stop?${new URLSearchParams({ id: this.id })}`, { - method: 'POST' + method: 'POST', + headers: { + 'content-type': 'application/json' + }, + body: JSON.stringify({ + ...(this.stopArgs ?? {}), + ...(args ?? {}) + }) }) if (!response.ok) { diff --git a/src/kubo/daemon.ts b/src/kubo/daemon.ts index cf3aad69..8b203ed1 100644 --- a/src/kubo/daemon.ts +++ b/src/kubo/daemon.ts @@ -5,7 +5,7 @@ import mergeOptions from 'merge-options' import pDefer from 'p-defer' import waitFor from 'p-wait-for' import { checkForRunningApi, tmpDir, buildStartArgs, repoExists, buildInitArgs } from './utils.js' -import type { KuboNode, KuboInfo, KuboInitOptions, KuboOptions, KuboStartOptions } from './index.js' +import type { KuboNode, KuboInfo, KuboInitOptions, KuboOptions, KuboStartOptions, KuboStopOptions } from './index.js' import type { Logger } from '@libp2p/interface' import type { KuboRPCClient } from 'kubo-rpc-client' @@ -34,6 +34,7 @@ export default class KuboDaemon implements KuboNode { private readonly env: Record private readonly initArgs?: KuboInitOptions private readonly startArgs?: KuboStartOptions + private readonly stopArgs?: KuboStopOptions constructor (options: KuboOptions) { if (options.rpc == null) { @@ -59,6 +60,10 @@ export default class KuboDaemon implements KuboNode { if (options.start != null && typeof options.start !== 'boolean') { this.startArgs = options.start } + + if (options.stop != null) { + this.stopArgs = options.stop + } } get api (): KuboRPCClient { @@ -223,20 +228,32 @@ export default class KuboDaemon implements KuboNode { await deferred.promise } - async stop (options: { timeout?: number } = {}): Promise { - const timeout = options.timeout ?? 60000 + async stop (options?: KuboStopOptions): Promise { + const stopOptions = { + ...(this.stopArgs ?? {}), + ...(options ?? {}) + } + const timeout = stopOptions.forceKillTimeout ?? 1000 const subprocess = this.subprocess if (subprocess == null || subprocess.exitCode != null || this._api == null) { return } + if (!(await this.api.isOnline())) { + return + } + await this.api.stop() - // wait for the subprocess to exit and declare ourselves stopped - await waitFor(() => subprocess.exitCode != null, { - timeout - }) + try { + // wait for the subprocess to exit and declare ourselves stopped + await waitFor(() => subprocess.exitCode != null, { + timeout + }) + } catch { + subprocess.kill('SIGKILL') + } if (this.disposable) { // wait for the cleanup routine to run after the subprocess has exited diff --git a/src/kubo/index.ts b/src/kubo/index.ts index 4930ff10..b77247df 100644 --- a/src/kubo/index.ts +++ b/src/kubo/index.ts @@ -38,7 +38,7 @@ export interface KuboStartOptions { args?: string[] } -export interface KuboOptions extends NodeOptions { +export interface KuboOptions extends NodeOptions { type: 'kubo' /** @@ -58,6 +58,15 @@ export interface KuboOptions extends NodeOptions { +export interface KuboNode extends Node { }