http: stop using socket.io.

This commit is contained in:
Christopher Jeffrey 2017-10-22 05:44:16 -07:00
parent f617283539
commit 649f8cc171
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
28 changed files with 6332 additions and 10459 deletions

16
bin/cli
View File

@ -534,7 +534,7 @@ CLI.prototype.rpc = async function rpc() {
CLI.prototype.handleWallet = async function handleWallet() {
this.wallet = new Wallet({
uri: this.config.str(['url', 'uri']),
url: this.config.str(['url', 'uri']),
apiKey: this.config.str('api-key'),
network: this.config.str('network'),
id: this.config.str('id', 'primary'),
@ -693,7 +693,7 @@ CLI.prototype.handleWallet = async function handleWallet() {
CLI.prototype.handleNode = async function handleNode() {
this.client = new Client({
uri: this.config.str(['url', 'uri']),
url: this.config.str(['url', 'uri']),
apiKey: this.config.str('api-key'),
network: this.config.str('network')
});
@ -776,14 +776,12 @@ CLI.prototype.open = async function open() {
}
};
CLI.prototype.destroy = function destroy() {
if (this.wallet)
this.wallet.client.destroy();
CLI.prototype.destroy = async function destroy() {
if (this.wallet && this.wallet.opened)
await this.wallet.close();
if (this.client)
this.client.destroy();
return Promise.resolve();
if (this.client && this.client.opened)
await this.client.close();
};
(async () => {

View File

@ -1,3 +0,0 @@
'use strict';
exports.unsupported = true;

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +0,0 @@
'use strict';
exports.unsupported = true;

File diff suppressed because it is too large Load Diff

View File

@ -11,11 +11,7 @@
* @module http
*/
exports.Base = require('./base');
exports.Client = require('./client');
exports.request = require('./request');
exports.RPCBase = require('./rpcbase');
exports.RPCClient = require('./rpcclient');
exports.RPC = require('./rpc');
exports.Server = require('./server');
exports.Wallet = require('./wallet');

View File

@ -1,458 +0,0 @@
/*!
* request.js - http request for bcoin
* Copyright (c) 2014-2017, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
'use strict';
const assert = require('assert');
const EventEmitter = require('events');
const URL = require('url');
const qs = require('querystring');
const fetch = global.fetch;
const FetchHeaders = global.Headers;
/*
* Constants
*/
const USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1)'
+ ' AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.1 Safari/537.36';
/**
* Request Options
* @constructor
* @ignore
* @param {Object} options
*/
function RequestOptions(options) {
if (!(this instanceof RequestOptions))
return new RequestOptions(options);
this.uri = 'http://localhost:80/';
this.host = 'localhost';
this.path = '/';
this.port = 80;
this.ssl = false;
this.method = 'GET';
this.strictSSL = true;
this.agent = USER_AGENT;
this.type = null;
this.expect = null;
this.query = null;
this.body = null;
this.auth = null;
this.limit = 10 << 20;
this.timeout = 5000;
this.buffer = false;
if (options)
this.fromOptions(options);
}
RequestOptions.prototype.setURI = function setURI(uri) {
assert(typeof uri === 'string');
if (!/:\/\//.test(uri))
uri = (this.ssl ? 'https://' : 'http://') + uri;
uri = URL.parse(uri);
assert(uri.protocol === 'http:' || uri.protocol === 'https:');
this.uri = uri;
this.ssl = uri.protocol === 'https:';
if (uri.search)
this.query = qs.parse(uri.search);
this.host = uri.hostname;
this.path = uri.pathname;
this.port = uri.port || (this.ssl ? 443 : 80);
if (uri.auth) {
const parts = uri.auth.split(':');
this.auth = {
username: parts[0] || '',
password: parts[1] || ''
};
}
};
RequestOptions.prototype.fromOptions = function fromOptions(options) {
if (typeof options === 'string')
options = { uri: options };
if (options.ssl != null) {
assert(typeof options.ssl === 'boolean');
this.ssl = options.ssl;
}
if (options.uri != null)
this.setURI(options.uri);
if (options.url != null)
this.setURI(options.url);
if (options.method != null) {
assert(typeof options.method === 'string');
this.method = options.method.toUpperCase();
}
if (options.strictSSL != null) {
assert(typeof options.strictSSL === 'boolean');
this.strictSSL = options.strictSSL;
}
if (options.agent != null) {
assert(typeof options.agent === 'string');
this.agent = options.agent;
}
if (options.auth != null) {
assert(typeof options.auth === 'object');
assert(typeof options.auth.username === 'string');
assert(typeof options.auth.password === 'string');
this.auth = options.auth;
}
if (options.query != null) {
if (typeof options.query === 'string') {
this.query = qs.stringify(options.query);
} else {
assert(typeof options.query === 'object');
this.query = options.query;
}
}
if (options.json != null) {
assert(typeof options.json === 'object');
this.body = Buffer.from(JSON.stringify(options.json), 'utf8');
this.type = 'json';
}
if (options.form != null) {
assert(typeof options.form === 'object');
this.body = Buffer.from(qs.stringify(options.form), 'utf8');
this.type = 'form';
}
if (options.type != null) {
assert(typeof options.type === 'string');
assert(getType(options.type));
this.type = options.type;
}
if (options.expect != null) {
assert(typeof options.expect === 'string');
assert(getType(options.expect));
this.expect = options.expect;
}
if (options.body != null) {
if (typeof options.body === 'string') {
this.body = Buffer.from(options.body, 'utf8');
} else {
assert(Buffer.isBuffer(options.body));
this.body = options.body;
}
}
if (options.timeout != null) {
assert(typeof options.timeout === 'number');
this.timeout = options.timeout;
}
if (options.limit != null) {
assert(typeof options.limit === 'number');
this.limit = options.limit;
}
if (options.buffer != null) {
assert(typeof options.buffer === 'boolean');
this.buffer = options.buffer;
}
};
RequestOptions.prototype.isExpected = function isExpected(type) {
if (!this.expect)
return true;
return this.expect === type;
};
RequestOptions.prototype.isOverflow = function isOverflow(hdr) {
if (!hdr)
return false;
if (!this.buffer)
return false;
const length = parseInt(hdr, 10);
if (!isFinite(length))
return true;
return length > this.limit;
};
RequestOptions.prototype.getHeaders = function getHeaders() {
const headers = new FetchHeaders();
headers.append('User-Agent', this.agent);
if (this.type)
headers.append('Content-Type', getType(this.type));
if (this.body)
headers.append('Content-Length', this.body.length.toString(10));
if (this.auth) {
const auth = `${this.auth.username}:${this.auth.password}`;
const data = Buffer.from(auth, 'utf8');
headers.append('Authorization', `Basic ${data.toString('base64')}`);
}
return headers;
};
RequestOptions.prototype.toURL = function toURL() {
let url = '';
if (this.ssl)
url += 'https://';
else
url += 'http://';
url += this.host;
url += ':' + this.port;
url += this.path;
if (this.query)
url += '?' + qs.stringify(this.query);
return url;
};
RequestOptions.prototype.toHTTP = function toHTTP() {
return {
method: this.method,
headers: this.getHeaders(),
body: this.body.buffer,
mode: 'cors',
credentials: 'include',
cache: 'no-cache',
redirect: 'follow',
referrer: 'no-referrer'
};
};
/**
* Response
* @constructor
* @ignore
*/
function Response() {
this.statusCode = 0;
this.headers = Object.create(null);
this.type = 'bin';
this.body = null;
}
Response.fromFetch = function fromFetch(response) {
const res = new Response();
res.statusCode = response.status;
for (const [key, value] of response.headers.entries())
res.headers[key.toLowerCase()] = value;
const contentType = res.headers['content-type'];
res.type = parseType(contentType);
return res;
};
/**
* Make an HTTP request.
* @private
* @param {Object} options
* @returns {Promise}
*/
async function _request(options) {
if (typeof fetch !== 'function')
throw new Error('Fetch API not available.');
const opt = new RequestOptions(options);
const response = await fetch(opt.toURL(), opt.toHTTP());
const res = Response.fromFetch(response);
if (!opt.isExpected(res.type))
throw new Error('Wrong content-type for response.');
const length = res.headers['content-length'];
if (opt.isOverflow(length))
throw new Error('Response exceeded limit.');
if (opt.buffer) {
switch (res.type) {
case 'bin': {
const data = await response.arrayBuffer();
res.body = Buffer.from(data.buffer);
if (opt.limit && res.body.length > opt.limit)
throw new Error('Response exceeded limit.');
break;
}
case 'json': {
res.body = await response.json();
break;
}
case 'form': {
const data = await response.formData();
res.body = Object.create(null);
for (const [key, value] of data.entries())
res.body[key] = value;
break;
}
default: {
res.body = await response.text();
if (opt.limit && res.body.length > opt.limit)
throw new Error('Response exceeded limit.');
break;
}
}
} else {
res.body = await response.arrayBuffer();
}
return res;
}
/**
* Make an HTTP request.
* @alias module:http.request
* @param {Object} options
* @param {String} options.uri
* @param {Object?} options.query
* @param {Object?} options.body
* @param {Object?} options.json
* @param {Object?} options.form
* @param {String?} options.type - One of `"json"`,
* `"form"`, `"text"`, or `"bin"`.
* @param {String?} options.agent - User agent string.
* @param {Object?} [options.strictSSL=true] - Whether to accept bad certs.
* @param {Object?} options.method - HTTP method.
* @param {Object?} options.auth
* @param {String?} options.auth.username
* @param {String?} options.auth.password
* @param {String?} options.expect - Type to expect (see options.type).
* Error will be returned if the response is not of this type.
* @param {Number?} options.limit - Byte limit on response.
* @returns {Promise}
*/
async function request(options) {
if (typeof options === 'string')
options = { uri: options };
options.buffer = true;
return _request(options);
}
request.stream = function stream(options) {
const s = new EventEmitter();
s.write = (data) => {
options.body = data;
return true;
};
s.end = () => {
_request(options).then((res) => {
s.emit('headers', res.headers);
s.emit('type', res.type);
s.emit('response', res);
s.emit('data', res.body);
s.emit('end');
s.emit('close');
}).catch((err) => {
s.emit('error', err);
});
return true;
};
return s;
};
/*
* Helpers
*/
function parseType(hdr) {
let type = hdr || '';
type = type.split(';')[0];
type = type.toLowerCase();
type = type.trim();
switch (type) {
case 'text/x-json':
case 'application/json':
return 'json';
case 'application/x-www-form-urlencoded':
return 'form';
case 'text/html':
case 'application/xhtml+xml':
return 'html';
case 'text/xml':
case 'application/xml':
return 'xml';
case 'text/javascript':
case 'application/javascript':
return 'js';
case 'text/css':
return 'css';
case 'text/plain':
return 'txt';
case 'application/octet-stream':
return 'bin';
default:
return 'bin';
}
}
function getType(type) {
switch (type) {
case 'json':
return 'application/json; charset=utf-8';
case 'form':
return 'application/x-www-form-urlencoded; charset=utf-8';
case 'html':
return 'text/html; charset=utf-8';
case 'xml':
return 'application/xml; charset=utf-8';
case 'js':
return 'application/javascript; charset=utf-8';
case 'css':
return 'text/css; charset=utf-8';
case 'txt':
return 'text/plain; charset=utf-8';
case 'bin':
return 'application/octet-stream';
default:
throw new Error(`Unknown type: ${type}.`);
}
}
/*
* Expose
*/
module.exports = request;

View File

@ -1,672 +0,0 @@
/*!
* request.js - http request for bcoin
* Copyright (c) 2014-2017, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
'use strict';
const assert = require('assert');
const {Stream} = require('stream');
/*
* Lazily Loaded
*/
let url = null;
let qs = null;
let http = null;
let https = null;
let StringDecoder = null;
/*
* Constants
*/
const USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1)'
+ ' AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.1 Safari/537.36';
/**
* Request Options
* @constructor
* @ignore
* @param {Object} options
*/
function RequestOptions(options) {
if (!(this instanceof RequestOptions))
return new RequestOptions(options);
this.uri = 'http://localhost:80/';
this.host = 'localhost';
this.path = '/';
this.port = 80;
this.ssl = false;
this.method = 'GET';
this.strictSSL = true;
this.pool = false;
this.agent = USER_AGENT;
this.type = null;
this.expect = null;
this.query = null;
this.body = null;
this.auth = null;
this.limit = 10 << 20;
this.maxRedirects = 5;
this.timeout = 5000;
this.buffer = false;
this.headers = null;
// Hack
ensureRequires();
if (options)
this.fromOptions(options);
}
RequestOptions.prototype.setURI = function setURI(uri) {
assert(typeof uri === 'string');
if (!/:\/\//.test(uri))
uri = (this.ssl ? 'https://' : 'http://') + uri;
uri = url.parse(uri);
assert(uri.protocol === 'http:' || uri.protocol === 'https:');
this.uri = uri;
this.ssl = uri.protocol === 'https:';
if (uri.search)
this.query = qs.parse(uri.search);
this.host = uri.hostname;
this.path = uri.pathname;
this.port = uri.port || (this.ssl ? 443 : 80);
if (uri.auth) {
const parts = uri.auth.split(':');
this.auth = {
username: parts[0] || '',
password: parts[1] || ''
};
}
};
RequestOptions.prototype.fromOptions = function fromOptions(options) {
if (typeof options === 'string')
options = { uri: options };
if (options.ssl != null) {
assert(typeof options.ssl === 'boolean');
this.ssl = options.ssl;
}
if (options.uri != null)
this.setURI(options.uri);
if (options.url != null)
this.setURI(options.url);
if (options.method != null) {
assert(typeof options.method === 'string');
this.method = options.method.toUpperCase();
}
if (options.strictSSL != null) {
assert(typeof options.strictSSL === 'boolean');
this.strictSSL = options.strictSSL;
}
if (options.pool != null) {
assert(typeof options.pool === 'boolean');
this.pool = options.pool;
}
if (options.agent != null) {
assert(typeof options.agent === 'string');
this.agent = options.agent;
}
if (options.auth != null) {
assert(typeof options.auth === 'object');
assert(typeof options.auth.username === 'string');
assert(typeof options.auth.password === 'string');
this.auth = options.auth;
}
if (options.query != null) {
if (typeof options.query === 'string') {
this.query = qs.stringify(options.query);
} else {
assert(typeof options.query === 'object');
this.query = options.query;
}
}
if (options.json != null) {
assert(typeof options.json === 'object');
this.body = Buffer.from(JSON.stringify(options.json), 'utf8');
this.type = 'json';
}
if (options.form != null) {
assert(typeof options.form === 'object');
this.body = Buffer.from(qs.stringify(options.form), 'utf8');
this.type = 'form';
}
if (options.type != null) {
assert(typeof options.type === 'string');
assert(getType(options.type));
this.type = options.type;
}
if (options.expect != null) {
assert(typeof options.expect === 'string');
assert(getType(options.expect));
this.expect = options.expect;
}
if (options.body != null) {
if (typeof options.body === 'string') {
this.body = Buffer.from(options.body, 'utf8');
} else {
assert(Buffer.isBuffer(options.body));
this.body = options.body;
}
}
if (options.timeout != null) {
assert(typeof options.timeout === 'number');
this.timeout = options.timeout;
}
if (options.limit != null) {
assert(typeof options.limit === 'number');
this.limit = options.limit;
}
if (options.maxRedirects != null) {
assert(typeof options.maxRedirects === 'number');
this.maxRedirects = options.maxRedirects;
}
if (options.buffer != null) {
assert(typeof options.buffer === 'boolean');
this.buffer = options.buffer;
}
if (options.headers != null) {
assert(typeof options.headers === 'object');
this.headers = options.headers;
}
};
RequestOptions.prototype.isExpected = function isExpected(type) {
if (!this.expect)
return true;
return this.expect === type;
};
RequestOptions.prototype.isOverflow = function isOverflow(hdr) {
if (!hdr)
return false;
if (!this.buffer)
return false;
const length = parseInt(hdr, 10);
if (!isFinite(length))
return true;
return length > this.limit;
};
RequestOptions.prototype.getBackend = function getBackend() {
ensureRequires(this.ssl);
return this.ssl ? https : http;
};
RequestOptions.prototype.getHeaders = function getHeaders() {
if (this.headers)
return this.headers;
const headers = Object.create(null);
headers['User-Agent'] = this.agent;
if (this.type)
headers['Content-Type'] = getType(this.type);
if (this.body)
headers['Content-Length'] = this.body.length.toString(10);
if (this.auth) {
const auth = `${this.auth.username}:${this.auth.password}`;
const data = Buffer.from(auth, 'utf8');
headers['Authorization'] = `Basic ${data.toString('base64')}`;
}
return headers;
};
RequestOptions.prototype.toHTTP = function toHTTP() {
let query = '';
if (this.query)
query = '?' + qs.stringify(this.query);
return {
method: this.method,
host: this.host,
port: this.port,
path: this.path + query,
headers: this.getHeaders(),
agent: this.pool ? null : false,
rejectUnauthorized: this.strictSSL
};
};
/**
* Request
* @alias module:http.Request
* @constructor
* @private
* @param {Object} options
*/
function Request(options) {
if (!(this instanceof Request))
return new Request(options);
Stream.call(this);
this.options = new RequestOptions(options);
this.request = null;
this.response = null;
this.statusCode = 0;
this.headers = null;
this.type = 'bin';
this.redirects = 0;
this.timeout = null;
this.finished = false;
this.onResponse = this._onResponse.bind(this);
this.onData = this._onData.bind(this);
this.onEnd = this._onEnd.bind(this);
this.total = 0;
this.decoder = null;
this.body = null;
this.buffer = null;
}
Object.setPrototypeOf(Request.prototype, Stream.prototype);
Request.prototype.startTimeout = function startTimeout() {
if (!this.options.timeout)
return;
this.timeout = setTimeout(() => {
this.finish(new Error('Request timed out.'));
}, this.options.timeout);
};
Request.prototype.stopTimeout = function stopTimeout() {
if (this.timeout != null) {
clearTimeout(this.timeout);
this.timeout = null;
}
};
Request.prototype.cleanup = function cleanup() {
this.stopTimeout();
if (this.request) {
this.request.removeListener('response', this.onResponse);
this.request.removeListener('error', this.onEnd);
this.request.addListener('error', () => {});
}
if (this.response) {
this.response.removeListener('data', this.onData);
this.response.removeListener('error', this.onEnd);
this.response.removeListener('end', this.onEnd);
this.response.addListener('error', () => {});
}
};
Request.prototype.close = function close() {
if (this.request) {
try {
this.request.abort();
} catch (e) {
;
}
}
if (this.response) {
try {
this.response.destroy();
} catch (e) {
;
}
}
this.cleanup();
this.request = null;
this.response = null;
};
Request.prototype.destroy = function destroy() {
this.close();
};
Request.prototype.start = function start() {
const backend = this.options.getBackend();
const options = this.options.toHTTP();
this.startTimeout();
this.request = backend.request(options);
this.response = null;
if (this.options.body)
this.request.write(this.options.body);
this.request.on('response', this.onResponse);
this.request.on('error', this.onEnd);
};
Request.prototype.write = function write(data) {
return this.request.write(data);
};
Request.prototype.end = function end() {
return this.request.end();
};
Request.prototype.finish = function finish(err) {
if (this.finished)
return;
this.finished = true;
if (err) {
this.destroy();
this.emit('error', err);
return;
}
this.cleanup();
if (this.options.buffer) {
assert(this.buffer != null);
switch (this.type) {
case 'bin': {
this.body = Buffer.concat(this.buffer);
this.buffer = null;
break;
}
case 'json': {
const buffer = this.buffer.trim();
this.buffer = null;
if (buffer.length === 0)
break;
let body;
try {
body = JSON.parse(buffer);
} catch (e) {
this.emit('error', e);
return;
}
if (!body || typeof body !== 'object') {
this.emit('error', new Error('JSON body is a non-object.'));
return;
}
this.body = body;
break;
}
case 'form': {
const buffer = this.buffer;
this.buffer = null;
try {
this.body = qs.parse(buffer);
} catch (e) {
this.emit('error', e);
return;
}
break;
}
default: {
this.body = this.buffer;
this.buffer = null;
break;
}
}
}
this.emit('end');
this.emit('close');
};
Request.prototype._onResponse = function _onResponse(response) {
const location = response.headers['location'];
if (location) {
if (++this.redirects > this.options.maxRedirects) {
this.finish(new Error('Too many redirects.'));
return;
}
this.close();
this.options.setURI(location);
this.start();
this.end();
return;
}
const contentType = response.headers['content-type'];
const type = parseType(contentType);
if (!this.options.isExpected(type)) {
this.finish(new Error('Wrong content-type for response.'));
return;
}
const length = response.headers['content-length'];
if (this.options.isOverflow(length)) {
this.finish(new Error('Response exceeded limit.'));
return;
}
this.response = response;
this.statusCode = response.statusCode;
this.headers = response.headers;
this.type = type;
this.response.on('data', this.onData);
this.response.on('error', this.onEnd);
this.response.on('end', this.onEnd);
this.emit('headers', response.headers);
this.emit('type', this.type);
this.emit('response', response);
if (this.options.buffer) {
if (this.type !== 'bin') {
this.decoder = new StringDecoder('utf8');
this.buffer = '';
} else {
this.buffer = [];
}
}
};
Request.prototype._onData = function _onData(data) {
this.total += data.length;
this.emit('data', data);
if (this.options.buffer) {
if (this.options.limit) {
if (this.total > this.options.limit) {
this.finish(new Error('Response exceeded limit.'));
return;
}
}
if (this.decoder) {
this.buffer += this.decoder.write(data);
return;
}
this.buffer.push(data);
}
};
Request.prototype._onEnd = function _onEnd(err) {
this.finish(err);
};
/**
* Make an HTTP request.
* @alias module:http.request
* @param {Object} options
* @param {String} options.uri
* @param {Object?} options.query
* @param {Object?} options.body
* @param {Object?} options.json
* @param {Object?} options.form
* @param {String?} options.type - One of `"json"`,
* `"form"`, `"text"`, or `"bin"`.
* @param {String?} options.agent - User agent string.
* @param {Object?} [options.strictSSL=true] - Whether to accept bad certs.
* @param {Object?} options.method - HTTP method.
* @param {Object?} options.auth
* @param {String?} options.auth.username
* @param {String?} options.auth.password
* @param {String?} options.expect - Type to expect (see options.type).
* Error will be returned if the response is not of this type.
* @param {Number?} options.limit - Byte limit on response.
* @returns {Promise}
*/
function request(options) {
if (typeof options === 'string')
options = { uri: options };
options.buffer = true;
return new Promise((resolve, reject) => {
const req = new Request(options);
req.on('error', err => reject(err));
req.on('end', () => resolve(req));
req.start();
req.end();
});
}
request.stream = function stream(options) {
const req = new Request(options);
req.start();
return req;
};
/*
* Helpers
*/
function parseType(hdr) {
let type = hdr || '';
type = type.split(';')[0];
type = type.toLowerCase();
type = type.trim();
switch (type) {
case 'text/x-json':
case 'application/json':
return 'json';
case 'application/x-www-form-urlencoded':
return 'form';
case 'text/html':
case 'application/xhtml+xml':
return 'html';
case 'text/xml':
case 'application/xml':
return 'xml';
case 'text/javascript':
case 'application/javascript':
return 'js';
case 'text/css':
return 'css';
case 'text/plain':
return 'txt';
case 'application/octet-stream':
return 'bin';
default:
return 'bin';
}
}
function getType(type) {
switch (type) {
case 'json':
return 'application/json; charset=utf-8';
case 'form':
return 'application/x-www-form-urlencoded; charset=utf-8';
case 'html':
return 'text/html; charset=utf-8';
case 'xml':
return 'application/xml; charset=utf-8';
case 'js':
return 'application/javascript; charset=utf-8';
case 'css':
return 'text/css; charset=utf-8';
case 'txt':
return 'text/plain; charset=utf-8';
case 'bin':
return 'application/octet-stream';
default:
throw new Error(`Unknown type: ${type}.`);
}
}
function ensureRequires(ssl) {
if (!url)
url = require('url');
if (!qs)
qs = require('querystring');
if (!http)
http = require('http');
if (ssl && !https)
https = require('https');
if (!StringDecoder)
StringDecoder = require('string_decoder').StringDecoder;
}
/*
* Expose
*/
module.exports = request;

File diff suppressed because it is too large Load Diff

View File

@ -1,308 +0,0 @@
/*!
* rpcbase.js - json rpc for bcoin.
* Copyright (c) 2014-2017, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
'use strict';
const assert = require('assert');
const EventEmitter = require('events');
/**
* JSON RPC
* @alias module:http.RPCBase
* @constructor
*/
function RPCBase() {
if (!(this instanceof RPCBase))
return new RPCBase();
EventEmitter.call(this);
this.calls = Object.create(null);
this.mounts = [];
}
Object.setPrototypeOf(RPCBase.prototype, EventEmitter.prototype);
/**
* RPC errors.
* @enum {Number}
* @default
*/
RPCBase.errors = {
// Standard JSON-RPC 2.0 errors
INVALID_REQUEST: -32600,
METHOD_NOT_FOUND: -32601,
INVALID_PARAMS: -32602,
INTERNAL_ERROR: -32603,
PARSE_ERROR: -32700,
// General application defined errors
MISC_ERROR: -1,
FORBIDDEN_BY_SAFE_MODE: -2,
TYPE_ERROR: -3,
INVALID_ADDRESS_OR_KEY: -5,
OUT_OF_MEMORY: -7,
INVALID_PARAMETER: -8,
DATABASE_ERROR: -20,
DESERIALIZATION_ERROR: -22,
VERIFY_ERROR: -25,
VERIFY_REJECTED: -26,
VERIFY_ALREADY_IN_CHAIN: -27,
IN_WARMUP: -28,
// Aliases for backward compatibility
TRANSACTION_ERROR: -25,
TRANSACTION_REJECTED: -26,
TRANSACTION_ALREADY_IN_CHAIN: -27,
// P2P client errors
CLIENT_NOT_CONNECTED: -9,
CLIENT_IN_INITIAL_DOWNLOAD: -10,
CLIENT_NODE_ALREADY_ADDED: -23,
CLIENT_NODE_NOT_ADDED: -24,
CLIENT_NODE_NOT_CONNECTED: -29,
CLIENT_INVALID_IP_OR_SUBNET: -30,
CLIENT_P2P_DISABLED: -31,
// Wallet errors
WALLET_ERROR: -4,
WALLET_INSUFFICIENT_FUNDS: -6,
WALLET_INVALID_ACCOUNT_NAME: -11,
WALLET_KEYPOOL_RAN_OUT: -12,
WALLET_UNLOCK_NEEDED: -13,
WALLET_PASSPHRASE_INCORRECT: -14,
WALLET_WRONG_ENC_STATE: -15,
WALLET_ENCRYPTION_FAILED: -16,
WALLET_ALREADY_UNLOCKED: -17
};
/**
* Magic string for signing.
* @const {String}
* @default
*/
RPCBase.MAGIC_STRING = 'Bitcoin Signed Message:\n';
/**
* Execute batched RPC calls.
* @param {Object|Object[]} body
* @param {Object} query
* @returns {Promise}
*/
RPCBase.prototype.call = async function call(body, query) {
let cmds = body;
let out = [];
let array = true;
if (!query)
query = {};
if (!Array.isArray(cmds)) {
cmds = [cmds];
array = false;
}
for (const cmd of cmds) {
if (!cmd || typeof cmd !== 'object') {
out.push({
result: null,
error: {
message: 'Invalid request.',
code: RPCBase.errors.INVALID_REQUEST
},
id: null
});
continue;
}
if (cmd.id && typeof cmd.id === 'object') {
out.push({
result: null,
error: {
message: 'Invalid ID.',
code: RPCBase.errors.INVALID_REQUEST
},
id: null
});
continue;
}
if (cmd.id == null)
cmd.id = null;
if (!cmd.params)
cmd.params = [];
if (typeof cmd.method !== 'string') {
out.push({
result: null,
error: {
message: 'Method not found.',
code: RPCBase.errors.METHOD_NOT_FOUND
},
id: cmd.id
});
continue;
}
if (!Array.isArray(cmd.params)) {
out.push({
result: null,
error: {
message: 'Invalid params.',
code: RPCBase.errors.INVALID_PARAMS
},
id: cmd.id
});
continue;
}
this.emit('call', cmd, query);
let result;
try {
result = await this.execute(cmd);
} catch (err) {
let code;
switch (err.type) {
case 'RPCError':
code = err.code;
break;
case 'ValidationError':
code = RPCBase.errors.TYPE_ERROR;
break;
case 'EncodingError':
code = RPCBase.errors.DESERIALIZATION_ERROR;
break;
case 'FundingError':
code = RPCBase.errors.WALLET_INSUFFICIENT_FUNDS;
break;
default:
code = RPCBase.errors.INTERNAL_ERROR;
this.emit('error', err);
break;
}
out.push({
result: null,
error: {
message: err.message,
code: code
},
id: cmd.id
});
continue;
}
if (result === undefined)
result = null;
out.push({
result: result,
error: null,
id: cmd.id
});
}
if (!array)
out = out[0];
return out;
};
/**
* Execute an RPC call.
* @private
* @param {Object} json
* @param {Boolean} help
* @returns {Promise}
*/
RPCBase.prototype.execute = async function execute(json, help) {
const func = this.calls[json.method];
if (!func) {
for (const mount of this.mounts) {
if (mount.calls[json.method])
return await mount.execute(json, help);
}
throw new RPCError(RPCBase.errors.METHOD_NOT_FOUND,
`Method not found: ${json.method}.`);
}
return func.call(this, json.params, help);
};
/**
* Add a custom RPC call.
* @param {String} name
* @param {Function} func
*/
RPCBase.prototype.add = function add(name, func) {
assert(typeof func === 'function', 'Handler must be a function.');
assert(!this.calls[name], 'Duplicate RPC call.');
this.calls[name] = func;
};
/**
* Mount another RPC object.
* @param {Object} rpc
*/
RPCBase.prototype.mount = function mount(rpc) {
assert(rpc, 'RPC must be an object.');
assert(typeof rpc.execute === 'function', 'Execute must be a method.');
this.mounts.push(rpc);
};
/**
* Attach to another RPC object.
* @param {Object} rpc
*/
RPCBase.prototype.attach = function attach(rpc) {
assert(rpc, 'RPC must be an object.');
assert(typeof rpc.execute === 'function', 'Execute must be a method.');
rpc.mount(this);
};
/**
* RPC Error
* @constructor
* @ignore
*/
function RPCError(code, msg) {
Error.call(this);
assert(typeof code === 'number');
assert(typeof msg === 'string');
this.type = 'RPCError';
this.message = msg;
this.code = code;
if (Error.captureStackTrace)
Error.captureStackTrace(this, RPCError);
}
Object.setPrototypeOf(RPCError.prototype, Error.prototype);
/*
* Expose
*/
exports = RPCBase;
exports.RPCError = RPCError;
module.exports = exports;

View File

@ -1,3 +0,0 @@
'use strict';
exports.unsupported = true;

View File

@ -1,101 +0,0 @@
/*!
* rpcclient.js - json rpc client for bcoin
* Copyright (c) 2014-2017, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
'use strict';
const Network = require('../protocol/network');
const request = require('./request');
/**
* Bcoin RPC client.
* @alias module:http.RPCClient
* @constructor
* @param {String} uri
* @param {Object?} options
*/
function RPCClient(options) {
if (!(this instanceof RPCClient))
return new RPCClient(options);
if (!options)
options = {};
if (typeof options === 'string')
options = { uri: options };
this.options = options;
this.network = Network.get(options.network);
this.uri = options.uri || `http://localhost:${this.network.rpcPort}`;
this.apiKey = options.apiKey;
this.id = 0;
}
/**
* Make a json rpc request.
* @private
* @param {String} method - RPC method name.
* @param {Array} params - RPC parameters.
* @returns {Promise} - Returns Object?.
*/
RPCClient.prototype.execute = async function execute(method, params) {
const res = await request({
method: 'POST',
uri: this.uri,
pool: true,
json: {
method: method,
params: params,
id: this.id++
},
auth: {
username: 'bitcoinrpc',
password: this.apiKey || ''
}
});
if (res.statusCode === 401)
throw new RPCError('Unauthorized (bad API key).', -1);
if (res.type !== 'json')
throw new Error('Bad response (wrong content-type).');
if (!res.body)
throw new Error('No body for JSON-RPC response.');
if (res.body.error)
throw new RPCError(res.body.error.message, res.body.error.code);
if (res.statusCode !== 200)
throw new Error(`Status code: ${res.statusCode}.`);
return res.body.result;
};
/*
* Helpers
*/
function RPCError(msg, code) {
Error.call(this);
this.type = 'RPCError';
this.message = String(msg);
this.code = code >>> 0;
if (Error.captureStackTrace)
Error.captureStackTrace(this, RPCError);
}
Object.setPrototypeOf(RPCError.prototype, Error.prototype);
/*
* Expose
*/
module.exports = RPCClient;

View File

@ -1,3 +0,0 @@
'use strict';
exports.unsupported = true;

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +0,0 @@
'use strict';
exports.unsupported = true;

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,7 @@
'use strict';
const request = require('../http/request');
const breq = require('breq');
const IP = require('../utils/ip');
/**
@ -23,14 +23,14 @@ const external = exports;
external.getIPv4 = async function getIPv4() {
try {
const res = await request({
const res = await breq({
method: 'GET',
uri: 'http://ipv4.icanhazip.com',
url: 'http://ipv4.icanhazip.com',
expect: 'txt',
timeout: 2000
});
const str = res.body.trim();
const str = res.text().trim();
const raw = IP.toBuffer(str);
if (!IP.isIPv4(raw))
@ -50,14 +50,14 @@ external.getIPv4 = async function getIPv4() {
*/
external.getIPv42 = async function getIPv42() {
const res = await request({
const res = await breq({
method: 'GET',
uri: 'http://checkip.dyndns.org',
url: 'http://checkip.dyndns.org',
expect: 'html',
timeout: 2000
});
const match = /IP Address:\s*([0-9a-f.:]+)/i.exec(res.body);
const match = /IP Address:\s*([0-9a-f.:]+)/i.exec(res.text());
if (!match)
throw new Error('Could not find IPv4.');
@ -78,14 +78,14 @@ external.getIPv42 = async function getIPv42() {
*/
external.getIPv6 = async function getIPv6() {
const res = await request({
const res = await breq({
method: 'GET',
uri: 'http://ipv6.icanhazip.com',
url: 'http://ipv6.icanhazip.com',
expect: 'txt',
timeout: 2000
});
const str = res.body.trim();
const str = res.text().trim();
const raw = IP.toBuffer(str);
if (!IP.isIPv6(raw))

View File

@ -9,7 +9,7 @@
const assert = require('assert');
const dgram = require('dgram');
const url = require('url');
const request = require('../http/request');
const breq = require('breq');
const co = require('../utils/co');
const Lock = require('../utils/lock');
const IP = require('../utils/ip');
@ -220,9 +220,9 @@ UPNP.prototype.resolve = async function resolve(location, targets) {
if (!targets)
targets = UPNP.WAN_SERVICES;
const res = await request({
const res = await breq({
method: 'GET',
uri: location,
url: location,
timeout: UPNP.RESPONSE_TIMEOUT,
expect: 'xml'
});
@ -368,9 +368,9 @@ UPNPService.prototype.soapRequest = async function soapRequest(action, args) {
const type = this.serviceType;
const req = this.createRequest(action, args);
const res = await request({
const res = await breq({
method: 'POST',
uri: this.controlURL,
url: this.controlURL,
timeout: UPNP.RESPONSE_TIMEOUT,
expect: 'xml',
headers: {

View File

@ -137,21 +137,19 @@ function FullNode(options) {
this.rpc = new RPC(this);
// HTTP needs access to the node.
if (!HTTPServer.unsupported) {
this.http = new HTTPServer({
network: this.network,
logger: this.logger,
node: this,
prefix: this.config.prefix,
ssl: this.config.bool('ssl'),
keyFile: this.config.path('ssl-key'),
certFile: this.config.path('ssl-cert'),
host: this.config.str('http-host'),
port: this.config.uint('http-port'),
apiKey: this.config.str('api-key'),
noAuth: this.config.bool('no-auth')
});
}
this.http = new HTTPServer({
network: this.network,
logger: this.logger,
node: this,
prefix: this.config.prefix,
ssl: this.config.bool('ssl'),
keyFile: this.config.path('ssl-key'),
certFile: this.config.path('ssl-cert'),
host: this.config.str('http-host'),
port: this.config.uint('http-port'),
apiKey: this.config.str('api-key'),
noAuth: this.config.bool('no-auth')
});
this._init();
}

View File

@ -572,15 +572,16 @@ Block.prototype.toJSON = function toJSON() {
* @param {Network} network
* @param {CoinView} view
* @param {Number} height
* @param {Number} depth
* @returns {Object}
*/
Block.prototype.getJSON = function getJSON(network, view, height, confirmations) {
Block.prototype.getJSON = function getJSON(network, view, height, depth) {
network = Network.get(network);
return {
hash: this.rhash(),
height: height,
confirmations: confirmations,
depth: depth,
version: this.version,
prevBlock: util.revHex(this.prevBlock),
merkleRoot: util.revHex(this.merkleRoot),

View File

@ -1,3 +0,0 @@
'use strict';
exports.unsupported = true;

View File

@ -7,325 +7,207 @@
'use strict';
const IOClient = require('socket.io-client');
const Network = require('../protocol/network');
const AsyncObject = require('../utils/asyncobject');
const {Client} = require('bcurl');
const TX = require('../primitives/tx');
const {BlockMeta} = require('./records');
const Headers = require('../primitives/headers');
const util = require('../utils/util');
const BufferReader = require('../utils/reader');
/**
* Bcoin HTTP client.
* @alias module:wallet.WalletClient
* @constructor
* @param {Object|String} options
*/
class WalletClient extends Client {
/**
* Bcoin HTTP client.
* @alias module:wallet.WalletClient
* @constructor
* @param {Object|String} options
*/
function WalletClient(options) {
if (!(this instanceof WalletClient))
return new WalletClient(options);
constructor(options) {
super(options);
}
if (!options)
options = {};
/**
* Open the client, wait for socket to connect.
* @returns {Promise}
*/
if (typeof options === 'string')
options = { uri: options };
async open() {
await super.open();
AsyncObject.call(this);
this.on('error', (err) => {
this.emit('error', err);
});
this.options = options;
this.network = Network.get(options.network);
this.listen('block connect', (entry, txs) => {
this.emit('block connect', ...parseBlock(entry, txs));
});
this.uri = options.uri || `http://localhost:${this.network.rpcPort}`;
this.apiKey = options.apiKey;
this.listen('block disconnect', (entry) => {
this.emit('block disconnect', parseEntry(entry));
});
this.socket = null;
}
this.listen('block rescan', (entry, txs) => {
this.emit('block rescan', ...parseBlock(entry, txs));
});
Object.setPrototypeOf(WalletClient.prototype, AsyncObject.prototype);
this.listen('chain reset', (tip) => {
this.emit('chain reset', parseEntry(tip));
});
/**
* Open the client, wait for socket to connect.
* @alias WalletClient#open
* @returns {Promise}
*/
this.listen('tx', (tx) => {
this.emit('tx', TX.fromRaw(tx));
});
WalletClient.prototype._open = async function _open() {
this.socket = new IOClient(this.uri, {
transports: ['websocket'],
forceNew: true
});
await this.watchChain();
await this.watchMempool();
}
this.socket.on('error', (err) => {
this.emit('error', err);
});
/**
* Auth with server.
* @private
* @returns {Promise}
*/
this.socket.on('version', (info) => {
if (info.network !== this.network.type)
this.emit('error', new Error('Wrong network.'));
});
auth() {
return this.call('auth', this.password);
}
this.socket.on('block connect', (entry, txs) => {
let block;
/**
* Make an RPC call.
* @returns {Promise}
*/
try {
block = parseBlock(entry, txs);
} catch (e) {
this.emit('error', e);
return;
}
execute(name, params) {
return super.execute('/', name, params);
}
this.emit('block connect', block.entry, block.txs);
});
/**
* Watch the blockchain.
* @private
* @returns {Promise}
*/
this.socket.on('block disconnect', (entry) => {
let block;
watchChain() {
return this.call('watch chain');
}
try {
block = parseEntry(entry);
} catch (e) {
this.emit('error', e);
return;
}
/**
* Watch the blockchain.
* @private
* @returns {Promise}
*/
this.emit('block disconnect', block);
});
watchMempool() {
return this.call('watch mempool');
}
this.socket.on('block rescan', (entry, txs, cb) => {
let block;
/**
* Get chain tip.
* @returns {Promise}
*/
try {
block = parseBlock(entry, txs);
} catch (e) {
this.emit('error', e);
cb();
return;
}
async getTip() {
const raw = await this.call('get tip');
return parseEntry(raw);
}
this.fire('block rescan', block.entry, block.txs).then(cb, cb);
});
/**
* Get chain entry.
* @param {Hash} hash
* @returns {Promise}
*/
this.socket.on('chain reset', (tip) => {
let block;
try {
block = parseEntry(tip);
} catch (e) {
this.emit('error', e);
return;
}
this.emit('chain reset', block);
});
this.socket.on('tx', (tx) => {
try {
tx = parseTX(tx);
} catch (e) {
this.emit('error', e);
return;
}
this.emit('tx', tx);
});
await this.onConnect();
await this.sendAuth();
await this.watchChain();
await this.watchMempool();
};
/**
* Close the client, wait for the socket to close.
* @alias WalletClient#close
* @returns {Promise}
*/
WalletClient.prototype._close = function _close() {
if (!this.socket)
return Promise.resolve();
this.socket.disconnect();
this.socket = null;
return Promise.resolve();
};
/**
* Wait for websocket connection.
* @private
* @returns {Promise}
*/
WalletClient.prototype.onConnect = function onConnect() {
return new Promise((resolve, reject) => {
this.socket.once('connect', resolve);
});
};
/**
* Wait for websocket auth.
* @private
* @returns {Promise}
*/
WalletClient.prototype.sendAuth = function sendAuth() {
return new Promise((resolve, reject) => {
this.socket.emit('auth', this.apiKey, wrap(resolve, reject));
});
};
/**
* Watch the blockchain.
* @private
* @returns {Promise}
*/
WalletClient.prototype.watchChain = function watchChain() {
return new Promise((resolve, reject) => {
this.socket.emit('watch chain', wrap(resolve, reject));
});
};
/**
* Watch the blockchain.
* @private
* @returns {Promise}
*/
WalletClient.prototype.watchMempool = function watchMempool() {
return new Promise((resolve, reject) => {
this.socket.emit('watch mempool', wrap(resolve, reject));
});
};
/**
* Get chain tip.
* @returns {Promise}
*/
WalletClient.prototype.getTip = function getTip() {
return new Promise((resolve, reject) => {
this.socket.emit('get tip', wrap(resolve, reject, parseEntry));
});
};
/**
* Get chain entry.
* @param {Hash} hash
* @returns {Promise}
*/
WalletClient.prototype.getEntry = function getEntry(block) {
return new Promise((resolve, reject) => {
async getEntry(block) {
if (typeof block === 'string')
block = util.revHex(block);
this.socket.emit('get entry', block, wrap(resolve, reject, parseEntry));
});
};
const raw = await this.call('get entry', block);
return parseEntry(raw);
}
/**
* Get hashes.
* @param {Number} [start=-1]
* @param {Number} [end=-1]
* @returns {Promise}
*/
/**
* Get hashes.
* @param {Number} [start=-1]
* @param {Number} [end=-1]
* @returns {Promise}
*/
WalletClient.prototype.getHashes = function getHashes(start = -1, end = -1) {
return new Promise((resolve, reject) => {
this.socket.emit('get hashes', start, end, wrap(resolve, reject));
});
};
getHashes(start = -1, end = -1) {
return this.call('get hashes', start, end);
}
/**
* Send a transaction. Do not wait for promise.
* @param {TX} tx
* @returns {Promise}
*/
/**
* Send a transaction. Do not wait for promise.
* @param {TX} tx
* @returns {Promise}
*/
WalletClient.prototype.send = function send(tx) {
return new Promise((resolve, reject) => {
this.socket.emit('send', tx.toRaw(), wrap(resolve, reject));
});
};
send(tx) {
return this.call('send', tx.toRaw());
}
/**
* Set bloom filter.
* @param {Bloom} filter
* @returns {Promise}
*/
/**
* Set bloom filter.
* @param {Bloom} filter
* @returns {Promise}
*/
WalletClient.prototype.setFilter = function setFilter(filter) {
return new Promise((resolve, reject) => {
this.socket.emit('set filter', filter.toRaw(), wrap(resolve, reject));
});
};
setFilter(filter) {
return this.call('set filter', filter.toRaw());
}
/**
* Add data to filter.
* @param {Buffer} data
* @returns {Promise}
*/
/**
* Add data to filter.
* @param {Buffer} data
* @returns {Promise}
*/
WalletClient.prototype.addFilter = function addFilter(chunks) {
if (!Array.isArray(chunks))
chunks = [chunks];
addFilter(chunks) {
if (!Array.isArray(chunks))
chunks = [chunks];
return new Promise((resolve, reject) => {
this.socket.emit('add filter', chunks, wrap(resolve, reject));
});
};
return this.call('add filter', chunks);
}
/**
* Reset filter.
* @returns {Promise}
*/
/**
* Reset filter.
* @returns {Promise}
*/
WalletClient.prototype.resetFilter = function resetFilter() {
return new Promise((resolve, reject) => {
this.socket.emit('reset filter', wrap(resolve, reject));
});
};
resetFilter() {
return this.call('reset filter');
}
/**
* Esimate smart fee.
* @param {Number?} blocks
* @returns {Promise}
*/
/**
* Esimate smart fee.
* @param {Number?} blocks
* @returns {Promise}
*/
WalletClient.prototype.estimateFee = function estimateFee(blocks) {
return new Promise((resolve, reject) => {
this.socket.emit('estimate fee', blocks, wrap(resolve, reject));
});
};
estimateFee(blocks) {
return this.call('estimate fee', blocks);
}
/**
* Rescan for any missed transactions.
* @param {Number|Hash} start - Start block.
* @param {Bloom} filter
* @param {Function} iter - Iterator.
* @returns {Promise}
*/
/**
* Rescan for any missed transactions.
* @param {Number|Hash} start - Start block.
* @param {Bloom} filter
* @param {Function} iter - Iterator.
* @returns {Promise}
*/
WalletClient.prototype.rescan = function rescan(start) {
return new Promise((resolve, reject) => {
rescan(start) {
if (typeof start === 'string')
start = util.revHex(start);
this.socket.emit('rescan', start, wrap(resolve, reject));
});
};
return this.call('rescan', start);
}
}
/*
* Helpers
*/
function parseEntry(data, enc) {
if (typeof data === 'string')
data = Buffer.from(data, 'hex');
function parseEntry(data) {
const block = Headers.fromHead(data);
const br = new BufferReader(data);
@ -334,7 +216,7 @@ function parseEntry(data, enc) {
const height = br.readU32();
const hash = block.hash('hex');
return new BlockMeta(hash, height, block.time);
return { hash, height, time: block.time };
}
function parseBlock(entry, txs) {
@ -342,48 +224,11 @@ function parseBlock(entry, txs) {
const out = [];
for (const raw of txs) {
const tx = parseTX(raw);
const tx = TX.fromRaw(raw);
out.push(tx);
}
return new BlockResult(block, out);
}
function parseTX(data) {
return TX.fromRaw(data, 'hex');
}
function BlockResult(entry, txs) {
this.entry = entry;
this.txs = txs;
}
function wrap(resolve, reject, parse) {
return function(err, result) {
if (err) {
reject(new Error(err.message));
return;
}
if (!result) {
resolve(null);
return;
}
if (!parse) {
resolve(result);
return;
}
try {
result = parse(result);
} catch (e) {
reject(e);
return;
}
resolve(result);
};
return [block, out];
}
/*

View File

@ -1,3 +0,0 @@
'use strict';
exports.unsupported = true;

File diff suppressed because it is too large Load Diff

View File

@ -56,10 +56,7 @@ plugin.init = function init(node) {
listen: false
});
if (node.http && wdb.http)
wdb.http.attach(node.http);
wdb.rpc.attach(node.rpc);
wdb.http.attach('/wallet', node.http);
return wdb;
};

File diff suppressed because it is too large Load Diff

View File

@ -62,22 +62,19 @@ function WalletDB(options) {
this.db = LDB(this.options);
this.rpc = new RPC(this);
this.primary = null;
this.http = null;
if (!HTTPServer.unsupported) {
this.http = new HTTPServer({
walletdb: this,
network: this.network,
logger: this.logger,
prefix: this.options.prefix,
apiKey: this.options.apiKey,
walletAuth: this.options.walletAuth,
noAuth: this.options.noAuth,
host: this.options.host,
port: this.options.port,
ssl: this.options.ssl
});
}
this.http = new HTTPServer({
walletdb: this,
network: this.network,
logger: this.logger,
prefix: this.options.prefix,
apiKey: this.options.apiKey,
walletAuth: this.options.walletAuth,
noAuth: this.options.noAuth,
host: this.options.host,
port: this.options.port,
ssl: this.options.ssl
});
this.state = new ChainState();
this.height = 0;

View File

@ -14,6 +14,8 @@ const MTX = require('../lib/primitives/mtx');
const HTTP = require('../lib/http');
const FullNode = require('../lib/node/fullnode');
const pkg = require('../lib/pkg');
const Network = require('../lib/protocol/network');
const network = Network.get('regtest');
const node = new FullNode({
network: 'regtest',
@ -24,8 +26,13 @@ const node = new FullNode({
plugins: [require('../lib/wallet/plugin')]
});
const client = new HTTP.Client({
port: network.rpcPort,
apiKey: 'foo'
});
const wallet = new HTTP.Wallet({
network: 'regtest',
port: network.rpcPort,
apiKey: 'foo'
});
@ -40,6 +47,7 @@ describe('HTTP', function() {
it('should open node', async () => {
consensus.COINBASE_MATURITY = 0;
await node.open();
await client.open();
});
it('should create wallet', async () => {
@ -48,7 +56,7 @@ describe('HTTP', function() {
});
it('should get info', async () => {
const info = await wallet.client.getInfo();
const info = await client.getInfo();
assert.strictEqual(info.network, node.network.type);
assert.strictEqual(info.version, pkg.version);
assert.typeOf(info.pool, 'object');
@ -154,12 +162,12 @@ describe('HTTP', function() {
});
it('should execute an rpc call', async () => {
const info = await wallet.client.rpc.execute('getblockchaininfo', []);
const info = await client.execute('getblockchaininfo', []);
assert.strictEqual(info.blocks, 0);
});
it('should execute an rpc call with bool parameter', async () => {
const info = await wallet.client.rpc.execute('getrawmempool', [true]);
const info = await client.execute('getrawmempool', [true]);
assert.deepStrictEqual(info, {});
});
@ -188,7 +196,7 @@ describe('HTTP', function() {
});
it('should get a block template', async () => {
const json = await wallet.client.rpc.execute('getblocktemplate', []);
const json = await client.execute('getblocktemplate', []);
assert.deepStrictEqual(json, {
capabilities: ['proposal'],
mutable: ['time', 'transactions', 'prevblock'],
@ -223,7 +231,7 @@ describe('HTTP', function() {
const attempt = await node.miner.createBlock();
const block = attempt.toBlock();
const hex = block.toRaw().toString('hex');
const json = await wallet.client.rpc.execute('getblocktemplate', [{
const json = await client.execute('getblocktemplate', [{
mode: 'proposal',
data: hex
}]);
@ -231,7 +239,7 @@ describe('HTTP', function() {
});
it('should validate an address', async () => {
const json = await wallet.client.rpc.execute('validateaddress', [
const json = await client.execute('validateaddress', [
addr.toString(node.network)
]);
assert.deepStrictEqual(json, {
@ -246,6 +254,7 @@ describe('HTTP', function() {
it('should cleanup', async () => {
consensus.COINBASE_MATURITY = 100;
await wallet.close();
await client.close();
await node.close();
});
});