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

[WIP] feat: add errors with codes and utils #1746

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
"err-code": "^1.1.2",
"file-type": "^10.2.0",
"fnv1a": "^1.0.1",
"format-util": "^1.0.3",
"fsm-event": "^2.1.0",
"get-folder-size": "^2.0.0",
"glob": "^7.1.3",
Expand Down
91 changes: 91 additions & 0 deletions src/core/errors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
'use strict'

const format = require('format-util')
const assert = require('assert')

const messages = new Map()
const { defineProperty } = Object

/**
* Get formatted message for a error code
*
* @see https://nodejs.org/api/util.html#util_util_format_format_args
* @param {string} key - Error code
* @param {Array} args - Placeholder values for the message
* @returns {string} - Formatted message
*/
function getMessage (key, args) {
const msg = messages.get(key)

if (typeof msg === 'function') {
assert(
msg.length <= args.length, // Default options do not count.
`Code: ${key}; The provided arguments length (${args.length}) does not ` +
`match the required ones (${msg.length}).`
)
return msg.apply(null, args)
}

const expectedLength = (msg.match(/%[dfijoOs]/g) || []).length
assert(
expectedLength === args.length,
`Code: ${key}; The provided arguments length (${args.length}) does not ` +
`match the required ones (${expectedLength}).`
)
if (args.length === 0) { return msg }

args.unshift(msg)
return format.apply(null, args)
}

function makeError (Base, key) {
return class IPFSError extends Base {
/**
* Creates an instance of IPFSError.
* @param {...Any} args - Message placeholders values
*/
constructor (...args) {
super(getMessage(key, args))
}

get name () {
return `${super.name} [${key}]`
}

set name (value) {
defineProperty(this, 'name', {
configurable: true,
enumerable: true,
value,
writable: true
})
}

get code () {
return key
}

set code (value) {
defineProperty(this, 'code', {
configurable: true,
enumerable: true,
value,
writable: true
})
}
}
}

function E (sym, val, def) {
messages.set(sym, val)
const c = makeError(def, sym)
c.code = sym
return c
}

// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error#Error_types
module.exports = {
ERR_IPFS_MISSING_IPLD_FORMAT: E('ERR_IPFS_MISSING_IPLD_FORMAT', 'Missing IPLD format %s', Error),
ERR_IPFS_PRELOAD_ABORTED: E('ERR_IPFS_PRELOAD_ABORTED', 'Preload aborted for %s', Error),
ERR_IPFS_INVALID_PATH: E('ERR_IPFS_INVALID_PATH', 'Invalid IPFS path: %s', TypeError)
}
9 changes: 7 additions & 2 deletions src/core/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const EventEmitter = require('events')
const config = require('./config')
const boot = require('./boot')
const components = require('./components')
const { ERR_IPFS_MISSING_IPLD_FORMAT } = require('./errors')

// replaced by repo-browser when running in the browser
const defaultRepo = require('./runtime/repo-nodejs')
Expand Down Expand Up @@ -120,8 +121,12 @@ class IPFS extends EventEmitter {
blockService: this._blockService,
loadFormat: (codec, callback) => {
this.log('Loading IPLD format', codec)
if (IpldFormats[codec]) return callback(null, IpldFormats[codec])
callback(new Error(`Missing IPLD format "${codec}"`))

if (IpldFormats[codec]) {
return callback(null, IpldFormats[codec])
}

callback(new ERR_IPFS_MISSING_IPLD_FORMAT(codec))
}
})
this._preload = preload(this)
Expand Down
3 changes: 2 additions & 1 deletion src/core/preload.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const toUri = require('multiaddr-to-uri')
const debug = require('debug')
const CID = require('cids')
const preload = require('./runtime/preload-nodejs')
const { ERR_IPFS_PRELOAD_ABORTED } = require('./errors')

const log = debug('jsipfs:preload')
log.error = debug('jsipfs:preload:error')
Expand Down Expand Up @@ -48,7 +49,7 @@ module.exports = self => {
const now = Date.now()

retry({ times: fallbackApiUris.length }, (cb) => {
if (stopped) return cb(new Error(`preload aborted for ${cid}`))
if (stopped) return cb(new ERR_IPFS_PRELOAD_ABORTED(cid))

// Remove failed request from a previous attempt
requests = requests.filter(r => r !== request)
Expand Down
9 changes: 4 additions & 5 deletions src/core/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ const promisify = require('promisify-es6')
const map = require('async/map')
const isIpfs = require('is-ipfs')
const CID = require('cids')
const { ERR_IPFS_INVALID_PATH } = require('./errors')

const ERR_BAD_PATH = 'ERR_BAD_PATH'
exports.OFFLINE_ERROR = 'This command must be run in online mode. Try running \'ipfs daemon\' first.'

/**
Expand All @@ -21,11 +21,10 @@ exports.OFFLINE_ERROR = 'This command must be run in online mode. Try running \'
* @throws on an invalid @param ipfsPath
*/
function parseIpfsPath (ipfsPath) {
const invalidPathErr = new Error('invalid ipfs ref path')
ipfsPath = ipfsPath.replace(/^\/ipfs\//, '')
const matched = ipfsPath.match(/([^/]+(?:\/[^/]+)*)\/?$/)
if (!matched) {
throw invalidPathErr
throw new ERR_IPFS_INVALID_PATH(ipfsPath)
}

const [hash, ...links] = matched[1].split('/')
Expand All @@ -34,7 +33,7 @@ function parseIpfsPath (ipfsPath) {
if (isIpfs.cid(hash)) {
return { hash, links }
} else {
throw invalidPathErr
throw new ERR_IPFS_INVALID_PATH(ipfsPath)
}
}

Expand All @@ -57,7 +56,7 @@ const normalizePath = (pathStr) => {
} else if (isIpfs.path(pathStr)) {
return pathStr
} else {
throw Object.assign(new Error(`invalid ${pathStr} path`), { code: ERR_BAD_PATH })
throw new ERR_IPFS_INVALID_PATH(pathStr)
}
}

Expand Down