datona-lib
Version:
Core library for access to the Datona IO Platform. Datona Protocol v0.0.2. Adds HTTP and WebSocket support.
419 lines (365 loc) • 11.8 kB
JavaScript
;
/*
* Datona-lib Error types
*
* Copyright (C) 2020 Datona Labs
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
/*
* Root class for all errors thrown by Datona software. All datona errors
* are derived from this class and have the same constructor parameters.
*/
class DatonaError extends Error {
constructor(message, details) {
super(message);
this.name = "DatonaError";
this.details = details;
}
/*
* Converts this error into a JSON formatted string, excluding the stacktrace
*/
toJSON() {
return JSON.stringify(this.toObject());
}
/*
* Converts this error into a simple struct with just name, message and details, excluding the stacktrace
*/
toObject() {
return {
name: this.name,
message: this.message,
details: this.details
};
}
/*
* Converts this error into a single line string suitable for logging,
* excluding the stacktrace. If the error details is not a string then it
* will be converted to JSON. If the error details is longer than 96 chars
* then it will be truncated.
*/
toString() {
var str = this.name + " - " + this.message;
if (this.details !== undefined) {
var details = (typeof this.details == "string") ? this.details.replace(/(?:\r\n|\r|\n)/g, '; ') : JSON.stringify(this.details);
if (details.length > 96) details = details.slice(0, 96) + "...";
str += " (" + details + ")";
}
return str;
}
}
module.exports.DatonaError = DatonaError;
/*
* Converts the given object into a DatonaError of the appropriate type.
* Inverse of DatonaError.toObject()
*/
function fromObject(error) {
if (error === undefined) throw new DatonaError("error is missing");
if (toString.call(error) !== '[object Object]') throw new DatonaError("error is invalid type: expecting object.");
if (error.name === undefined || error.name === "") throw new DatonaError("name missing from error");
const type = module.exports[error.name];
if (type === undefined || ! type instanceof DatonaError) throw new DeveloperError("Software has thrown "+error.name+" - "+error.message, error);
return new type(error.message, error.details);
}
module.exports.fromObject = fromObject;
/*
* Class of exception for defensive programming checks. These errors are not expected
* to be raised and indicate a low-level software problem that needs raising with
* the software developer.
*/
class InternalError extends DatonaError {
constructor(message, details) {
super(message, details);
this.name = "InternalError";
}
}
module.exports.InternalError = InternalError;
/*
* Class of exception for software usage errors. These errors indicate a
* problem with how the developer is interfacing with this software.
*/
class DeveloperError extends DatonaError {
constructor(message, details) {
super(message, details);
this.name = "DeveloperError";
}
}
module.exports.DeveloperError = DeveloperError;
/*
* The caller of this method passed an invalid or missing argument
*/
class ArgumentError extends DeveloperError {
constructor(message, details) {
super(message, details);
this.name = "ArgumentError";
}
}
module.exports.ArgumentError = ArgumentError;
/*
* The caller of this method passed an argument with an invalid type
*/
class TypeError extends DeveloperError {
constructor(message, details) {
super(message, details);
this.name = "TypeError";
}
}
module.exports.TypeError = TypeError;
/*
* The caller of this method passed an invalid hash
*/
class InvalidHashError extends DeveloperError {
constructor(message, details) {
super(message, details);
this.name = "InvalidHashError";
}
}
module.exports.InvalidHashError = InvalidHashError;
/*
* Class of cryptographic errors
*/
class CryptographicError extends DatonaError {
constructor(message, details) {
super(message, details);
this.name = "CryptographicError";
}
}
module.exports.CryptographicError = CryptographicError;
/*
* The caller of this method passed an invalid hash
*/
class InvalidSignatureError extends CryptographicError {
constructor(message, details) {
super(message, details);
this.name = "InvalidSignatureError";
}
}
module.exports.InvalidSignatureError = InvalidSignatureError;
/*
* The data could not be hashed
*/
class HashingError extends CryptographicError {
constructor(message, details) {
super(message, details);
this.name = "HashingError";
}
}
module.exports.HashingError = HashingError;
/*
* Class of errors related to blockchain access and contract management
*/
class BlockchainError extends DatonaError {
constructor(message, details) {
super(message, details);
this.name = "BlockchainError";
}
}
module.exports.BlockchainError = BlockchainError;
/*
* This request must be made by the contract owner
*/
class ContractOwnerError extends BlockchainError {
constructor(message, details) {
super(message, details);
this.name = "ContractOwnerError";
}
}
module.exports.ContractOwnerError = ContractOwnerError;
/*
* Indicates the contract class is invalid
*/
class ContractTypeError extends BlockchainError {
constructor(message, details) {
super(message, details);
this.name = "ContractTypeError";
}
}
module.exports.ContractTypeError = ContractTypeError;
/*
* This request must be made by the contract owner
*/
class ContractExpiryError extends BlockchainError {
constructor(message, details) {
super(message, details);
this.name = "ContractExpiryError";
}
}
module.exports.ContractExpiryError = ContractExpiryError;
/*
* Indicates the signatory does not have permission to perform this action
*/
class PermissionError extends BlockchainError {
constructor(message, details) {
super(message, details);
this.name = "PermissionError";
}
}
module.exports.PermissionError = PermissionError;
/*
* Class of errors related to a communications transaction
*/
class TransactionError extends DatonaError {
constructor(message, details) {
super(message, details);
this.name = "TransactionError";
}
}
module.exports.TransactionError = TransactionError;
/*
* Indicates the transaction type is invalid
*/
class InvalidTransactionError extends TransactionError {
constructor(message, details) {
super(message, details);
this.name = "InvalidTransactionError";
}
}
module.exports.InvalidTransactionError = InvalidTransactionError;
/*
* Indicates the transaction has an invalid form
*/
class MalformedTransactionError extends TransactionError {
constructor(message, details) {
super(message, details);
this.name = "MalformedTransactionError";
}
}
module.exports.MalformedTransactionError = MalformedTransactionError;
/*
* Class of errors related to a communications transaction
*/
class CommunicationError extends TransactionError {
constructor(message, details) {
super(message, details);
this.name = "CommunicationError";
}
}
module.exports.CommunicationError = CommunicationError;
/*
* Indicates the transaction contains an invalid request
*/
class RequestError extends TransactionError {
constructor(message, details) {
super(message, details);
this.name = "RequestError";
}
}
module.exports.RequestError = RequestError;
/*
* Class of errors related to vault management and guardianship
*/
class VaultError extends DatonaError {
constructor(message, details) {
super(message, details);
this.name = "VaultError";
}
}
module.exports.VaultError = VaultError;
/*
* Error resulting from filesystem access
*/
class FileSystemError extends DatonaError {
constructor(err, message) {
const fsErrMsg = decodeFSError(err);
message = (message === undefined) ? fsErrMsg : message+" ("+fsErrMsg+")";
super(message, err);
this.name = "FileSystemError";
}
}
module.exports.FileSystemError = FileSystemError;
const FS_ERROR_CODES = {
E2BIG: "argument list too long",
EACCES: "permission denied",
EADDRINUSE: "address already in use",
EADDRNOTAVAIL: "address not available",
EAFNOSUPPORT: "address family not supported",
EAGAIN: "resource temporarily unavailable",
EAI_ADDRFAMILY: "address family not supported",
EAI_AGAIN: "temporary failure",
EAI_BADFLAGS: "bad ai_flags value",
EAI_BADHINTS: "invalid value for hints",
EAI_CANCELED: "request canceled",
EAI_FAIL: "permanent failure",
EAI_FAMILY: "ai_family not supported",
EAI_MEMORY: "out of memory",
EAI_NODATA: "no address",
EAI_NONAME: "unknown node or service",
EAI_OVERFLOW: "argument buffer overflow",
EAI_PROTOCOL: "resolved protocol is unknown",
EAI_SERVICE: "service not available for socket type",
EAI_SOCKTYPE: "socket type not supported",
EAI_SYSTEM: "system error",
EALREADY: "connection already in progress",
EBADF: "bad file descriptor",
EBUSY: "resource busy or locked",
ECANCELED: "operation canceled",
ECHARSET: "invalid Unicode character",
ECONNABORTED: "software caused connection abort",
ECONNREFUSED: "connection refused",
ECONNRESET: "connection reset by peer",
EDESTADDRREQ: "destination address required",
EEXIST: "file already exists",
EFAULT: "bad address in system call argument",
EFBIG: "file too large",
EHOSTUNREACH: "host is unreachable",
EINTR: "interrupted system call",
EINVAL: "invalid argument",
EIO: "i/o error",
EISCONN: "socket is already connected",
EISDIR: "illegal operation on a directory",
ELOOP: "too many symbolic links encountered",
EMFILE: "too many open files",
EMSGSIZE: "message too long",
ENAMETOOLONG: "name too long",
ENETDOWN: "network is down",
ENETUNREACH: "network is unreachable",
ENFILE: "file table overflow",
ENOBUFS: "no buffer space available",
ENODEV: "no such device",
ENOENT: "no such file or directory",
ENOMEM: "not enough memory",
ENONET: "machine is not on the network",
ENOPROTOOPT: "protocol not available",
ENOSPC: "no space left on device",
ENOSYS: "function not implemented",
ENOTCONN: "socket is not connected",
ENOTDIR: "not a directory",
ENOTEMPTY: "directory not empty",
ENOTSOCK: "socket operation on non-socket",
ENOTSUP: "operation not supported on socket",
EPERM: "operation not permitted",
EPIPE: "broken pipe",
EPROTO: "protocol error",
EPROTONOSUPPORT: "protocol not supported",
EPROTOTYPE: "protocol wrong type for socket",
ERANGE: "result too large",
EROFS: "read-only file system",
ESHUTDOWN: "cannot send after transport endpoint shutdown",
ESPIPE: "invalid seek",
ESRCH: "no such process",
ETIMEDOUT: "connection timed out",
ETXTBSY: "text file is busy",
EXDEV: "cross-device link not permitted",
UNKNOWN: "unknown error",
EOF: "end of file",
ENXIO: "no such device or address",
EMLINK: "too many links"
};
function decodeFSError(err) {
if (err === undefined || err.code === undefined) return err;
else if (err.code in FS_ERROR_CODES) return FS_ERROR_CODES[err.code] + " " + err.path;
else return "unknown error accessing " + err.path;
}