Skip to content
Snippets Groups Projects
Commit 10d605e1 authored by Jason Salyers's avatar Jason Salyers
Browse files

[JES] Add automatic failover capability

parent 36e75cd3
No related branches found
No related tags found
2 merge requests!2Fail Over Capability,!1Automatic Fail Over
{ {
"transport": "http", "transport": "http",
"websocket": "wss://api.hive.blog:8090", "websocket": "wss://api.hive.blog:8090",
"uri": "https://anyx.io", "uri": "https://api.hive.blog",
"url": "https://anyx.io", "url": "https://api.hive.blog",
"dev_uri": "https://api.steemitdev.com", "dev_uri": "",
"stage_uri": "https://api.steemitstage.com", "stage_uri": "",
"address_prefix": "STM", "address_prefix": "STM",
"chain_id": "0000000000000000000000000000000000000000000000000000000000000000", "chain_id": "0000000000000000000000000000000000000000000000000000000000000000",
"alternative_api_endpoints": ["https://api.hive.blog", "https://anyx.io"], "alternative_api_endpoints": ["https://api.hive.blog", "https://anyx.io"],
......
{ {
"name": "hive-js-dev", "name": "@hiveio/hive-js",
"version": "0.0.9", "version": "0.0.2",
"description": "Steem.js the JavaScript API for Steem blockchain", "description": "Hive.js the JavaScript API for Hive blockchain",
"main": "lib/index.js", "main": "lib/index.js",
"scripts": { "scripts": {
"test": "eslint --quiet src test; mocha -t 40000 --require babel-polyfill --require babel-register", "test": "eslint --quiet src test; mocha -t 40000 --require babel-polyfill --require babel-register",
......
...@@ -27,8 +27,10 @@ class Steem extends EventEmitter { ...@@ -27,8 +27,10 @@ class Steem extends EventEmitter {
this._setLogger(options); this._setLogger(options);
this.options = options; this.options = options;
this.seqNo = 0; // used for rpc calls this.seqNo = 0; // used for rpc calls
this.errorCount = 0; this.error_count = 0;
this.apiIndex = 0; this.api_index = 0;
this.error_threshold = 3;
this.alternative_api_endpoints = ['https://api.hive.blog', 'https://anyx.io'];
methods.forEach(method => { methods.forEach(method => {
const methodName = method.method_name || camelCase(method.method); const methodName = method.method_name || camelCase(method.method);
const methodParams = method.params || []; const methodParams = method.params || [];
...@@ -184,6 +186,12 @@ class Steem extends EventEmitter { ...@@ -184,6 +186,12 @@ class Steem extends EventEmitter {
setOptions(options) { setOptions(options) {
Object.assign(this.options, options); Object.assign(this.options, options);
if (options.hasOwnProperty('failover_threshold'))
this.failover_threshold = options.failover_threshold;
if (options.hasOwnProperty('alternative_api_endpoints'))
this.alternative_api_endpoints = options.alternative_api_endpoints;
this._setLogger(options); this._setLogger(options);
this._setTransport(options); this._setTransport(options);
this.transport.setOptions(options); this.transport.setOptions(options);
...@@ -191,35 +199,22 @@ class Steem extends EventEmitter { ...@@ -191,35 +199,22 @@ class Steem extends EventEmitter {
{ {
config.set( 'address_prefix', options.useTestNet ? 'TST' : 'STM' ) config.set( 'address_prefix', options.useTestNet ? 'TST' : 'STM' )
} }
if (options.hasOwnProperty('failover_threshold'))
{
config.set('failover_threshold', options.failover_threshold);
}
if (options.hasOwnProperty('alternative_api_endpoints'))
{
config.set('alternative_api_endpoints', options.alternative_api_endpoints);
}
if (options.hasOwnProperty('url')) if (options.hasOwnProperty('url'))
{ {
if (this.options.alternative_api_endpoints === undefined || this.options.alternative_api_endpoints === null) let new_index = 0;
{ for (var i = 0; i < this.alternative_api_endpoints.length; i++)
console.log("no alternative api endpoints found, can't update the index");
}
let index = 0;
for (var i = 0; i < this.options.alternative_api_endpoints.length; i++)
{ {
if (this.options.url === this.options.alternative_api_endpoints[i]) let temp_endpoint = this.alternative_api_endpoints[i];
if (temp_endpoint === options.url)
{ {
index = i; new_index = i;
break; break;
} }
} }
this.apiIndex = index; this.api_index = new_index;
console.log("updated apiIndex to be ", this.apiIndex); let new_endpoint = this.alternative_api_endpoints[this.api_index];
} }
console.log("done setting options. new options are: ", this.options);
console.log("does failover_threshold still exist? ", this.options.failover_threshold === 'undefined' ? "no" : "yes");
} }
setWebSocket(url) { setWebSocket(url) {
...@@ -382,26 +377,31 @@ class Steem extends EventEmitter { ...@@ -382,26 +377,31 @@ class Steem extends EventEmitter {
notifyError(err, ignore=false) notifyError(err, ignore=false)
{ {
this.errorCount++;
if (ignore) if (ignore)
{ {
return; return;
} }
if (this.options.failover_threshold === 'undefined') if (this.failover_threshold === undefined || this.alternative_api_endpoints === undefined)
{
return;
}
if (err && err.toString().includes("overseer"))
{ {
console.log("no failover options are listed, can't failover"); //overseer was a steem thing, it doesn't exist in hive so don't count this error towards failover
return; return;
} }
if (this.errorCount >= this.options.failover_threshold) this.error_count++;
if (this.error_count >= this.failover_threshold)
{ {
console.log("failing over"); let current_url = this.options.url;
this.errorCount = 0; this.error_count = 0;
this.apiIndex++; this.api_index++;
if (this.apiIndex >= this.options.alternative_api_endpoints.length) if (this.api_index >= this.alternative_api_endpoints.length)
{ {
this.apiIndex = 0; this.api_index = 0;
} }
let nextEndpoint = this.options.alternative_api_endpoints[this.apiIndex]; let nextEndpoint = this.alternative_api_endpoints[this.api_index];
console.log("failing over. old endpoint was: ", current_url, " new one is: ", nextEndpoint);
this.setOptions({url: nextEndpoint}); this.setOptions({url: nextEndpoint});
} }
} }
......
...@@ -45,7 +45,6 @@ export function jsonRpc(uri, {method, id, params, fetchMethod=fetch}) { ...@@ -45,7 +45,6 @@ export function jsonRpc(uri, {method, id, params, fetchMethod=fetch}) {
throw new Error(`Invalid response id: ${ rpcRes.id }`); throw new Error(`Invalid response id: ${ rpcRes.id }`);
} }
if (rpcRes.error) { if (rpcRes.error) {
console.log("rcpRes error means rpc threw an error. uri, payload are: ", uri, payload);
throw new RPCError(rpcRes.error); throw new RPCError(rpcRes.error);
} }
return rpcRes.result return rpcRes.result
......
import each from 'lodash/each';
const defaultConfig = require('../config.json');
class Config {
constructor(c) {
each(c, (value, key) => {
this[key] = value;
});
}
get(k) {
return this[k];
}
set(k, v) {
this[k] = v;
}
}
module.exports = new Config(defaultConfig);
if(typeof module.exports.Config !== 'undefined') {
throw new Error("default config.json file may not contain a property 'Config'");
}
module.exports.Config = Config;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment