@ylide/everscale
Version:
Ylide Protocol SDK implementation for EverScale blockchain
153 lines • 5.94 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.GqlSender = void 0;
const gql_1 = require("everscale-standalone-client/client/ConnectionController/gql");
const gqlQueries_1 = require("./gqlQueries");
class GqlSender {
params;
latencyDetectionInterval;
endpoints;
nextLatencyDetectionTime = 0;
currentEndpoint;
resolutionPromise;
constructor(params) {
this.params = params;
this.latencyDetectionInterval = params.latencyDetectionInterval || 60000;
this.endpoints = params.endpoints.map(e => gql_1.GqlSocket.expandAddress(e));
if (this.endpoints.length === 1) {
this.currentEndpoint = this.endpoints[0];
this.nextLatencyDetectionTime = Number.MAX_VALUE;
}
}
isLocal() {
return !!this.params.local;
}
async send(data) {
const now = Date.now();
try {
let endpoint;
if (this.currentEndpoint != null && now < this.nextLatencyDetectionTime) {
// Default route
endpoint = this.currentEndpoint;
}
else if (this.resolutionPromise != null) {
// Already resolving
endpoint = await this.resolutionPromise;
delete this.resolutionPromise;
}
else {
delete this.currentEndpoint;
// Start resolving (current endpoint is null, or it is time to refresh)
this.resolutionPromise = this._selectQueryingEndpoint().then(_endpoint => {
this.currentEndpoint = _endpoint;
this.nextLatencyDetectionTime = Date.now() + this.latencyDetectionInterval;
return _endpoint;
});
endpoint = await this.resolutionPromise;
delete this.resolutionPromise;
}
return fetch(endpoint.url, {
method: 'post',
headers: {
'Content-Type': 'application/json',
},
body: data,
}).then(response => response.json());
}
catch (e) {
throw e;
}
}
async _selectQueryingEndpoint() {
const maxLatency = this.params.maxLatency || 60000;
const endpointCount = this.endpoints.length;
for (let retryCount = 0; retryCount < 5; ++retryCount) {
let handlers;
const promise = new Promise((resolve, reject) => {
handlers = {
resolve: (endpoint) => resolve(endpoint),
reject: () => reject(undefined),
};
});
let checkedEndpoints = 0;
let lastLatency;
for (const endpoint of this.endpoints) {
gql_1.GqlSocket.checkLatency(endpoint).then(latency => {
++checkedEndpoints;
if (latency !== undefined && latency <= maxLatency) {
return handlers.resolve(endpoint);
}
if (lastLatency === undefined ||
lastLatency.latency === undefined ||
(latency !== undefined && latency < lastLatency.latency)) {
lastLatency = { endpoint, latency };
}
if (checkedEndpoints >= endpointCount) {
if (lastLatency?.latency !== undefined) {
handlers.resolve(lastLatency.endpoint);
}
else {
handlers.reject();
}
}
});
}
try {
return await promise;
}
catch (e) {
let resolveDelay;
const delayPromise = new Promise(resolve => {
resolveDelay = () => resolve();
});
setTimeout(() => resolveDelay(), Math.min(100 * retryCount, 5000));
await delayPromise;
}
}
throw new Error('Not available endpoint found');
}
async query(query, variables = {}) {
return this.send(JSON.stringify({
query,
variables,
}));
}
async queryContractMessages(dst, contractAddress, limit) {
const query = (0, gqlQueries_1.getContractMessagesQuery)(dst, contractAddress, limit);
return await this.queryMessages(query);
}
async queryMessage(query, variables = {}) {
const data = await this.query(query, variables);
if (!data || !data.data || !data.data.blockchain || !data.data.blockchain.message) {
return null;
}
const m = data.data.blockchain.message;
return {
...m,
id: m.id.startsWith('message/') ? m.id.split('message/')[1] : m.id,
cursor: null,
};
}
async queryMessages(query, variables = {}) {
const data = await this.query(query, variables);
if (!data ||
!data.data ||
!data.data.blockchain ||
!data.data.blockchain.account ||
!data.data.blockchain.account.messages ||
!data.data.blockchain.account.messages.edges ||
!Array.isArray(data.data.blockchain.account.messages.edges) ||
!data.data.blockchain.account.messages.edges.length) {
return [];
}
const msgs = data.data.blockchain.account.messages.edges.map((e) => ({
...e.node,
id: e.node.id.startsWith('message/') ? e.node.id.split('message/')[1] : e.node.id,
cursor: e.cursor,
}));
msgs.sort((a, b) => b.created_at - a.created_at);
return msgs;
}
}
exports.GqlSender = GqlSender;
//# sourceMappingURL=GqlSender.js.map