Unsubscribe error on ShapeShift modal close (#4005)
* unsubscribe in onClose (state available) * Revert "unsubscribe in onClose (state available)" This reverts commit 1da0a7447563e3cb0d9149b0b9898ec93b483982. * Fix shapeshift double unsubscribe * Swap multiple list test addresses
This commit is contained in:
parent
63017268ad
commit
7cdfaf1a43
18
js/src/3rdparty/shapeshift/helpers.spec.js
vendored
18
js/src/3rdparty/shapeshift/helpers.spec.js
vendored
@ -16,16 +16,10 @@
|
|||||||
|
|
||||||
const nock = require('nock');
|
const nock = require('nock');
|
||||||
|
|
||||||
const ShapeShift = require('./');
|
|
||||||
const initShapeshift = (ShapeShift.default || ShapeShift);
|
|
||||||
|
|
||||||
const APIKEY = '0x123454321';
|
const APIKEY = '0x123454321';
|
||||||
|
|
||||||
const shapeshift = initShapeshift(APIKEY);
|
function mockget (shapeshift, requests) {
|
||||||
const rpc = shapeshift.getRpc();
|
let scope = nock(shapeshift.getRpc().ENDPOINT);
|
||||||
|
|
||||||
function mockget (requests) {
|
|
||||||
let scope = nock(rpc.ENDPOINT);
|
|
||||||
|
|
||||||
requests.forEach((request) => {
|
requests.forEach((request) => {
|
||||||
scope = scope
|
scope = scope
|
||||||
@ -38,8 +32,8 @@ function mockget (requests) {
|
|||||||
return scope;
|
return scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
function mockpost (requests) {
|
function mockpost (shapeshift, requests) {
|
||||||
let scope = nock(rpc.ENDPOINT);
|
let scope = nock(shapeshift.getRpc().ENDPOINT);
|
||||||
|
|
||||||
requests.forEach((request) => {
|
requests.forEach((request) => {
|
||||||
scope = scope
|
scope = scope
|
||||||
@ -58,7 +52,5 @@ function mockpost (requests) {
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
APIKEY,
|
APIKEY,
|
||||||
mockget,
|
mockget,
|
||||||
mockpost,
|
mockpost
|
||||||
shapeshift,
|
|
||||||
rpc
|
|
||||||
};
|
};
|
||||||
|
19
js/src/3rdparty/shapeshift/rpc.spec.js
vendored
19
js/src/3rdparty/shapeshift/rpc.spec.js
vendored
@ -16,12 +16,21 @@
|
|||||||
|
|
||||||
const helpers = require('./helpers.spec.js');
|
const helpers = require('./helpers.spec.js');
|
||||||
|
|
||||||
const APIKEY = helpers.APIKEY;
|
const ShapeShift = require('./');
|
||||||
|
const initShapeshift = (ShapeShift.default || ShapeShift);
|
||||||
|
|
||||||
const mockget = helpers.mockget;
|
const mockget = helpers.mockget;
|
||||||
const mockpost = helpers.mockpost;
|
const mockpost = helpers.mockpost;
|
||||||
const rpc = helpers.rpc;
|
|
||||||
|
|
||||||
describe('shapeshift/rpc', () => {
|
describe('shapeshift/rpc', () => {
|
||||||
|
let rpc;
|
||||||
|
let shapeshift;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
shapeshift = initShapeshift(helpers.APIKEY);
|
||||||
|
rpc = shapeshift.getRpc();
|
||||||
|
});
|
||||||
|
|
||||||
describe('GET', () => {
|
describe('GET', () => {
|
||||||
const REPLY = { test: 'this is some result' };
|
const REPLY = { test: 'this is some result' };
|
||||||
|
|
||||||
@ -29,7 +38,7 @@ describe('shapeshift/rpc', () => {
|
|||||||
let result;
|
let result;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
scope = mockget([{ path: 'test', reply: REPLY }]);
|
scope = mockget(shapeshift, [{ path: 'test', reply: REPLY }]);
|
||||||
|
|
||||||
return rpc
|
return rpc
|
||||||
.get('test')
|
.get('test')
|
||||||
@ -54,7 +63,7 @@ describe('shapeshift/rpc', () => {
|
|||||||
let result;
|
let result;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
scope = mockpost([{ path: 'test', reply: REPLY }]);
|
scope = mockpost(shapeshift, [{ path: 'test', reply: REPLY }]);
|
||||||
|
|
||||||
return rpc
|
return rpc
|
||||||
.post('test', { input: 'stuff' })
|
.post('test', { input: 'stuff' })
|
||||||
@ -76,7 +85,7 @@ describe('shapeshift/rpc', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('passes the apikey specified', () => {
|
it('passes the apikey specified', () => {
|
||||||
expect(scope.body.test.apiKey).to.equal(APIKEY);
|
expect(scope.body.test.apiKey).to.equal(helpers.APIKEY);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
77
js/src/3rdparty/shapeshift/shapeshift.js
vendored
77
js/src/3rdparty/shapeshift/shapeshift.js
vendored
@ -15,8 +15,9 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
export default function (rpc) {
|
export default function (rpc) {
|
||||||
let subscriptions = [];
|
let _subscriptions = [];
|
||||||
let pollStatusIntervalId = null;
|
let _pollStatusIntervalId = null;
|
||||||
|
let _subscriptionPromises = null;
|
||||||
|
|
||||||
function getCoins () {
|
function getCoins () {
|
||||||
return rpc.get('getcoins');
|
return rpc.get('getcoins');
|
||||||
@ -36,75 +37,93 @@ export default function (rpc) {
|
|||||||
|
|
||||||
function shift (toAddress, returnAddress, pair) {
|
function shift (toAddress, returnAddress, pair) {
|
||||||
return rpc.post('shift', {
|
return rpc.post('shift', {
|
||||||
withdrawal: toAddress,
|
pair,
|
||||||
pair: pair,
|
returnAddress,
|
||||||
returnAddress: returnAddress
|
withdrawal: toAddress
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function subscribe (depositAddress, callback) {
|
function subscribe (depositAddress, callback) {
|
||||||
const idx = subscriptions.length;
|
if (!depositAddress || !callback) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
subscriptions.push({
|
const index = _subscriptions.length;
|
||||||
depositAddress,
|
|
||||||
|
_subscriptions.push({
|
||||||
callback,
|
callback,
|
||||||
idx
|
depositAddress,
|
||||||
|
index
|
||||||
});
|
});
|
||||||
|
|
||||||
// Only poll if there are subscriptions...
|
if (_pollStatusIntervalId === null) {
|
||||||
if (!pollStatusIntervalId) {
|
_pollStatusIntervalId = setInterval(_pollStatus, 2000);
|
||||||
pollStatusIntervalId = setInterval(_pollStatus, 2000);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function unsubscribe (depositAddress) {
|
function unsubscribe (depositAddress) {
|
||||||
const newSubscriptions = []
|
_subscriptions = _subscriptions.filter((sub) => sub.depositAddress !== depositAddress);
|
||||||
.concat(subscriptions)
|
|
||||||
.filter((sub) => sub.depositAddress !== depositAddress);
|
|
||||||
|
|
||||||
subscriptions = newSubscriptions;
|
if (_subscriptions.length === 0) {
|
||||||
|
clearInterval(_pollStatusIntervalId);
|
||||||
if (subscriptions.length === 0) {
|
_pollStatusIntervalId = null;
|
||||||
clearInterval(pollStatusIntervalId);
|
|
||||||
pollStatusIntervalId = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _getSubscriptionStatus (subscription) {
|
function _getSubscriptionStatus (subscription) {
|
||||||
if (!subscription) {
|
if (!subscription) {
|
||||||
return;
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
getStatus(subscription.depositAddress)
|
return getStatus(subscription.depositAddress)
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
switch (result.status) {
|
switch (result.status) {
|
||||||
case 'no_deposits':
|
case 'no_deposits':
|
||||||
case 'received':
|
case 'received':
|
||||||
subscription.callback(null, result);
|
subscription.callback(null, result);
|
||||||
return;
|
return true;
|
||||||
|
|
||||||
case 'complete':
|
case 'complete':
|
||||||
subscription.callback(null, result);
|
subscription.callback(null, result);
|
||||||
subscriptions[subscription.idx] = null;
|
unsubscribe(subscription.depositAddress);
|
||||||
return;
|
return true;
|
||||||
|
|
||||||
case 'failed':
|
case 'failed':
|
||||||
subscription.callback({
|
subscription.callback({
|
||||||
message: status.error,
|
message: status.error,
|
||||||
fatal: true
|
fatal: true
|
||||||
});
|
});
|
||||||
subscriptions[subscription.idx] = null;
|
unsubscribe(subscription.depositAddress);
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(subscription.callback);
|
.catch(() => {
|
||||||
|
return true;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function _pollStatus () {
|
function _pollStatus () {
|
||||||
subscriptions.forEach(_getSubscriptionStatus);
|
_subscriptionPromises = Promise.all(_subscriptions.map(_getSubscriptionStatus));
|
||||||
|
}
|
||||||
|
|
||||||
|
function _getSubscriptions () {
|
||||||
|
return _subscriptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _getSubscriptionPromises () {
|
||||||
|
return _subscriptionPromises;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _isPolling () {
|
||||||
|
return _pollStatusIntervalId !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
_getSubscriptions,
|
||||||
|
_getSubscriptionPromises,
|
||||||
|
_isPolling,
|
||||||
getCoins,
|
getCoins,
|
||||||
getMarketInfo,
|
getMarketInfo,
|
||||||
getRpc,
|
getRpc,
|
||||||
|
110
js/src/3rdparty/shapeshift/shapeshift.spec.js
vendored
110
js/src/3rdparty/shapeshift/shapeshift.spec.js
vendored
@ -14,13 +14,29 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
const sinon = require('sinon');
|
||||||
|
|
||||||
|
const ShapeShift = require('./');
|
||||||
|
const initShapeshift = (ShapeShift.default || ShapeShift);
|
||||||
|
|
||||||
const helpers = require('./helpers.spec.js');
|
const helpers = require('./helpers.spec.js');
|
||||||
|
|
||||||
const mockget = helpers.mockget;
|
const mockget = helpers.mockget;
|
||||||
const mockpost = helpers.mockpost;
|
const mockpost = helpers.mockpost;
|
||||||
const shapeshift = helpers.shapeshift;
|
|
||||||
|
|
||||||
describe('shapeshift/calls', () => {
|
describe('shapeshift/calls', () => {
|
||||||
|
let clock;
|
||||||
|
let shapeshift;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
clock = sinon.useFakeTimers();
|
||||||
|
shapeshift = initShapeshift(helpers.APIKEY);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
clock.restore();
|
||||||
|
});
|
||||||
|
|
||||||
describe('getCoins', () => {
|
describe('getCoins', () => {
|
||||||
const REPLY = {
|
const REPLY = {
|
||||||
BTC: {
|
BTC: {
|
||||||
@ -39,8 +55,8 @@ describe('shapeshift/calls', () => {
|
|||||||
|
|
||||||
let scope;
|
let scope;
|
||||||
|
|
||||||
before(() => {
|
beforeEach(() => {
|
||||||
scope = mockget([{ path: 'getcoins', reply: REPLY }]);
|
scope = mockget(shapeshift, [{ path: 'getcoins', reply: REPLY }]);
|
||||||
|
|
||||||
return shapeshift.getCoins();
|
return shapeshift.getCoins();
|
||||||
});
|
});
|
||||||
@ -61,8 +77,8 @@ describe('shapeshift/calls', () => {
|
|||||||
|
|
||||||
let scope;
|
let scope;
|
||||||
|
|
||||||
before(() => {
|
beforeEach(() => {
|
||||||
scope = mockget([{ path: 'marketinfo/btc_ltc', reply: REPLY }]);
|
scope = mockget(shapeshift, [{ path: 'marketinfo/btc_ltc', reply: REPLY }]);
|
||||||
|
|
||||||
return shapeshift.getMarketInfo('btc_ltc');
|
return shapeshift.getMarketInfo('btc_ltc');
|
||||||
});
|
});
|
||||||
@ -80,8 +96,8 @@ describe('shapeshift/calls', () => {
|
|||||||
|
|
||||||
let scope;
|
let scope;
|
||||||
|
|
||||||
before(() => {
|
beforeEach(() => {
|
||||||
scope = mockget([{ path: 'txStat/0x123', reply: REPLY }]);
|
scope = mockget(shapeshift, [{ path: 'txStat/0x123', reply: REPLY }]);
|
||||||
|
|
||||||
return shapeshift.getStatus('0x123');
|
return shapeshift.getStatus('0x123');
|
||||||
});
|
});
|
||||||
@ -101,8 +117,8 @@ describe('shapeshift/calls', () => {
|
|||||||
|
|
||||||
let scope;
|
let scope;
|
||||||
|
|
||||||
before(() => {
|
beforeEach(() => {
|
||||||
scope = mockpost([{ path: 'shift', reply: REPLY }]);
|
scope = mockpost(shapeshift, [{ path: 'shift', reply: REPLY }]);
|
||||||
|
|
||||||
return shapeshift.shift('0x456', '1BTC', 'btc_eth');
|
return shapeshift.shift('0x456', '1BTC', 'btc_eth');
|
||||||
});
|
});
|
||||||
@ -125,4 +141,80 @@ describe('shapeshift/calls', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('subscriptions', () => {
|
||||||
|
const ADDRESS = '0123456789abcdef';
|
||||||
|
const REPLY = {
|
||||||
|
status: 'complete',
|
||||||
|
address: ADDRESS
|
||||||
|
};
|
||||||
|
|
||||||
|
let callback;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
mockget(shapeshift, [{ path: `txStat/${ADDRESS}`, reply: REPLY }]);
|
||||||
|
callback = sinon.stub();
|
||||||
|
shapeshift.subscribe(ADDRESS, callback);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('subscribe', () => {
|
||||||
|
it('adds the depositAddress to the list', () => {
|
||||||
|
const subscriptions = shapeshift._getSubscriptions();
|
||||||
|
|
||||||
|
expect(subscriptions.length).to.equal(1);
|
||||||
|
expect(subscriptions[0].depositAddress).to.equal(ADDRESS);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('starts the polling timer', () => {
|
||||||
|
expect(shapeshift._isPolling()).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('calls the callback once the timer has elapsed', () => {
|
||||||
|
clock.tick(2222);
|
||||||
|
|
||||||
|
return shapeshift._getSubscriptionPromises().then(() => {
|
||||||
|
expect(callback).to.have.been.calledWith(null, REPLY);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('auto-unsubscribes on completed', () => {
|
||||||
|
clock.tick(2222);
|
||||||
|
|
||||||
|
return shapeshift._getSubscriptionPromises().then(() => {
|
||||||
|
expect(shapeshift._getSubscriptions().length).to.equal(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('unsubscribe', () => {
|
||||||
|
it('unbsubscribes when requested', () => {
|
||||||
|
expect(shapeshift._getSubscriptions().length).to.equal(1);
|
||||||
|
shapeshift.unsubscribe(ADDRESS);
|
||||||
|
expect(shapeshift._getSubscriptions().length).to.equal(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('clears the polling on no subscriptions', () => {
|
||||||
|
shapeshift.unsubscribe(ADDRESS);
|
||||||
|
expect(shapeshift._isPolling()).to.be.false;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles unsubscribe of auto-unsubscribe', () => {
|
||||||
|
clock.tick(2222);
|
||||||
|
|
||||||
|
return shapeshift._getSubscriptionPromises().then(() => {
|
||||||
|
expect(shapeshift.unsubscribe(ADDRESS)).to.be.true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles unsubscribe when multiples listed', () => {
|
||||||
|
const ADDRESS2 = 'abcdef0123456789';
|
||||||
|
|
||||||
|
shapeshift.subscribe(ADDRESS2, sinon.stub());
|
||||||
|
expect(shapeshift._getSubscriptions().length).to.equal(2);
|
||||||
|
expect(shapeshift._getSubscriptions()[0].depositAddress).to.equal(ADDRESS);
|
||||||
|
shapeshift.unsubscribe(ADDRESS);
|
||||||
|
expect(shapeshift._getSubscriptions()[0].depositAddress).to.equal(ADDRESS2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user