v2.3.0: fix(#158), disable time sync by default. Optionally avoid hitting time API when connecting authenticated websocket.

This commit is contained in:
tiagosiebler
2022-07-12 11:32:17 +01:00
parent 7c531161b5
commit 43c1f91b50
18 changed files with 50 additions and 60 deletions

View File

@@ -64,10 +64,10 @@ const restClientOptions = {
recv_window?: number; recv_window?: number;
// how often to sync time drift with bybit servers // how often to sync time drift with bybit servers
sync_interval_ms?: number | string; sync_interval_ms?: number;
// Default: false. Disable above sync mechanism if true. // Default: false. Disable above sync mechanism if true.
disable_time_sync?: boolean; enable_time_sync?: boolean;
// Default: false. If true, we'll throw errors if any params are undefined // Default: false. If true, we'll throw errors if any params are undefined
strict_param_validation?: boolean; strict_param_validation?: boolean;

View File

@@ -27,7 +27,7 @@ import { WebsocketClient, wsKeySpotPublic } from '../src/websocket-client';
market: market, market: market,
livenet: true, livenet: true,
restOptions: { restOptions: {
// disable_time_sync: true, // enable_time_sync: true,
}, },
}, },
logger logger

View File

@@ -1,6 +1,6 @@
{ {
"name": "bybit-api", "name": "bybit-api",
"version": "2.2.2", "version": "2.3.0",
"description": "Node.js connector for Bybit's REST APIs and WebSockets, with TypeScript & integration tests.", "description": "Node.js connector for Bybit's REST APIs and WebSockets, with TypeScript & integration tests.",
"main": "lib/index.js", "main": "lib/index.js",
"types": "lib/index.d.ts", "types": "lib/index.d.ts",

View File

@@ -61,10 +61,13 @@ export default abstract class BaseRestClient {
this.options = { this.options = {
recv_window: 5000, recv_window: 5000,
// how often to sync time drift with bybit servers
sync_interval_ms: 3600000, /** Throw errors if any params are undefined */
// if true, we'll throw errors if any params are undefined
strict_param_validation: false, strict_param_validation: false,
/** Disable time sync by default */
enable_time_sync: false,
/** How often to sync time drift with bybit servers (if time sync is enabled) */
sync_interval_ms: 3600000,
...options, ...options,
}; };
@@ -86,7 +89,7 @@ export default abstract class BaseRestClient {
); );
} }
if (this.options.disable_time_sync !== true) { if (this.options.enable_time_sync) {
this.syncTime(); this.syncTime();
setInterval(this.syncTime.bind(this), +this.options.sync_interval_ms!); setInterval(this.syncTime.bind(this), +this.options.sync_interval_ms!);
} }
@@ -254,10 +257,11 @@ export default abstract class BaseRestClient {
} }
/** /**
* Trigger time sync and store promise * Trigger time sync and store promise. Use force: true, if automatic time sync is disabled
*/ */
private syncTime(): Promise<any> { private syncTime(force?: boolean): Promise<any> {
if (this.options.disable_time_sync === true) { if (!force && !this.options.enable_time_sync) {
this.timeOffset = 0;
return Promise.resolve(false); return Promise.resolve(false);
} }

View File

@@ -1,21 +1,26 @@
export interface RestClientOptions { export interface RestClientOptions {
// override the max size of the request window (in ms) /** Override the max size of the request window (in ms) */
recv_window?: number; recv_window?: number;
// how often to sync time drift with bybit servers /** @deprecated Time sync is now disabled by default. To re-enable it, use enable_time_sync instead. */
sync_interval_ms?: number | string;
// Default: false. Disable above sync mechanism if true.
disable_time_sync?: boolean; disable_time_sync?: boolean;
// Default: false. If true, we'll throw errors if any params are undefined /** Disabled by default. This can help on machines with consistent latency problems. */
enable_time_sync?: boolean;
/** How often to sync time drift with bybit servers */
sync_interval_ms?: number | string;
/** Default: false. If true, we'll throw errors if any params are undefined */
strict_param_validation?: boolean; strict_param_validation?: boolean;
// Optionally override API protocol + domain /**
// e.g 'https://api.bytick.com' * Optionally override API protocol + domain
* e.g baseUrl: 'https://api.bytick.com'
**/
baseUrl?: string; baseUrl?: string;
// Default: true. whether to try and post-process request exceptions. /** Default: true. whether to try and post-process request exceptions. */
parse_exceptions?: boolean; parse_exceptions?: boolean;
} }

View File

@@ -4,6 +4,7 @@ import WebSocket from 'isomorphic-ws';
import { InverseClient } from './inverse-client'; import { InverseClient } from './inverse-client';
import { LinearClient } from './linear-client'; import { LinearClient } from './linear-client';
import { DefaultLogger } from './logger'; import { DefaultLogger } from './logger';
import { SpotClient } from './spot-client';
import { KlineInterval } from './types/shared'; import { KlineInterval } from './types/shared';
import { signMessage } from './util/node-support'; import { signMessage } from './util/node-support';
import { import {
@@ -148,6 +149,8 @@ export interface WSClientConfigurableOptions {
restOptions?: RestClientOptions; restOptions?: RestClientOptions;
requestOptions?: any; requestOptions?: any;
wsUrl?: string; wsUrl?: string;
/** If true, fetch server time before trying to authenticate (disabled by default) */
fetchTimeOffsetBeforeAuth?: boolean;
} }
export interface WebsocketClientOptions extends WSClientConfigurableOptions { export interface WebsocketClientOptions extends WSClientConfigurableOptions {
@@ -229,7 +232,7 @@ function resolveMarket(options: WSClientConfigurableOptions): APIMarket {
export class WebsocketClient extends EventEmitter { export class WebsocketClient extends EventEmitter {
private logger: typeof DefaultLogger; private logger: typeof DefaultLogger;
private restClient: InverseClient | LinearClient; private restClient: InverseClient | LinearClient | SpotClient;
private options: WebsocketClientOptions; private options: WebsocketClientOptions;
private wsStore: WsStore; private wsStore: WsStore;
@@ -247,6 +250,7 @@ export class WebsocketClient extends EventEmitter {
pongTimeout: 1000, pongTimeout: 1000,
pingInterval: 10000, pingInterval: 10000,
reconnectTimeout: 500, reconnectTimeout: 500,
fetchTimeOffsetBeforeAuth: false,
...options, ...options,
}; };
@@ -263,8 +267,7 @@ export class WebsocketClient extends EventEmitter {
this.options.requestOptions this.options.requestOptions
); );
} else if (this.isSpot()) { } else if (this.isSpot()) {
// TODO: spot client this.restClient = new SpotClient(
this.restClient = new LinearClient(
undefined, undefined,
undefined, undefined,
this.isLivenet(), this.isLivenet(),
@@ -474,7 +477,9 @@ export class WebsocketClient extends EventEmitter {
wsKey, wsKey,
}); });
const timeOffset = await this.restClient.fetchTimeOffset(); const timeOffset = this.options.fetchTimeOffsetBeforeAuth
? await this.restClient.fetchTimeOffset()
: 0;
const params: any = { const params: any = {
api_key: this.options.key, api_key: this.options.key,

View File

@@ -6,9 +6,7 @@ describe('Public Inverse-Futures REST API GET Endpoints', () => {
const API_KEY = process.env.API_KEY_COM; const API_KEY = process.env.API_KEY_COM;
const API_SECRET = process.env.API_SECRET_COM; const API_SECRET = process.env.API_SECRET_COM;
const api = new InverseFuturesClient(API_KEY, API_SECRET, useLivenet, { const api = new InverseFuturesClient(API_KEY, API_SECRET, useLivenet);
disable_time_sync: true,
});
// Warning: if some of these start to fail with 10001 params error, it's probably that this future expired and a newer one exists with a different symbol! // Warning: if some of these start to fail with 10001 params error, it's probably that this future expired and a newer one exists with a different symbol!
const symbol = 'BTCUSDU22'; const symbol = 'BTCUSDU22';

View File

@@ -11,9 +11,7 @@ describe('Private Inverse-Futures REST API POST Endpoints', () => {
expect(API_SECRET).toStrictEqual(expect.any(String)); expect(API_SECRET).toStrictEqual(expect.any(String));
}); });
const api = new InverseFuturesClient(API_KEY, API_SECRET, useLivenet, { const api = new InverseFuturesClient(API_KEY, API_SECRET, useLivenet);
disable_time_sync: true,
});
// Warning: if some of these start to fail with 10001 params error, it's probably that this future expired and a newer one exists with a different symbol! // Warning: if some of these start to fail with 10001 params error, it's probably that this future expired and a newer one exists with a different symbol!
const symbol = 'BTCUSDU22'; const symbol = 'BTCUSDU22';

View File

@@ -7,9 +7,7 @@ import {
describe('Public Inverse Futures REST API Endpoints', () => { describe('Public Inverse Futures REST API Endpoints', () => {
const useLivenet = true; const useLivenet = true;
const api = new InverseFuturesClient(undefined, undefined, useLivenet, { const api = new InverseFuturesClient(undefined, undefined, useLivenet);
disable_time_sync: true,
});
const symbol = 'BTCUSD'; const symbol = 'BTCUSD';
const interval = '15'; const interval = '15';

View File

@@ -11,9 +11,7 @@ describe('Private Inverse REST API Endpoints', () => {
expect(API_SECRET).toStrictEqual(expect.any(String)); expect(API_SECRET).toStrictEqual(expect.any(String));
}); });
const api = new InverseClient(API_KEY, API_SECRET, useLivenet, { const api = new InverseClient(API_KEY, API_SECRET, useLivenet);
disable_time_sync: true,
});
const symbol = 'BTCUSD'; const symbol = 'BTCUSD';

View File

@@ -12,9 +12,7 @@ describe('Private Inverse REST API Endpoints', () => {
expect(API_SECRET).toStrictEqual(expect.any(String)); expect(API_SECRET).toStrictEqual(expect.any(String));
}); });
const api = new InverseClient(API_KEY, API_SECRET, useLivenet, { const api = new InverseClient(API_KEY, API_SECRET, useLivenet);
disable_time_sync: true,
});
const symbol = 'BTCUSD'; const symbol = 'BTCUSD';

View File

@@ -7,9 +7,7 @@ import {
describe('Public Inverse REST API Endpoints', () => { describe('Public Inverse REST API Endpoints', () => {
const useLivenet = true; const useLivenet = true;
const api = new InverseClient(undefined, undefined, useLivenet, { const api = new InverseClient(undefined, undefined, useLivenet);
disable_time_sync: true,
});
const symbol = 'BTCUSD'; const symbol = 'BTCUSD';
const interval = '15'; const interval = '15';

View File

@@ -11,9 +11,7 @@ describe('Public Linear REST API GET Endpoints', () => {
expect(API_SECRET).toStrictEqual(expect.any(String)); expect(API_SECRET).toStrictEqual(expect.any(String));
}); });
const api = new LinearClient(API_KEY, API_SECRET, useLivenet, { const api = new LinearClient(API_KEY, API_SECRET, useLivenet);
disable_time_sync: true,
});
const symbol = 'BTCUSDT'; const symbol = 'BTCUSDT';

View File

@@ -11,9 +11,7 @@ describe('Private Inverse-Futures REST API POST Endpoints', () => {
expect(API_SECRET).toStrictEqual(expect.any(String)); expect(API_SECRET).toStrictEqual(expect.any(String));
}); });
const api = new LinearClient(API_KEY, API_SECRET, useLivenet, { const api = new LinearClient(API_KEY, API_SECRET, useLivenet);
disable_time_sync: true,
});
// Warning: if some of these start to fail with 10001 params error, it's probably that this future expired and a newer one exists with a different symbol! // Warning: if some of these start to fail with 10001 params error, it's probably that this future expired and a newer one exists with a different symbol!
const symbol = 'BTCUSDT'; const symbol = 'BTCUSDT';

View File

@@ -7,9 +7,7 @@ import {
describe('Public Linear REST API Endpoints', () => { describe('Public Linear REST API Endpoints', () => {
const useLivenet = true; const useLivenet = true;
const api = new LinearClient(undefined, undefined, useLivenet, { const api = new LinearClient(undefined, undefined, useLivenet);
disable_time_sync: true,
});
const symbol = 'BTCUSDT'; const symbol = 'BTCUSDT';
const interval = '15'; const interval = '15';

View File

@@ -16,9 +16,7 @@ describe('Private Spot REST API Endpoints', () => {
expect(API_SECRET).toStrictEqual(expect.any(String)); expect(API_SECRET).toStrictEqual(expect.any(String));
}); });
const api = new SpotClient(API_KEY, API_SECRET, useLivenet, { const api = new SpotClient(API_KEY, API_SECRET, useLivenet);
disable_time_sync: true,
});
const symbol = 'BTCUSDT'; const symbol = 'BTCUSDT';
const interval = '15m'; const interval = '15m';

View File

@@ -11,9 +11,7 @@ describe('Private Inverse-Futures REST API POST Endpoints', () => {
expect(API_SECRET).toStrictEqual(expect.any(String)); expect(API_SECRET).toStrictEqual(expect.any(String));
}); });
const api = new SpotClient(API_KEY, API_SECRET, useLivenet, { const api = new SpotClient(API_KEY, API_SECRET, useLivenet);
disable_time_sync: true,
});
// Warning: if some of these start to fail with 10001 params error, it's probably that this future expired and a newer one exists with a different symbol! // Warning: if some of these start to fail with 10001 params error, it's probably that this future expired and a newer one exists with a different symbol!
const symbol = 'BTCUSDT'; const symbol = 'BTCUSDT';

View File

@@ -7,9 +7,7 @@ import {
describe('Public Spot REST API Endpoints', () => { describe('Public Spot REST API Endpoints', () => {
const useLivenet = true; const useLivenet = true;
const api = new SpotClient(undefined, undefined, useLivenet, { const api = new SpotClient(undefined, undefined, useLivenet);
disable_time_sync: true,
});
const symbol = 'BTCUSDT'; const symbol = 'BTCUSDT';
const interval = '15m'; const interval = '15m';