Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix node connection issues #1504

Merged
merged 3 commits into from
Aug 4, 2023
Merged
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
69 changes: 36 additions & 33 deletions backends/Eclair.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,18 @@ import Base64Utils from './../utils/Base64Utils';
import { Hash as sha256Hash } from 'fast-sha256';

// keep track of all active calls so we can cancel when appropriate
const calls: any = {};
const calls = new Map<string, Promise<any>>();

export default class Eclair {
clearCachedCalls = () => calls.clear();

api = (method: string, params: any = {}) => {
const { password, certVerification, enableTor } = stores.settingsStore;
let { url } = stores.settingsStore;

const id: string = method + JSON.stringify(params);
if (calls[id]) {
return calls[id];
if (calls.has(id)) {
return calls.get(id);
}

url = url.slice(-1) === '/' ? url : url + '/';
Expand All @@ -28,48 +30,49 @@ export default class Eclair {
const body = querystring.stringify(params);

if (enableTor === true) {
calls[id] = doTorRequest(
url + method,
RequestMethod.POST,
body,
headers
calls.set(
id,
doTorRequest(url + method, RequestMethod.POST, body, headers)
);
} else {
calls[id] = ReactNativeBlobUtil.config({
trusty: !certVerification
})
.fetch('POST', url + method, headers, body)
.then((response: any) => {
delete calls[id];
calls.set(
id,
ReactNativeBlobUtil.config({
trusty: !certVerification
})
.fetch('POST', url + method, headers, body)
.then((response: any) => {
calls.delete(id);

const status = response.info().status;
if (status < 300) {
return response.json();
} else {
let errorInfo;
try {
errorInfo = response.json();
} catch (err) {
throw new Error(
'response was (' +
status +
')' +
response.text()
);
const status = response.info().status;
if (status < 300) {
return response.json();
} else {
let errorInfo;
try {
errorInfo = response.json();
} catch (err) {
throw new Error(
'response was (' +
status +
')' +
response.text()
);
}
throw new Error(errorInfo.error);
}
throw new Error(errorInfo.error);
}
});
})
);
}
setTimeout(
(id: string) => {
delete calls[id];
calls.delete(id);
},
9000,
id
);

return calls[id];
return calls.get(id);
};

getTransactions = () =>
Expand Down
87 changes: 51 additions & 36 deletions backends/LND.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,13 @@ interface Headers {
}

// keep track of all active calls so we can cancel when appropriate
const calls: any = {};
const calls = new Map<string, Promise<any>>();

export default class LND {
torSocksPort?: number = undefined;

clearCachedCalls = () => calls.clear();

restReq = async (
headers: Headers | any,
url: string,
Expand All @@ -29,49 +33,60 @@ export default class LND {
// use body data as an identifier too, we don't want to cancel when we
// are making multiples calls to get all the node names, for example
const id = data ? `${url}${JSON.stringify(data)}` : url;
if (calls[id]) {
return calls[id];
if (calls.has(id)) {
return calls.get(id);
}
// API is a bit of a mess but
// If tor enabled in setting, start up the daemon here
if (useTor === true) {
calls[id] = doTorRequest(
url,
method as RequestMethod,
JSON.stringify(data),
headers
).then((response: any) => {
delete calls[id];
return response;
});
calls.set(
id,
doTorRequest(
url,
method as RequestMethod,
JSON.stringify(data),
headers
).then((response: any) => {
calls.delete(id);
return response;
})
);
} else {
calls[id] = ReactNativeBlobUtil.config({
trusty: !certVerification
})
.fetch(method, url, headers, data ? JSON.stringify(data) : data)
.then((response: any) => {
delete calls[id];
if (response.info().status < 300) {
// handle ws responses
if (response.data.includes('\n')) {
const split = response.data.split('\n');
const length = split.length;
// last instance is empty
return JSON.parse(split[length - 2]);
calls.set(
id,
ReactNativeBlobUtil.config({
trusty: !certVerification
})
.fetch(
method,
url,
headers,
data ? JSON.stringify(data) : data
)
.then((response: any) => {
calls.delete(id);
if (response.info().status < 300) {
// handle ws responses
if (response.data.includes('\n')) {
const split = response.data.split('\n');
const length = split.length;
// last instance is empty
return JSON.parse(split[length - 2]);
}
return response.json();
} else {
const errorInfo = response.json();
throw new Error(
(errorInfo.error && errorInfo.error.message) ||
errorInfo.message ||
errorInfo.error
);
}
return response.json();
} else {
const errorInfo = response.json();
throw new Error(
(errorInfo.error && errorInfo.error.message) ||
errorInfo.message ||
errorInfo.error
);
}
});
})
);
}

return await calls[id];
return await calls.get(id);
};

supports = (minVersion: string, eosVersion?: string) => {
Expand Down
61 changes: 33 additions & 28 deletions backends/Spark.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,18 @@ import TransactionRequest from './../models/TransactionRequest';
import OpenChannelRequest from './../models/OpenChannelRequest';

// keep track of all active calls so we can cancel when appropriate
const calls: any = {};
const calls = new Map<string, Promise<any>>();

export default class Spark {
clearCachedCalls = () => calls.clear();

rpc = (rpcmethod: string, param = {}, range: any = null) => {
const { accessKey, certVerification, enableTor } = stores.settingsStore;
let { url } = stores.settingsStore;

const id = rpcmethod + JSON.stringify(param) + JSON.stringify(range);
if (calls[id]) {
return calls[id];
if (calls.has(id)) {
return calls.get(id);
}

url = url.slice(-4) === '/rpc' ? url : url + '/rpc';
Expand All @@ -26,35 +28,38 @@ export default class Spark {
const body = JSON.stringify({ method: rpcmethod, params: param });

if (enableTor === true) {
calls[id] = doTorRequest(url, RequestMethod.POST, body, headers);
calls.set(id, doTorRequest(url, RequestMethod.POST, body, headers));
} else {
calls[id] = ReactNativeBlobUtil.config({
trusty: !certVerification
})
.fetch('POST', url, headers, body)
.then((response: any) => {
delete calls[id];
const status = response.info().status;
if (status < 300) {
return response.json();
} else {
let errorInfo;
try {
errorInfo = response.json();
} catch (err) {
throw new Error(
'response was (' +
status +
')' +
response.text()
);
calls.set(
id,
ReactNativeBlobUtil.config({
trusty: !certVerification
})
.fetch('POST', url, headers, body)
.then((response: any) => {
calls.delete(id);
const status = response.info().status;
if (status < 300) {
return response.json();
} else {
let errorInfo;
try {
errorInfo = response.json();
} catch (err) {
throw new Error(
'response was (' +
status +
')' +
response.text()
);
}
throw new Error(errorInfo.message);
}
throw new Error(errorInfo.message);
}
});
})
);
}

return calls[id];
return calls.get(id);
};

getTransactions = () =>
Expand Down
9 changes: 9 additions & 0 deletions stores/NodeInfoStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,18 @@ export default class NodeInfoStore {
this.loading = true;
};

private currentRequest: any;

@action
public getNodeInfo = () => {
this.errorMsg = '';
this.loading = true;
const currentRequest = (this.currentRequest = {});
BackendUtils.getMyNodeInfo()
.then((data: any) => {
if (this.currentRequest !== currentRequest) {
return;
}
const nodeInfo = new NodeInfo(data);
this.nodeInfo = nodeInfo;
this.testnet = nodeInfo.isTestNet;
Expand All @@ -52,6 +58,9 @@ export default class NodeInfoStore {
this.error = false;
})
.catch((error: any) => {
if (this.currentRequest !== currentRequest) {
return;
}
// handle error
this.errorMsg = ErrorUtils.errorToUserFriendly(
error.toString()
Expand Down
1 change: 1 addition & 0 deletions stores/SettingsStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1026,6 +1026,7 @@ export default class SettingsStore {
if (status) {
this.error = false;
this.errorMsg = '';
BackendUtils.clearCachedCalls();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should probably check first if clearCachedCalls is defined as it isn't defined for all backends

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is not necessary since the call function of BackendUtils already checks this.

}
this.connecting = status;
return this.connecting;
Expand Down
2 changes: 2 additions & 0 deletions utils/BackendUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ class BackendUtils {
checkPerms = () => this.call('checkPerms');
isConnected = (...args: any[]) => this.call('isConnected', args);
disconnect = (...args: any[]) => this.call('disconnect', args);

clearCachedCalls = (...args: any[]) => this.call('clearCachedCalls', args);
}

const backendUtils = new BackendUtils();
Expand Down