From 74f0db53b2681de2a68f621cbb7fa5ad8941f99d Mon Sep 17 00:00:00 2001 From: Adam Uhlir Date: Wed, 7 Aug 2019 11:46:55 +0200 Subject: [PATCH] refactor: error objects and handling License: MIT Signed-off-by: Adam Uhlir --- package.json | 1 - src/blockstore.js | 8 +-- src/config.js | 9 ++- src/errors/index.js | 129 ++++++++++++++++++++++++++++++++++++++-- src/index.js | 21 +++---- src/lock-memory.js | 4 +- src/version.js | 4 +- test/blockstore-test.js | 7 ++- test/config-test.js | 8 ++- test/options-test.js | 11 ++-- test/repo-test.js | 14 ++--- 11 files changed, 167 insertions(+), 49 deletions(-) diff --git a/package.json b/package.json index 6391b261..480cc433 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,6 @@ "datastore-fs": "~0.9.0", "datastore-level": "~0.12.0", "debug": "^4.1.0", - "err-code": "^1.1.2", "interface-datastore": "~0.7.0", "ipfs-block": "~0.8.1", "just-safe-get": "^1.3.0", diff --git a/src/blockstore.js b/src/blockstore.js index 84950f99..fb617bf9 100644 --- a/src/blockstore.js +++ b/src/blockstore.js @@ -6,7 +6,7 @@ const Key = require('interface-datastore').Key const base32 = require('base32.js') const Block = require('ipfs-block') const CID = require('cids') -const errcode = require('err-code') +const { ERR_INVALID_CID } = require('./errors') /** * Transform a raw buffer to a base32 encoded key. @@ -63,7 +63,7 @@ function createBaseStore (store) { */ async get (cid) { if (!CID.isCID(cid)) { - throw errcode(new Error('Not a valid cid'), 'ERR_INVALID_CID') + throw new ERR_INVALID_CID('Not a valid CID') } const key = cidToDsKey(cid) let blockData @@ -138,7 +138,7 @@ function createBaseStore (store) { */ async has (cid) { if (!CID.isCID(cid)) { - throw errcode(new Error('Not a valid cid'), 'ERR_INVALID_CID') + throw new ERR_INVALID_CID('Not a valid CID') } const exists = await store.has(cidToDsKey(cid)) @@ -155,7 +155,7 @@ function createBaseStore (store) { */ async delete (cid) { // eslint-disable-line require-await if (!CID.isCID(cid)) { - throw errcode(new Error('Not a valid cid'), 'ERR_INVALID_CID') + throw new ERR_INVALID_CID('Not a valid CID') } return store.delete(cidToDsKey(cid)) }, diff --git a/src/config.js b/src/config.js index 2292ccb6..c1fa85dc 100644 --- a/src/config.js +++ b/src/config.js @@ -5,8 +5,7 @@ const Queue = require('p-queue') const _get = require('just-safe-get') const _set = require('just-safe-set') const _has = require('lodash.has') -const errcode = require('err-code') -const errors = require('./errors') +const { ERR_NOT_FOUND, ERR_INVALID_VALUE, ERR_INVALID_KEY } = require('./errors') const configKey = new Key('config') @@ -28,7 +27,7 @@ module.exports = (store) => { const encodedValue = await store.get(configKey) const config = JSON.parse(encodedValue.toString()) if (key !== undefined && !_has(config, key)) { - throw new errors.NotFoundError(`Key ${key} does not exist in config`) + throw new ERR_NOT_FOUND(`Key ${key} does not exist in config`) } const value = key !== undefined ? _get(config, key) : config @@ -47,11 +46,11 @@ module.exports = (store) => { value = key key = undefined } else if (!key || typeof key !== 'string') { - throw errcode(new Error('Invalid key type: ' + typeof key), 'ERR_INVALID_KEY') + throw new ERR_INVALID_KEY('Invalid key type: ' + typeof key) } if (value === undefined || Buffer.isBuffer(value)) { - throw errcode(new Error('Invalid value type: ' + typeof value), 'ERR_INVALID_VALUE') + throw new ERR_INVALID_VALUE('Invalid value type: ' + typeof value) } return setQueue.add(() => _doSet({ diff --git a/src/errors/index.js b/src/errors/index.js index 5a1d7327..8118d3d3 100644 --- a/src/errors/index.js +++ b/src/errors/index.js @@ -1,5 +1,7 @@ 'use strict' +// TODO: Should be refactored when https://github.com/ipfs/js-ipfs/pull/1746/ is adopted. + /** * Error raised when there is lock already in place when repo is being opened. */ @@ -13,7 +15,7 @@ class LockExistsError extends Error { } LockExistsError.code = 'ERR_LOCK_EXISTS' -exports.LockExistsError = LockExistsError +exports.ERR_LOCK_EXISTS = LockExistsError /** * Error raised when requested item is not found. @@ -28,8 +30,125 @@ class NotFoundError extends Error { } NotFoundError.code = 'ERR_NOT_FOUND' -exports.NotFoundError = NotFoundError +exports.ERR_NOT_FOUND = NotFoundError + +/** + * Error raised when repo was not initialized. + */ +class RepoNotInitializedError extends Error { + constructor (message, path) { + super(message) + this.name = 'RepoNotInitializedError' + this.code = 'ERR_REPO_NOT_INITIALIZED' + this.message = message + this.path = path + } +} + +RepoNotInitializedError.code = 'ERR_REPO_NOT_INITIALIZED' +exports.ERR_REPO_NOT_INITIALIZED = RepoNotInitializedError + +/** + * Error raised while opening repo when repo is already opened. + */ +class RepoAlreadyOpenError extends Error { + constructor (message) { + super(message) + this.name = 'RepoAlreadyOpenError' + this.code = 'ERR_REPO_ALREADY_OPEN' + this.message = message + } +} + +RepoAlreadyOpenError.code = 'ERR_REPO_ALREADY_OPEN' +exports.ERR_REPO_ALREADY_OPEN = RepoAlreadyOpenError + +/** + * Error raised while opening repo when repo is already opened. + */ +class RepoAlreadyClosedError extends Error { + constructor (message) { + super(message) + this.name = 'RepoAlreadyClosedError' + this.code = 'ERR_REPO_ALREADY_CLOSED' + this.message = message + } +} + +RepoAlreadyClosedError.code = 'ERR_REPO_ALREADY_CLOSED' +exports.ERR_REPO_ALREADY_CLOSED = RepoAlreadyClosedError + +/** + * Error raised when lock object is returned that does not have close() function. + */ +class NoCloseFunctionError extends Error { + constructor (message) { + super(message) + this.name = 'NoCloseFunctionError' + this.code = 'ERR_NO_CLOSE_FUNCTION' + this.message = message + } +} + +NoCloseFunctionError.code = 'ERR_NO_CLOSE_FUNCTION' +exports.ERR_NO_CLOSE_FUNCTION = NoCloseFunctionError + +/** + * Error raised when the version of repo is not as expected. + */ +class InvalidRepoVersionError extends Error { + constructor (message) { + super(message) + this.name = 'InvalidRepoVersionError' + this.code = 'ERR_INVALID_REPO_VERSION' + this.message = message + } +} + +InvalidRepoVersionError.code = 'ERR_INVALID_REPO_VERSION' +exports.ERR_INVALID_REPO_VERSION = InvalidRepoVersionError + +/** + * Error raised when the config's key is of invalid type. + */ +class InvalidKeyError extends Error { + constructor (message) { + super(message) + this.name = 'InvalidKeyError' + this.code = 'ERR_INVALID_KEY' + this.message = message + } +} + +InvalidKeyError.code = 'ERR_INVALID_KEY' +exports.ERR_INVALID_KEY = InvalidKeyError + +/** + * Error raised when the config's value is of invalid type. + */ +class InvalidValueError extends Error { + constructor (message) { + super(message) + this.name = 'InvalidValueError' + this.code = 'ERR_INVALID_VALUE' + this.message = message + } +} + +InvalidValueError.code = 'ERR_INVALID_VALUE' +exports.ERR_INVALID_VALUE = InvalidValueError + +/** + * Error raised when CID is not valid. + */ +class InvalidCidError extends Error { + constructor (message) { + super(message) + this.name = 'InvalidCidError' + this.code = 'ERR_INVALID_CID' + this.message = message + } +} -exports.ERR_REPO_NOT_INITIALIZED = 'ERR_REPO_NOT_INITIALIZED' -exports.ERR_REPO_ALREADY_OPEN = 'ERR_REPO_ALREADY_OPEN' -exports.ERR_REPO_ALREADY_CLOSED = 'ERR_REPO_ALREADY_CLOSED' +InvalidCidError.code = 'ERR_INVALID_CID' +exports.ERR_INVALID_CID = InvalidCidError diff --git a/src/index.js b/src/index.js index e19fae99..e4c9786e 100644 --- a/src/index.js +++ b/src/index.js @@ -5,7 +5,6 @@ const assert = require('assert') const path = require('path') const debug = require('debug') const Big = require('bignumber.js') -const errcode = require('err-code') const backends = require('./backends') const version = require('./version') @@ -15,7 +14,7 @@ const apiAddr = require('./api-addr') const blockstore = require('./blockstore') const defaultOptions = require('./default-options') const defaultDatastore = require('./default-datastore') -const ERRORS = require('./errors') +const errors = require('./errors') const log = debug('repo') @@ -75,7 +74,7 @@ class IpfsRepo { */ async open () { if (!this.closed) { - throw errcode(new Error('repo is already open'), ERRORS.ERR_REPO_ALREADY_OPEN) + throw new errors.ERR_REPO_ALREADY_OPEN('Repo is already open') } log('opening at: %s', this.path) @@ -149,7 +148,7 @@ class IpfsRepo { const lockfile = await this._locker.lock(path) if (typeof lockfile.close !== 'function') { - throw errcode(new Error('Locks must have a close method'), 'ERR_NO_CLOSE_FUNCTION') + throw new errors.ERR_NO_CLOSE_FUNCTION('Locks must have a close method') } return lockfile @@ -180,18 +179,14 @@ class IpfsRepo { ]) } catch (err) { if (err.code === 'ERR_NOT_FOUND') { - throw errcode(new Error('repo is not initialized yet'), ERRORS.ERR_REPO_NOT_INITIALIZED, { - path: this.path - }) + throw new errors.ERR_REPO_NOT_INITIALIZED('Repo is not initialized yet', this.path) } throw err } if (!config) { - throw errcode(new Error('repo is not initialized yet'), ERRORS.ERR_REPO_NOT_INITIALIZED, { - path: this.path - }) + throw new errors.ERR_REPO_NOT_INITIALIZED('Repo is not initialized yet', this.path) } } @@ -202,7 +197,7 @@ class IpfsRepo { */ async close () { if (this.closed) { - throw errcode(new Error('repo is already closed'), ERRORS.ERR_REPO_ALREADY_CLOSED) + throw new errors.ERR_REPO_ALREADY_CLOSED('Repo is already closed') } log('closing at: %s', this.path) @@ -210,7 +205,7 @@ class IpfsRepo { // Delete api, ignoring irrelevant errors await this.apiAddr.delete() } catch (err) { - if (err.code !== ERRORS.ERR_REPO_NOT_INITIALIZED && !err.message.startsWith('ENOENT')) { + if (err.code !== errors.ERR_REPO_NOT_INITIALIZED.code && !err.message.startsWith('ENOENT')) { throw err } } @@ -299,7 +294,7 @@ async function getSize (queryFn) { module.exports = IpfsRepo module.exports.repoVersion = repoVersion -module.exports.errors = ERRORS +module.exports.errors = errors function buildOptions (_options) { const options = Object.assign({}, defaultOptions, _options) diff --git a/src/lock-memory.js b/src/lock-memory.js index d01ccced..905ceb88 100644 --- a/src/lock-memory.js +++ b/src/lock-memory.js @@ -1,6 +1,6 @@ 'use strict' -const errors = require('./errors') +const { ERR_LOCK_EXISTS } = require('./errors') const debug = require('debug') const log = debug('repo:lock') @@ -20,7 +20,7 @@ exports.lock = async (dir) => { // eslint-disable-line require-await log('locking %s', file) if (LOCKS[file] === true) { - throw new errors.LockExistsError(`Lock already being held for file: ${file}`) + throw new ERR_LOCK_EXISTS(`Lock already being held for file: ${file}`) } LOCKS[file] = true diff --git a/src/version.js b/src/version.js index cd0db0ce..db85afab 100644 --- a/src/version.js +++ b/src/version.js @@ -3,7 +3,7 @@ const Key = require('interface-datastore').Key const debug = require('debug') const log = debug('repo:version') -const errcode = require('err-code') +const { ERR_INVALID_REPO_VERSION } = require('./errors') const versionKey = new Key('version') @@ -48,7 +48,7 @@ module.exports = (store) => { const compatibleVersion = (version === 6 && expected === 7) || (expected === 6 && version === 7) if (version !== expected && !compatibleVersion) { - throw errcode(new Error(`ipfs repo needs migration: expected version v${expected}, found version v${version}`), 'ERR_INVALID_REPO_VERSION') + throw new ERR_INVALID_REPO_VERSION(`Ipfs repo needs migration: expected version v${expected}, found version v${version}`) } } } diff --git a/test/blockstore-test.js b/test/blockstore-test.js index 07ca44e6..6f3a9dc1 100644 --- a/test/blockstore-test.js +++ b/test/blockstore-test.js @@ -14,6 +14,7 @@ const path = require('path') const Key = require('interface-datastore').Key const base32 = require('base32.js') const IPFSRepo = require('../') +const errors = IPFSRepo.errors module.exports = (repo) => { describe('blockstore', () => { @@ -187,7 +188,7 @@ module.exports = (repo) => { await repo.blocks.get('foo') throw new Error('Should have thrown') } catch (err) { - expect(err.code).to.equal('ERR_INVALID_CID') + expect(err.code).to.equal(errors.ERR_INVALID_CID.code) } }) @@ -278,7 +279,7 @@ module.exports = (repo) => { await repo.blocks.has('foo') throw new Error('Should have thrown') } catch (err) { - expect(err.code).to.equal('ERR_INVALID_CID') + expect(err.code).to.equal(errors.ERR_INVALID_CID.code) } }) @@ -304,7 +305,7 @@ module.exports = (repo) => { await repo.blocks.delete('foo') throw new Error('Should have thrown') } catch (err) { - expect(err.code).to.equal('ERR_INVALID_CID') + expect(err.code).to.equal(errors.ERR_INVALID_CID.code) } }) }) diff --git a/test/config-test.js b/test/config-test.js index f753de02..70765e45 100644 --- a/test/config-test.js +++ b/test/config-test.js @@ -5,6 +5,8 @@ const chai = require('chai') chai.use(require('dirty-chai')) const expect = chai.expect +const errors = require('../src/errors') + module.exports = (repo) => { describe('config', () => { describe('.set', () => { @@ -13,7 +15,7 @@ module.exports = (repo) => { await repo.config.set(5, 'value') throw new Error('Should have thrown') } catch (err) { - expect(err.code).to.equal('ERR_INVALID_KEY') + expect(err.code).to.equal(errors.ERR_INVALID_KEY.code) } }) @@ -22,7 +24,7 @@ module.exports = (repo) => { await repo.config.set('foo', Buffer.from([0, 1, 2])) throw new Error('Should have thrown') } catch (err) { - expect(err.code).to.equal('ERR_INVALID_VALUE') + expect(err.code).to.equal(errors.ERR_INVALID_VALUE.code) } }) }) @@ -32,7 +34,7 @@ module.exports = (repo) => { await repo.config.get('someRandomKey') throw new Error('Should have thrown') } catch (err) { - expect(err.code).to.equal('ERR_NOT_FOUND') + expect(err.code).to.equal(errors.ERR_NOT_FOUND.code) } }) }) diff --git a/test/options-test.js b/test/options-test.js index 8b2be95e..2bc0c86c 100644 --- a/test/options-test.js +++ b/test/options-test.js @@ -31,8 +31,10 @@ describe('custom options tests', () => { it('allows for a custom lock', () => { const lock = { - lock: async (path) => { }, - locked: async (path) => { } + lock: async (path) => { + }, + locked: async (path) => { + } } const repo = new Repo(repoPath, { @@ -58,11 +60,12 @@ describe('custom options tests', () => { } catch (err) { error = err } - expect(error.code).to.equal('ERR_NO_CLOSE_FUNCTION') + expect(error.code).to.equal(Repo.errors.ERR_NO_CLOSE_FUNCTION.code) }) }) -function noop () {} +function noop () { +} function expectedRepoOptions () { const options = { diff --git a/test/repo-test.js b/test/repo-test.js index ef23c583..d2225519 100644 --- a/test/repo-test.js +++ b/test/repo-test.js @@ -6,7 +6,7 @@ chai.use(require('dirty-chai')) const expect = chai.expect const path = require('path') const IPFSRepo = require('../') -const Errors = require('../src/errors') +const errors = require('../src/errors') const os = require('os') module.exports = (repo) => { @@ -84,7 +84,7 @@ module.exports = (repo) => { await repo.version.check(4) throw new Error('Should have thrown error') } catch (err) { - expect(err.code).to.equal('ERR_INVALID_REPO_VERSION') + expect(err.code).to.equal(errors.ERR_INVALID_REPO_VERSION.code) } }) @@ -95,7 +95,7 @@ module.exports = (repo) => { await repo.version.check(2) throw new Error('Should have thrown error') } catch (err) { - expect(err.code).to.equal('ERR_INVALID_REPO_VERSION') + expect(err.code).to.equal(errors.ERR_INVALID_REPO_VERSION.code) } }) @@ -125,7 +125,7 @@ module.exports = (repo) => { try { await repo.close() } catch (err) { - expect(err.code).to.eql(Errors.ERR_REPO_ALREADY_CLOSED) + expect(err.code).to.eql(errors.ERR_REPO_ALREADY_CLOSED.code) return } expect.fail('Did not throw') @@ -136,7 +136,7 @@ module.exports = (repo) => { try { await repo.open() } catch (err) { - expect(err.code).to.eql(Errors.ERR_REPO_ALREADY_OPEN) + expect(err.code).to.eql(errors.ERR_REPO_ALREADY_OPEN.code) return } expect.fail('Did not throw') @@ -235,7 +235,7 @@ module.exports = (repo) => { try { await otherRepo.open() } catch (err) { - expect(err.code).to.equal(Errors.ERR_REPO_NOT_INITIALIZED) + expect(err.code).to.equal(errors.ERR_REPO_NOT_INITIALIZED.code) } }) @@ -254,7 +254,7 @@ module.exports = (repo) => { try { await otherRepo.open() } catch (err) { - expect(err.code).to.equal(Errors.ERR_REPO_NOT_INITIALIZED) + expect(err.code).to.equal(errors.ERR_REPO_NOT_INITIALIZED.code) } })