Skip to content
This repository has been archived by the owner on Feb 12, 2024. It is now read-only.

Commit

Permalink
refactor: remove proxy api object and detect initialisaion state
Browse files Browse the repository at this point in the history
Ask the repo if it has been initialised, if so, allow the user to
skip the `.init()` step and move on to `.start()`

Removes the proxy api object in favour of vanilla functions because
it was causing errors to be thrown if you even referenced properties
that were from a different api state.

E.g. with an unitialised repo:

```javascript
const ipfs = await IPFS.create({
  init: false,
  start: false
})

// no invocation, just referencing the property causes an error to be thrown
console.info(ipfs.start)
```

I'd looked at changing the proxy behaviour to return a function that
throws if invoked, but at the time the proxy is called you don't know
what the calling code is going to do with the return value so it's hard
to know if it's accessing a function or a property - the return value is
just put on the stack and interacted with so it seemed simpler to just
pull it out and define the API up front.

A nice future improvement might be to have `.init`, `.start` and `.stop`
export functions that update the API - that way after `.stop` has been
invoked, it could restore the API from the post-`.init` state, but this
can come later.

Also upgrades `ipfsd-ctl` to pass refs only during factory creation.

Depends on:

- [ ] ipfs/js-ipfsd-ctl#457
- [ ] ipfs/js-ipfs-repo#219
- [ ] ipfs-inactive/npm-go-ipfs-dep#40
  • Loading branch information
achingbrain committed Feb 10, 2020
1 parent 39d87c5 commit 8c13bb0
Show file tree
Hide file tree
Showing 12 changed files with 323 additions and 103 deletions.
12 changes: 3 additions & 9 deletions .aegir.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,8 @@ module.exports = {
port: 43134
}, {
type: 'js',
ipfsModule: {
path: __dirname,
ref: require(__dirname)
},
ipfsHttpModule: {
path: require.resolve('ipfs-http-client'),
ref: require('ipfs-http-client')
},
ipfsModule: require(__dirname),
ipfsHttpModule: require('ipfs-http-client'),
ipfsBin: path.join(__dirname, 'src', 'cli', 'bin.js'),
ipfsOptions: {
config: {
Expand All @@ -89,7 +83,7 @@ module.exports = {
}
}, {
go: {
ipfsBin: require.resolve(`go-ipfs-dep/go-ipfs/ipfs${os.platform() === 'win32' ? '.exe' : ''}`)
ipfsBin: require('go-ipfs-dep').path()
}
}).start()
},
Expand Down
10 changes: 2 additions & 8 deletions examples/circuit-relaying/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,8 @@ const execa = require('execa')
const delay = require('delay')
const { createFactory } = require('ipfsd-ctl')
const df = createFactory({
ipfsModule: {
path: require.resolve('../../src'),
ref: require('../../src')
},
ipfsHttpModule: {
path: require.resolve('ipfs-http-client'),
ref: require('ipfs-http-client')
}
ipfsModule: require('../../src'),
ipfsHttpModule: require('ipfs-http-client')
})
const {
startServer
Expand Down
10 changes: 2 additions & 8 deletions examples/exchange-files-in-browser/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,8 @@ const execa = require('execa')
const delay = require('delay')
const { createFactory } = require('ipfsd-ctl')
const df = createFactory({
ipfsModule: {
path: require.resolve('../../src'),
ref: require('../../src')
},
ipfsHttpModule: {
path: require.resolve('ipfs-http-client'),
ref: require('ipfs-http-client')
}
ipfsModule: require('../../src'),
ipfsHttpModule: require('ipfs-http-client')
}, {
js: {
ipfsBin: path.resolve(`${__dirname}/../../src/cli/bin.js`)
Expand Down
10 changes: 2 additions & 8 deletions examples/explore-ethereum-blockchain/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,8 @@ const fs = require('fs-extra')
const path = require('path')
const { createFactory } = require('ipfsd-ctl')
const df = createFactory({
ipfsModule: {
path: require.resolve('../../src'),
ref: require('../../src')
},
ipfsHttpModule: {
path: require.resolve('ipfs-http-client'),
ref: require('ipfs-http-client')
}
ipfsModule: require('../../src'),
ipfsHttpModule: require('ipfs-http-client')
}, {
js: {
ipfsBin: path.resolve(`${__dirname}/../../src/cli/bin.js`)
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@
"ipfs-http-response": "^0.5.0",
"ipfs-mfs": "^1.0.0",
"ipfs-multipart": "^0.3.0",
"ipfs-repo": "^0.30.0",
"ipfs-repo": "github:ipfs/js-ipfs-repo#feat-add-is-initialized-meethod",
"ipfs-unixfs": "^0.3.0",
"ipfs-unixfs-exporter": "^0.41.0",
"ipfs-unixfs-importer": "^0.44.0",
Expand Down Expand Up @@ -182,11 +182,11 @@
"dir-compare": "^1.7.3",
"execa": "^3.0.0",
"form-data": "^3.0.0",
"go-ipfs-dep": "^0.4.23",
"go-ipfs-dep": "github:ipfs/npm-go-ipfs-dep#add-path-function-to-detect-binary",
"hat": "0.0.3",
"interface-ipfs-core": "^0.132.0",
"ipfs-interop": "github:ipfs/interop#refactor/async-await",
"ipfsd-ctl": "github:ipfs/js-ipfsd-ctl#remove-option-normalisation",
"ipfsd-ctl": "github:ipfs/js-ipfsd-ctl#remove-path-ref-and-findbin",
"ncp": "^2.0.0",
"p-event": "^4.1.0",
"p-map": "^3.0.0",
Expand Down
127 changes: 116 additions & 11 deletions src/core/api-manager.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,128 @@
'use strict'

const noop = () => {}
const defaultApi = (onUndef = noop) => ({
add: onUndef,
bitswap: {
stat: onUndef,
unwant: onUndef,
wantlist: onUndef
},
block: {
get: onUndef,
put: onUndef,
rm: onUndef,
stat: onUndef
},
bootstrap: {
add: onUndef,
list: onUndef,
rm: onUndef
},
cat: onUndef,
config: onUndef,
dag: {
get: onUndef,
put: onUndef,
resolve: onUndef,
tree: onUndef
},
dns: onUndef,
files: {
chmod: onUndef,
cp: onUndef,
flush: onUndef,
ls: onUndef,
mkdir: onUndef,
mv: onUndef,
read: onUndef,
rm: onUndef,
stat: onUndef,
touch: onUndef,
write: onUndef
},
get: onUndef,
id: onUndef,
init: onUndef,
isOnline: onUndef,
key: {
export: onUndef,
gen: onUndef,
import: onUndef,
info: onUndef,
list: onUndef,
rename: onUndef,
rm: onUndef
},
ls: onUndef,
name: {
publish: onUndef,
pubsub: {
cancel: onUndef,
state: onUndef,
subs: onUndef
}
},
object: {
data: onUndef,
get: onUndef,
links: onUndef,
new: onUndef,
patch: {
addLink: onUndef,
appendData: onUndef,
rmLink: onUndef,
setData: onUndef
},
put: onUndef,
stat: onUndef
},
pin: onUndef,
ping: onUndef,
pubsub: {
subscribe: onUndef,
unsubscribe: onUndef,
publish: onUndef,
ls: onUndef,
peers: onUndef
},
refs: onUndef,
repo: {
gc: onUndef,
stat: onUndef,
version: onUndef
},
resolve: onUndef,
start: onUndef,
stats: {
bitswap: onUndef,
bw: onUndef,
repo: onUndef
},
stop: onUndef,
swarm: {
addrs: onUndef,
connect: onUndef,
disconnect: onUndef,
localAddrs: onUndef,
peers: onUndef
},
version: onUndef
})

module.exports = class ApiManager {
constructor () {
this._api = {}
this._onUndef = () => undefined
this.api = new Proxy(this._api, {
get: (_, prop) => {
if (prop === 'then') return undefined // Not a promise!
return this._api[prop] === undefined ? this._onUndef(prop) : this._api[prop]
}
})
this.api = {
...defaultApi()
}
}

update (nextApi, onUndef) {
const prevApi = { ...this._api }
const prevUndef = this._onUndef
Object.keys(this._api).forEach(k => { delete this._api[k] })
Object.assign(this._api, nextApi)
if (onUndef) this._onUndef = onUndef
Object.keys(this.api).forEach(k => { delete this.api[k] })
Object.assign(this.api, defaultApi(onUndef), nextApi)
this._onUndef = onUndef || noop
return { cancel: () => this.update(prevApi, prevUndef), api: this.api }
}
}
39 changes: 10 additions & 29 deletions src/core/components/init.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,25 @@
'use strict'

const log = require('debug')('ipfs:components:init')
const defer = require('p-defer')
const PeerId = require('peer-id')
const PeerInfo = require('peer-info')
const mergeOptions = require('merge-options')
const getDefaultConfig = require('../runtime/config-nodejs.js')
const createRepo = require('../runtime/repo-nodejs')
const Keychain = require('libp2p-keychain')
const NoKeychain = require('./no-keychain')
const mortice = require('mortice')
const { DAGNode } = require('ipld-dag-pb')
const UnixFs = require('ipfs-unixfs')
const multicodec = require('multicodec')
const {
AlreadyInitializingError,
AlreadyInitializedError,
NotStartedError,
NotEnabledError
NotStartedError
} = require('../errors')
const BlockService = require('ipfs-block-service')
const Ipld = require('ipld')
const getDefaultIpldOptions = require('../runtime/ipld-nodejs')
const createPreloader = require('../preload')
const { ERR_REPO_NOT_INITIALIZED } = require('ipfs-repo').errors
const IPNS = require('../ipns')
const OfflineDatastore = require('../ipns/routing/offline-datastore')
const initAssets = require('../runtime/init-assets-nodejs')
Expand All @@ -32,9 +29,11 @@ const Components = require('./')
module.exports = ({
apiManager,
print,
options: constructorOptions
options: constructorOptions,
repo
}) => async function init (options) {
const { cancel } = apiManager.update({ init: () => { throw new AlreadyInitializingError() } })
const initPromise = defer()
const { cancel } = apiManager.update({ init: () => initPromise.promise })

try {
options = options || {}
Expand All @@ -49,30 +48,9 @@ module.exports = ({
options.config = mergeOptions(options.config, constructorOptions.config)
}

options.repo = options.repo || constructorOptions.repo
options.repoAutoMigrate = options.repoAutoMigrate || constructorOptions.repoAutoMigrate

const repo = typeof options.repo === 'string' || options.repo == null
? createRepo({ path: options.repo, autoMigrate: options.repoAutoMigrate })
: options.repo

let isInitialized = true

if (repo.closed) {
try {
await repo.open()
} catch (err) {
if (err.code === ERR_REPO_NOT_INITIALIZED) {
isInitialized = false
} else {
throw err
}
}
}

if (!isInitialized && options.allowNew === false) {
throw new NotEnabledError('new repo initialization is not enabled')
}
const isInitialized = await repo.isInitialized()

const { peerId, keychain } = isInitialized
? await initExistingRepo(repo, options)
Expand Down Expand Up @@ -160,9 +138,11 @@ module.exports = ({
apiManager.update(api, () => { throw new NotStartedError() })
} catch (err) {
cancel()
initPromise.reject(err)
throw err
}

initPromise.resolve(apiManager.api)
return apiManager.api
}

Expand Down Expand Up @@ -212,6 +192,7 @@ async function initNewRepo (repo, { privateKey, emptyRepo, bits, profiles, confi
}

async function initExistingRepo (repo, { config: newConfig, profiles, pass }) {
await repo.open()
let config = await repo.config.get()

if (newConfig || profiles) {
Expand Down
Loading

0 comments on commit 8c13bb0

Please sign in to comment.