ipfsd-ctl
Version:
Spawn IPFS Daemons, JS or Go
261 lines (227 loc) • 5.74 kB
JavaScript
import { multiaddr } from '@multiformats/multiaddr'
import http from 'ipfs-utils/src/http.js'
import mergeOptions from 'merge-options'
import { logger } from '@libp2p/logger'
const merge = mergeOptions.bind({ ignoreUndefined: true })
const daemonLog = {
info: logger('ipfsd-ctl:client:stdout'),
err: logger('ipfsd-ctl:client:stderr')
}
/**
* @typedef {import('./index').ControllerOptions} ControllerOptions
* @typedef {import('@multiformats/multiaddr').Multiaddr} Multiaddr
*/
/**
* Controller for remote nodes
*
* @class
*/
class Client {
/**
* @class
* @param {string} baseUrl
* @param {import('./types').RemoteState} remoteState
* @param {ControllerOptions} options
*/
constructor (baseUrl, remoteState, options) {
this.opts = options
this.baseUrl = baseUrl
this.id = remoteState.id
this.path = remoteState.path
this.initialized = remoteState.initialized
this.started = remoteState.started
this.disposable = remoteState.disposable
this.clean = remoteState.clean
this.api = null
/** @type {import('./types').Subprocess | null} */
this.subprocess = null
/** @type {Multiaddr} */
this.apiAddr // eslint-disable-line no-unused-expressions
this._setApi(remoteState.apiAddr)
this._setGateway(remoteState.gatewayAddr)
this._setGrpc(remoteState.grpcAddr)
this._createApi()
/** @type {import('./types').PeerData | null} */
this._peerId = null
}
get peer () {
if (this._peerId == null) {
throw new Error('Not started')
}
return this._peerId
}
/**
* @private
* @param {string} addr
*/
_setApi (addr) {
if (addr) {
this.apiAddr = multiaddr(addr)
}
}
/**
* @private
* @param {string} addr
*/
_setGateway (addr) {
if (addr) {
this.gatewayAddr = multiaddr(addr)
}
}
/**
* @private
* @param {string} addr
*/
_setGrpc (addr) {
if (addr) {
this.grpcAddr = multiaddr(addr)
}
}
/**
* @private
*/
_createApi () {
if (this.opts.ipfsClientModule && this.grpcAddr && this.apiAddr) {
this.api = this.opts.ipfsClientModule.create({
grpc: this.grpcAddr,
http: this.apiAddr
})
} else if (this.apiAddr) {
this.api = this.opts.ipfsHttpModule.create(this.apiAddr)
}
if (this.api) {
if (this.apiAddr) {
this.api.apiHost = this.apiAddr.nodeAddress().address
this.api.apiPort = this.apiAddr.nodeAddress().port
}
if (this.gatewayAddr) {
this.api.gatewayHost = this.gatewayAddr.nodeAddress().address
this.api.gatewayPort = this.gatewayAddr.nodeAddress().port
}
if (this.grpcAddr) {
this.api.grpcHost = this.grpcAddr.nodeAddress().address
this.api.grpcPort = this.grpcAddr.nodeAddress().port
}
}
}
/**
* Initialize a repo.
*
* @param {import('./types').InitOptions} [initOptions]
* @returns {Promise<Client>}
*/
async init (initOptions = {}) {
if (this.initialized) {
return this
}
let ipfsOptions = {}
if (this.opts.ipfsOptions != null && this.opts.ipfsOptions.init != null && !(typeof this.opts.ipfsOptions.init === 'boolean')) {
ipfsOptions = this.opts.ipfsOptions.init
}
const opts = merge(
{
emptyRepo: false,
profiles: this.opts.test ? ['test'] : []
},
ipfsOptions,
typeof initOptions === 'boolean' ? {} : initOptions
)
const req = await http.post(
`${this.baseUrl}/init`,
{
searchParams: new URLSearchParams({ id: this.id }),
json: opts
}
)
const rsp = await req.json()
this.initialized = rsp.initialized
this.clean = false
return this
}
/**
* Delete the repo that was being used.
* If the node was marked as `disposable` this will be called
* automatically when the process is exited.
*
* @returns {Promise<Client>}
*/
async cleanup () {
if (this.clean) {
return this
}
await http.post(
`${this.baseUrl}/cleanup`,
{ searchParams: new URLSearchParams({ id: this.id }) }
)
this.clean = true
return this
}
/**
* Start the daemon.
*
* @returns {Promise<Client>}
*/
async start () {
if (!this.started) {
const req = await http.post(
`${this.baseUrl}/start`,
{ searchParams: new URLSearchParams({ id: this.id }) }
)
const res = await req.json()
this._setApi(res.apiAddr)
this._setGateway(res.gatewayAddr)
this._setGrpc(res.grpcAddr)
this._createApi()
this.started = true
}
// Add `peerId`
const id = await this.api.id()
this._peerId = id
daemonLog.info(id)
return this
}
/**
* Stop the daemon
*/
async stop () {
if (!this.started) {
return this
}
await http.post(
`${this.baseUrl}/stop`,
{ searchParams: new URLSearchParams({ id: this.id }) }
)
this.started = false
if (this.disposable) {
await this.cleanup()
}
return this
}
/**
* Get the pid of the `ipfs daemon` process.
*
* @returns {Promise<number>}
*/
async pid () {
const req = await http.get(
`${this.baseUrl}/pid`,
{ searchParams: new URLSearchParams({ id: this.id }) }
)
const res = await req.json()
return res.pid
}
/**
* Get the version of ipfs
*
* @returns {Promise<string>}
*/
async version () {
const req = await http.get(
`${this.baseUrl}/version`,
{ searchParams: new URLSearchParams({ id: this.id }) }
)
const res = await req.json()
return res.version
}
}
export default Client