UNPKG

4 kBJavaScriptView Raw
1'use strict'
2const merge = require('merge-options').bind({ ignoreUndefined: true })
3const kyOriginal = require('ky-universal').default
4const { tmpDir } = require('./utils')
5const { isNode } = require('ipfs-utils/src/env')
6const ControllerDaemon = require('./ipfsd-daemon')
7const ControllerRemote = require('./ipfsd-client')
8const ControllerProc = require('./ipfsd-in-proc')
9const testsConfig = require('./config')
10
11/** @typedef {import("./index").ControllerOptions} ControllerOptions */
12/** @typedef {import("./index").ControllerOptionsOverrides} ControllerOptionsOverrides */
13/** @typedef {import("./index").IpfsOptions} IpfsOptions */
14
15const ky = kyOriginal.extend({ timeout: false })
16const defaults = {
17 remote: !isNode,
18 endpoint: 'http://localhost:43134',
19 disposable: true,
20 test: false,
21 type: 'go',
22 env: {},
23 args: [],
24 ipfsOptions: {},
25 forceKill: true,
26 forceKillTimeout: 5000
27}
28
29/**
30 * Factory class to spawn ipfsd controllers
31 */
32class Factory {
33 /**
34 *
35 * @param {ControllerOptions} options
36 * @param {ControllerOptionsOverrides} overrides - Pre-defined overrides per controller type
37 */
38 constructor (options = {}, overrides = {}) {
39 /** @type ControllerOptions */
40 this.opts = merge(defaults, options)
41
42 /** @type ControllerOptionsOverrides */
43 this.overrides = merge({
44 js: merge(this.opts, { type: 'js' }),
45 go: merge(this.opts, { type: 'go' }),
46 proc: merge(this.opts, { type: 'proc' })
47 }, overrides)
48
49 /** @type ControllerDaemon[] */
50 this.controllers = []
51 }
52
53 /**
54 * Utility method to get a temporary directory
55 * useful in browsers to be able to generate temp
56 * repos manually
57 *
58 * @param {ControllerOptions} options - Controller type
59 *
60 * @returns {Promise<String>}
61 */
62 async tmpDir (options) {
63 options = merge(this.opts, options)
64 if (options.remote) {
65 const res = await ky.get(
66 `${options.endpoint}/util/tmp-dir`,
67 { searchParams: { type: options.type } }
68 ).json()
69
70 return res.tmpDir
71 }
72
73 return Promise.resolve(tmpDir(options.type))
74 }
75
76 async _spawnRemote (options) {
77 const opts = {
78 json: {
79 ...options,
80 // avoid recursive spawning
81 remote: false
82 }
83 }
84
85 const res = await ky.post(
86 `${options.endpoint}/spawn`,
87 opts
88 ).json()
89 return new ControllerRemote(
90 options.endpoint,
91 res,
92 options
93 )
94 }
95
96 /**
97 * Spawn an IPFSd Controller
98 * @param {ControllerOptions} options
99 * @returns {Promise<ControllerDaemon>}
100 */
101 async spawn (options = { }) {
102 const type = options.type || this.opts.type
103 const opts = merge(
104 this.overrides[type],
105 options
106 )
107
108 // IPFS options defaults
109 const ipfsOptions = merge(
110 {
111 start: false,
112 init: false
113 },
114 opts.test ? {
115 config: testsConfig(opts),
116 preload: { enabled: false }
117 } : {},
118 opts.ipfsOptions
119 )
120
121 let ctl
122 if (opts.type === 'proc') {
123 // spawn in-proc controller
124 ctl = new ControllerProc({ ...opts, ipfsOptions })
125 } else if (opts.remote) {
126 // spawn remote controller
127 ctl = await this._spawnRemote({ ...opts, ipfsOptions })
128 } else {
129 // spawn daemon controller
130 ctl = new ControllerDaemon({ ...opts, ipfsOptions })
131 }
132
133 // Save the controller
134 this.controllers.push(ctl)
135
136 // Auto init and start controller
137 if (opts.disposable && (!options.ipfsOptions || (options.ipfsOptions && options.ipfsOptions.init !== false))) {
138 await ctl.init(ipfsOptions.init)
139 }
140 if (opts.disposable && (!options.ipfsOptions || (options.ipfsOptions && options.ipfsOptions.start !== false))) {
141 await ctl.start()
142 }
143
144 return ctl
145 }
146
147 /**
148 * Stop all controllers
149 * @returns {Promise<ControllerDaemon[]>}
150 */
151 async clean () {
152 await Promise.all(this.controllers.map(n => n.stop()))
153 this.controllers = []
154 return this
155 }
156}
157
158module.exports = Factory