aboutsummaryrefslogtreecommitdiffstats
path: root/packages/connect
diff options
context:
space:
mode:
authorBrandon Millman <brandon.millman@gmail.com>2018-05-26 07:08:15 +0800
committerBrandon Millman <brandon.millman@gmail.com>2018-07-12 01:18:15 +0800
commita4b6112a311332df2c00799857463a646df78e25 (patch)
tree8fcc053b7fae56f7a69801e3c4091cda30a393ac /packages/connect
parent47debf0134b5864046831321b8eeeeb9aaaaf0a8 (diff)
downloaddexon-sol-tools-a4b6112a311332df2c00799857463a646df78e25.tar
dexon-sol-tools-a4b6112a311332df2c00799857463a646df78e25.tar.gz
dexon-sol-tools-a4b6112a311332df2c00799857463a646df78e25.tar.bz2
dexon-sol-tools-a4b6112a311332df2c00799857463a646df78e25.tar.lz
dexon-sol-tools-a4b6112a311332df2c00799857463a646df78e25.tar.xz
dexon-sol-tools-a4b6112a311332df2c00799857463a646df78e25.tar.zst
dexon-sol-tools-a4b6112a311332df2c00799857463a646df78e25.zip
Consolidate back to one channel and expose only the factory
Diffstat (limited to 'packages/connect')
-rw-r--r--packages/connect/src/index.ts3
-rw-r--r--packages/connect/src/node_ws_orderbook_channel.ts158
-rw-r--r--packages/connect/src/orderbook_channel_factory.ts35
-rw-r--r--packages/connect/src/schemas/node_websocket_orderbook_channel_config_schema.ts10
-rw-r--r--packages/connect/src/schemas/schemas.ts2
-rw-r--r--packages/connect/src/types.ts7
-rw-r--r--packages/connect/src/ws_orderbook_channel.ts (renamed from packages/connect/src/browser_ws_orderbook_channel.ts)37
-rw-r--r--packages/connect/test/browser_ws_orderbook_channel_test.ts63
-rw-r--r--packages/connect/test/orderbook_channel_factory_test.ts26
-rw-r--r--packages/connect/test/ws_orderbook_channel_test.ts (renamed from packages/connect/test/node_ws_orderbook_channel_test.ts)8
10 files changed, 65 insertions, 284 deletions
diff --git a/packages/connect/src/index.ts b/packages/connect/src/index.ts
index 30ce57aea..7f5eb8ed3 100644
--- a/packages/connect/src/index.ts
+++ b/packages/connect/src/index.ts
@@ -1,12 +1,9 @@
export { HttpClient } from './http_client';
-export { BrowserWebSocketOrderbookChannel } from './browser_ws_orderbook_channel';
-export { NodeWebSocketOrderbookChannel } from './node_ws_orderbook_channel';
export { orderbookChannelFactory } from './orderbook_channel_factory';
export {
Client,
FeesRequest,
FeesResponse,
- NodeWebSocketOrderbookChannelConfig,
OrderbookChannel,
OrderbookChannelHandler,
OrderbookChannelSubscriptionOpts,
diff --git a/packages/connect/src/node_ws_orderbook_channel.ts b/packages/connect/src/node_ws_orderbook_channel.ts
deleted file mode 100644
index 5f61ac4c8..000000000
--- a/packages/connect/src/node_ws_orderbook_channel.ts
+++ /dev/null
@@ -1,158 +0,0 @@
-import * as _ from 'lodash';
-import * as WebSocket from 'websocket';
-
-import { schemas as clientSchemas } from './schemas/schemas';
-import {
- NodeWebSocketOrderbookChannelConfig,
- OrderbookChannel,
- OrderbookChannelHandler,
- OrderbookChannelMessageTypes,
- OrderbookChannelSubscriptionOpts,
- WebsocketClientEventType,
- WebsocketConnectionEventType,
-} from './types';
-import { assert } from './utils/assert';
-import { orderbookChannelMessageParser } from './utils/orderbook_channel_message_parser';
-
-const DEFAULT_HEARTBEAT_INTERVAL_MS = 15000;
-const MINIMUM_HEARTBEAT_INTERVAL_MS = 10;
-
-/**
- * This class includes all the functionality related to interacting with a websocket endpoint
- * that implements the standard relayer API v0 in a node environment
- */
-export class NodeWebSocketOrderbookChannel implements OrderbookChannel {
- private _apiEndpointUrl: string;
- private _client: WebSocket.client;
- private _connectionIfExists?: WebSocket.connection;
- private _heartbeatTimerIfExists?: NodeJS.Timer;
- private _subscriptionCounter = 0;
- private _heartbeatIntervalMs: number;
- /**
- * Instantiates a new NodeWebSocketOrderbookChannelConfig instance
- * @param url The relayer API base WS url you would like to interact with
- * @param config The configuration object. Look up the type for the description.
- * @return An instance of NodeWebSocketOrderbookChannelConfig
- */
- constructor(url: string, config?: NodeWebSocketOrderbookChannelConfig) {
- assert.isUri('url', url);
- if (!_.isUndefined(config)) {
- assert.doesConformToSchema('config', config, clientSchemas.nodeWebSocketOrderbookChannelConfigSchema);
- }
- this._apiEndpointUrl = url;
- this._heartbeatIntervalMs =
- _.isUndefined(config) || _.isUndefined(config.heartbeatIntervalMs)
- ? DEFAULT_HEARTBEAT_INTERVAL_MS
- : config.heartbeatIntervalMs;
- this._client = new WebSocket.client();
- }
- /**
- * Subscribe to orderbook snapshots and updates from the websocket
- * @param subscriptionOpts An OrderbookChannelSubscriptionOpts instance describing which
- * token pair to subscribe to
- * @param handler An OrderbookChannelHandler instance that responds to various
- * channel updates
- */
- public subscribe(subscriptionOpts: OrderbookChannelSubscriptionOpts, handler: OrderbookChannelHandler): void {
- assert.isOrderbookChannelSubscriptionOpts('subscriptionOpts', subscriptionOpts);
- assert.isOrderbookChannelHandler('handler', handler);
- this._subscriptionCounter += 1;
- const subscribeMessage = {
- type: 'subscribe',
- channel: 'orderbook',
- requestId: this._subscriptionCounter,
- payload: subscriptionOpts,
- };
- this._getConnection((error, connection) => {
- if (!_.isUndefined(error)) {
- handler.onError(this, subscriptionOpts, error);
- } else if (!_.isUndefined(connection) && connection.connected) {
- connection.on(WebsocketConnectionEventType.Error, wsError => {
- handler.onError(this, subscriptionOpts, wsError);
- });
- connection.on(WebsocketConnectionEventType.Close, (_code: number, _desc: string) => {
- handler.onClose(this, subscriptionOpts);
- });
- connection.on(WebsocketConnectionEventType.Message, message => {
- this._handleWebSocketMessage(subscribeMessage.requestId, subscriptionOpts, message, handler);
- });
- connection.sendUTF(JSON.stringify(subscribeMessage));
- }
- });
- }
- /**
- * Close the websocket and stop receiving updates
- */
- public close(): void {
- if (!_.isUndefined(this._connectionIfExists)) {
- this._connectionIfExists.close();
- }
- if (!_.isUndefined(this._heartbeatTimerIfExists)) {
- clearInterval(this._heartbeatTimerIfExists);
- }
- }
- private _getConnection(callback: (error?: Error, connection?: WebSocket.connection) => void): void {
- if (!_.isUndefined(this._connectionIfExists) && this._connectionIfExists.connected) {
- callback(undefined, this._connectionIfExists);
- } else {
- this._client.on(WebsocketClientEventType.Connect, connection => {
- this._connectionIfExists = connection;
- if (this._heartbeatIntervalMs >= MINIMUM_HEARTBEAT_INTERVAL_MS) {
- this._heartbeatTimerIfExists = setInterval(() => {
- connection.ping('');
- }, this._heartbeatIntervalMs);
- } else {
- callback(
- new Error(
- `Heartbeat interval is ${
- this._heartbeatIntervalMs
- }ms which is less than the required minimum of ${MINIMUM_HEARTBEAT_INTERVAL_MS}ms`,
- ),
- undefined,
- );
- }
- callback(undefined, this._connectionIfExists);
- });
- this._client.on(WebsocketClientEventType.ConnectFailed, error => {
- callback(error, undefined);
- });
- this._client.connect(this._apiEndpointUrl);
- }
- }
- private _handleWebSocketMessage(
- requestId: number,
- subscriptionOpts: OrderbookChannelSubscriptionOpts,
- message: WebSocket.IMessage,
- handler: OrderbookChannelHandler,
- ): void {
- if (!_.isUndefined(message.utf8Data)) {
- try {
- const utf8Data = message.utf8Data;
- const parserResult = orderbookChannelMessageParser.parse(utf8Data);
- if (parserResult.requestId === requestId) {
- switch (parserResult.type) {
- case OrderbookChannelMessageTypes.Snapshot: {
- handler.onSnapshot(this, subscriptionOpts, parserResult.payload);
- break;
- }
- case OrderbookChannelMessageTypes.Update: {
- handler.onUpdate(this, subscriptionOpts, parserResult.payload);
- break;
- }
- default: {
- handler.onError(
- this,
- subscriptionOpts,
- new Error(`Message has missing a type parameter: ${utf8Data}`),
- );
- }
- }
- }
- } catch (error) {
- handler.onError(this, subscriptionOpts, error);
- }
- } else {
- handler.onError(this, subscriptionOpts, new Error(`Message does not contain utf8Data`));
- }
- }
-}
diff --git a/packages/connect/src/orderbook_channel_factory.ts b/packages/connect/src/orderbook_channel_factory.ts
index cb00212e7..4b363365f 100644
--- a/packages/connect/src/orderbook_channel_factory.ts
+++ b/packages/connect/src/orderbook_channel_factory.ts
@@ -1,16 +1,21 @@
-// import * as WebSocket from 'websocket';
+import * as WebSocket from 'websocket';
-import { BrowserWebSocketOrderbookChannel } from './browser_ws_orderbook_channel';
-import { NodeWebSocketOrderbookChannel } from './node_ws_orderbook_channel';
+import { OrderbookChannel, WebsocketClientEventType } from './types';
+import { assert } from './utils/assert';
+import { WebSocketOrderbookChannel } from './ws_orderbook_channel';
export const orderbookChannelFactory = {
- async createBrowserOrderbookChannelAsync(url: string): Promise<BrowserWebSocketOrderbookChannel> {
- return new Promise<BrowserWebSocketOrderbookChannel>((resolve, reject) => {
- const client = new WebSocket(url);
- console.log(client);
+ /**
+ * Instantiates a new WebSocketOrderbookChannel instance
+ * @param url The relayer API base WS url you would like to interact with
+ * @return An OrderbookChannel Promise
+ */
+ async createWebSocketOrderbookChannelAsync(url: string): Promise<OrderbookChannel> {
+ assert.isUri('url', url);
+ return new Promise<OrderbookChannel>((resolve, reject) => {
+ const client = new WebSocket.w3cwebsocket(url);
client.onopen = () => {
- const orderbookChannel = new BrowserWebSocketOrderbookChannel(client);
- console.log(orderbookChannel);
+ const orderbookChannel = new WebSocketOrderbookChannel(client);
resolve(orderbookChannel);
};
client.onerror = err => {
@@ -18,16 +23,4 @@ export const orderbookChannelFactory = {
};
});
},
- // async createNodeOrderbookChannelAsync(url: string): Promise<NodeWebSocketOrderbookChannel> {
- // return new Promise<BrowserWebSocketOrderbookChannel>((resolve, reject) => {
- // const client = new WebSocket.w3cwebsocket(url);
- // client.onopen = () => {
- // const orderbookChannel = new BrowserWebSocketOrderbookChannel(client);
- // resolve(orderbookChannel);
- // };
- // client.onerror = err => {
- // reject(err);
- // };
- // });
- // },
};
diff --git a/packages/connect/src/schemas/node_websocket_orderbook_channel_config_schema.ts b/packages/connect/src/schemas/node_websocket_orderbook_channel_config_schema.ts
deleted file mode 100644
index c745d0b82..000000000
--- a/packages/connect/src/schemas/node_websocket_orderbook_channel_config_schema.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-export const nodeWebSocketOrderbookChannelConfigSchema = {
- id: '/NodeWebSocketOrderbookChannelConfig',
- type: 'object',
- properties: {
- heartbeatIntervalMs: {
- type: 'number',
- minimum: 10,
- },
- },
-};
diff --git a/packages/connect/src/schemas/schemas.ts b/packages/connect/src/schemas/schemas.ts
index 835fc7b4f..0b8b798a9 100644
--- a/packages/connect/src/schemas/schemas.ts
+++ b/packages/connect/src/schemas/schemas.ts
@@ -1,5 +1,4 @@
import { feesRequestSchema } from './fees_request_schema';
-import { nodeWebSocketOrderbookChannelConfigSchema } from './node_websocket_orderbook_channel_config_schema';
import { orderBookRequestSchema } from './orderbook_request_schema';
import { ordersRequestOptsSchema } from './orders_request_opts_schema';
import { pagedRequestOptsSchema } from './paged_request_opts_schema';
@@ -7,7 +6,6 @@ import { tokenPairsRequestOptsSchema } from './token_pairs_request_opts_schema';
export const schemas = {
feesRequestSchema,
- nodeWebSocketOrderbookChannelConfigSchema,
orderBookRequestSchema,
ordersRequestOptsSchema,
pagedRequestOptsSchema,
diff --git a/packages/connect/src/types.ts b/packages/connect/src/types.ts
index 5657942ee..5ea114371 100644
--- a/packages/connect/src/types.ts
+++ b/packages/connect/src/types.ts
@@ -16,13 +16,6 @@ export interface OrderbookChannel {
}
/**
- * heartbeatInterval: Interval in milliseconds that the orderbook channel should ping the underlying websocket. Default: 15000
- */
-export interface NodeWebSocketOrderbookChannelConfig {
- heartbeatIntervalMs?: number;
-}
-
-/**
* baseTokenAddress: The address of token designated as the baseToken in the currency pair calculation of price
* quoteTokenAddress: The address of token designated as the quoteToken in the currency pair calculation of price
* snapshot: If true, a snapshot of the orderbook will be sent before the updates to the orderbook
diff --git a/packages/connect/src/browser_ws_orderbook_channel.ts b/packages/connect/src/ws_orderbook_channel.ts
index 599b4f0be..f90d9ac30 100644
--- a/packages/connect/src/browser_ws_orderbook_channel.ts
+++ b/packages/connect/src/ws_orderbook_channel.ts
@@ -1,4 +1,5 @@
import * as _ from 'lodash';
+import * as WebSocket from 'websocket';
import {
OrderbookChannel,
@@ -18,19 +19,27 @@ interface Subscription {
/**
* This class includes all the functionality related to interacting with a websocket endpoint
- * that implements the standard relayer API v0 in a browser environment
+ * that implements the standard relayer API v0
*/
-export class BrowserWebSocketOrderbookChannel implements OrderbookChannel {
- private _client: WebSocket;
+export class WebSocketOrderbookChannel implements OrderbookChannel {
+ private _client: WebSocket.w3cwebsocket;
private _subscriptions: Subscription[] = [];
/**
* Instantiates a new WebSocketOrderbookChannel instance
* @param url The relayer API base WS url you would like to interact with
* @return An instance of WebSocketOrderbookChannel
*/
- constructor(client: WebSocket) {
- // assert.isUri('url', url);
+ constructor(client: WebSocket.w3cwebsocket) {
this._client = client;
+ this._client.onerror = err => {
+ this._alertAllHandlersToError(err);
+ };
+ this._client.onclose = () => {
+ this._alertAllHandlersToClose();
+ };
+ this._client.onmessage = message => {
+ this._handleWebSocketMessage(message);
+ };
}
/**
* Subscribe to orderbook snapshots and updates from the websocket
@@ -53,17 +62,6 @@ export class BrowserWebSocketOrderbookChannel implements OrderbookChannel {
requestId: this._subscriptions.length - 1,
payload: subscriptionOpts,
};
- this._client.onerror = () => {
- this._alertAllHandlersToError(new Error('hello'));
- };
- this._client.onclose = () => {
- _.forEach(this._subscriptions, subscription => {
- subscription.handler.onClose(this, subscription.subscriptionOpts);
- });
- };
- this._client.onmessage = message => {
- this._handleWebSocketMessage(message);
- };
this._sendMessage(subscribeMessage);
}
/**
@@ -76,7 +74,7 @@ export class BrowserWebSocketOrderbookChannel implements OrderbookChannel {
* Send a message to the client if it has been instantiated and it is open
*/
private _sendMessage(message: any): void {
- if (this._client.readyState === WebSocket.OPEN) {
+ if (this._client.readyState === WebSocket.w3cwebsocket.OPEN) {
this._client.send(JSON.stringify(message));
}
}
@@ -88,6 +86,11 @@ export class BrowserWebSocketOrderbookChannel implements OrderbookChannel {
subscription.handler.onError(this, subscription.subscriptionOpts, error);
});
}
+ private _alertAllHandlersToClose(): void {
+ _.forEach(this._subscriptions, subscription => {
+ subscription.handler.onClose(this, subscription.subscriptionOpts);
+ });
+ }
private _handleWebSocketMessage(message: any): void {
// if we get a message with no data, alert all handlers and return
if (_.isUndefined(message.data)) {
diff --git a/packages/connect/test/browser_ws_orderbook_channel_test.ts b/packages/connect/test/browser_ws_orderbook_channel_test.ts
deleted file mode 100644
index d6a7af5c0..000000000
--- a/packages/connect/test/browser_ws_orderbook_channel_test.ts
+++ /dev/null
@@ -1,63 +0,0 @@
-// import * as chai from 'chai';
-// import * as dirtyChai from 'dirty-chai';
-// import * as _ from 'lodash';
-// import 'mocha';
-// import * as WebSocket from 'websocket';
-
-// import { BrowserWebSocketOrderbookChannel } from '../src/browser_ws_orderbook_channel';
-
-// chai.config.includeStack = true;
-// chai.use(dirtyChai);
-// const expect = chai.expect;
-
-// describe('BrowserWebSocketOrderbookChannel', () => {
-// const websocketUrl = 'ws://localhost:8080';
-// const client = new WebSocket.w3cwebsocket(websocketUrl);
-// const orderbookChannel = new BrowserWebSocketOrderbookChannel(client);
-// const subscriptionOpts = {
-// baseTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
-// quoteTokenAddress: '0xef7fff64389b814a946f3e92105513705ca6b990',
-// snapshot: true,
-// limit: 100,
-// };
-// const emptyOrderbookChannelHandler = {
-// onSnapshot: () => {
-// _.noop();
-// },
-// onUpdate: () => {
-// _.noop();
-// },
-// onError: () => {
-// _.noop();
-// },
-// onClose: () => {
-// _.noop();
-// },
-// };
-// describe('#subscribe', () => {
-// it('throws when subscriptionOpts does not conform to schema', () => {
-// const badSubscribeCall = orderbookChannel.subscribe.bind(
-// orderbookChannel,
-// {},
-// emptyOrderbookChannelHandler,
-// );
-// expect(badSubscribeCall).throws(
-// 'Expected subscriptionOpts to conform to schema /RelayerApiOrderbookChannelSubscribePayload\nEncountered: {}\nValidation errors: instance requires property "baseTokenAddress", instance requires property "quoteTokenAddress"',
-// );
-// });
-// it('throws when handler has the incorrect members', () => {
-// const badSubscribeCall = orderbookChannel.subscribe.bind(orderbookChannel, subscriptionOpts, {});
-// expect(badSubscribeCall).throws(
-// 'Expected handler.onSnapshot to be of type function, encountered: undefined',
-// );
-// });
-// it('does not throw when inputs are of correct types', () => {
-// const goodSubscribeCall = orderbookChannel.subscribe.bind(
-// orderbookChannel,
-// subscriptionOpts,
-// emptyOrderbookChannelHandler,
-// );
-// expect(goodSubscribeCall).to.not.throw();
-// });
-// });
-// });
diff --git a/packages/connect/test/orderbook_channel_factory_test.ts b/packages/connect/test/orderbook_channel_factory_test.ts
new file mode 100644
index 000000000..fd84332cc
--- /dev/null
+++ b/packages/connect/test/orderbook_channel_factory_test.ts
@@ -0,0 +1,26 @@
+import * as chai from 'chai';
+import * as dirtyChai from 'dirty-chai';
+import * as _ from 'lodash';
+import 'mocha';
+import * as WebSocket from 'websocket';
+
+import { orderbookChannelFactory } from '../src/orderbook_channel_factory';
+
+chai.config.includeStack = true;
+chai.use(dirtyChai);
+const expect = chai.expect;
+
+describe('orderbookChannelFactory', () => {
+ const websocketUrl = 'ws://localhost:8080';
+
+ describe('#createWebSocketOrderbookChannelAsync', () => {
+ it('throws when input is not a url', () => {
+ const badInput = 54;
+ const badSubscribeCall = orderbookChannelFactory.createWebSocketOrderbookChannelAsync.bind(
+ orderbookChannelFactory,
+ badInput,
+ );
+ expect(orderbookChannelFactory.createWebSocketOrderbookChannelAsync(badInput as any)).to.be.rejected();
+ });
+ });
+});
diff --git a/packages/connect/test/node_ws_orderbook_channel_test.ts b/packages/connect/test/ws_orderbook_channel_test.ts
index 5e5325e83..79100d0e2 100644
--- a/packages/connect/test/node_ws_orderbook_channel_test.ts
+++ b/packages/connect/test/ws_orderbook_channel_test.ts
@@ -2,16 +2,18 @@ import * as chai from 'chai';
import * as dirtyChai from 'dirty-chai';
import * as _ from 'lodash';
import 'mocha';
+import * as WebSocket from 'websocket';
-import { NodeWebSocketOrderbookChannel } from '../src/node_ws_orderbook_channel';
+import { WebSocketOrderbookChannel } from '../src/ws_orderbook_channel';
chai.config.includeStack = true;
chai.use(dirtyChai);
const expect = chai.expect;
-describe('NodeWebSocketOrderbookChannel', () => {
+describe('WebSocketOrderbookChannel', () => {
const websocketUrl = 'ws://localhost:8080';
- const orderbookChannel = new NodeWebSocketOrderbookChannel(websocketUrl);
+ const client = new WebSocket.w3cwebsocket(websocketUrl);
+ const orderbookChannel = new WebSocketOrderbookChannel(client);
const subscriptionOpts = {
baseTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
quoteTokenAddress: '0xef7fff64389b814a946f3e92105513705ca6b990',