@oada/client
Advanced tools
Comparing version 1.0.4 to 1.1.0-alpha
@@ -9,2 +9,3 @@ import { WebSocketClient } from "./websocket"; | ||
_ws?: WebSocketClient; | ||
pingInterval?: number; | ||
} | ||
@@ -16,2 +17,3 @@ export declare type Response = SocketResponse; | ||
watchCallback?: (response: Readonly<Change>) => void; | ||
timeout?: number; | ||
} | ||
@@ -22,2 +24,3 @@ export interface WatchRequest { | ||
watchCallback: (response: Readonly<Change>) => void; | ||
timeout?: number; | ||
} | ||
@@ -29,2 +32,3 @@ export interface PUTRequest { | ||
tree?: object; | ||
timeout?: number; | ||
} | ||
@@ -36,8 +40,11 @@ export interface POSTRequest { | ||
tree?: object; | ||
timeout?: number; | ||
} | ||
export interface HEADRequest { | ||
path: string; | ||
timeout?: number; | ||
} | ||
export interface DELETERequest { | ||
path: string; | ||
timeout?: number; | ||
} | ||
@@ -44,0 +51,0 @@ export declare class OADAClient { |
@@ -21,6 +21,6 @@ "use strict"; | ||
this._concurrency = 1; | ||
this._domain = config.domain.replace(/^https:\/\//, ''); | ||
this._domain = config.domain.replace(/^https:\/\//, ""); | ||
this._token = config.token || this._token; | ||
this._concurrency = config.concurrency || this._concurrency; | ||
this._ws = new websocket_1.WebSocketClient(this._domain, this._concurrency); | ||
this._ws = new websocket_1.WebSocketClient(this._domain, this._concurrency, config.pingInterval); | ||
} | ||
@@ -43,5 +43,2 @@ clone(token) { | ||
disconnect() { | ||
if (!this._ws.isConnected()) { | ||
throw new Error("Not connected"); | ||
} | ||
return this._ws.disconnect(); | ||
@@ -56,3 +53,3 @@ } | ||
path: request.path, | ||
}); | ||
}, undefined, request.timeout); | ||
if (request.tree) { | ||
@@ -88,3 +85,3 @@ const arrayPath = utils.toArrayPath(request.path); | ||
} | ||
}); | ||
}, request.timeout); | ||
if (r.status !== 200) { | ||
@@ -171,4 +168,4 @@ throw new Error("Watch request failed!"); | ||
"_rev" in treeObj | ||
? { _id: resourceId, _type: contentType, _rev: 0 } | ||
: { _id: resourceId, _type: contentType }; | ||
? { _id: resourceId, _rev: 0 } | ||
: { _id: resourceId }; | ||
newResourcePathArray = partialPathArray.slice(); | ||
@@ -192,3 +189,3 @@ } | ||
data: request.data, | ||
}); | ||
}, undefined, request.timeout); | ||
} | ||
@@ -215,3 +212,3 @@ async post(request) { | ||
data, | ||
}); | ||
}, undefined, request.timeout); | ||
} | ||
@@ -225,3 +222,3 @@ async head(request) { | ||
path: request.path, | ||
}); | ||
}, undefined, request.timeout); | ||
} | ||
@@ -235,3 +232,3 @@ async delete(request) { | ||
path: request.path, | ||
}); | ||
}, undefined, request.timeout); | ||
} | ||
@@ -248,3 +245,3 @@ async _createResource(contentType, data) { | ||
async _resourceExists(path) { | ||
if (path === '/resources') | ||
if (path === "/resources") | ||
return true; | ||
@@ -251,0 +248,0 @@ const headResponse = await this.head({ |
@@ -5,3 +5,3 @@ import { Json, Change } from "."; | ||
path: string; | ||
method: "head" | "get" | "put" | "post" | "delete" | "watch" | "unwatch"; | ||
method: "head" | "get" | "put" | "post" | "delete" | "watch" | "unwatch" | "ping"; | ||
headers: Record<string, string>; | ||
@@ -26,11 +26,18 @@ data?: Json; | ||
private _domain; | ||
private _connected; | ||
private _status; | ||
private _requests; | ||
private _q; | ||
constructor(domain: string, concurrency?: number); | ||
private _pingInterval; | ||
private _timeoutTimerID; | ||
private _pingTimerID; | ||
constructor(domain: string, concurrency?: number, pingInterval?: number); | ||
private _sendPing; | ||
private _resetReconnectTimers; | ||
private _reconnect; | ||
private _connect; | ||
disconnect(): Promise<void>; | ||
isConnected(): boolean; | ||
request(req: SocketRequest, callback?: (response: Readonly<SocketChange>) => void): Promise<SocketResponse>; | ||
request(req: SocketRequest, callback?: (response: Readonly<SocketChange>) => void, timeout?: number): Promise<SocketResponse>; | ||
private doRequest; | ||
private _receive; | ||
} |
@@ -27,8 +27,43 @@ "use strict"; | ||
const v2_1 = require("@oada/types/oada/change/v2"); | ||
var ConnectionStatus; | ||
(function (ConnectionStatus) { | ||
ConnectionStatus[ConnectionStatus["Disconnected"] = 0] = "Disconnected"; | ||
ConnectionStatus[ConnectionStatus["Connecting"] = 1] = "Connecting"; | ||
ConnectionStatus[ConnectionStatus["Connected"] = 2] = "Connected"; | ||
})(ConnectionStatus || (ConnectionStatus = {})); | ||
class WebSocketClient { | ||
constructor(domain, concurrency = 10) { | ||
this._connected = false; | ||
constructor(domain, concurrency = 10, pingInterval = 60000) { | ||
this._domain = domain; | ||
this._requests = new Map(); | ||
this._ws = new Promise((resolve) => { | ||
this._q = new p_queue_1.default({ concurrency }); | ||
this._q.on("active", () => { | ||
trace(`WS Queue. Size: ${this._q.size} pending: ${this._q.pending}`); | ||
}); | ||
this._status = ConnectionStatus.Connecting; | ||
this._ws = this._connect(); | ||
this._pingInterval = pingInterval; | ||
this._pingTimerID = setTimeout(this._sendPing.bind(this), this._pingInterval); | ||
this._timeoutTimerID = setTimeout(this._reconnect.bind(this), this._pingInterval + 5000); | ||
} | ||
_sendPing() { | ||
const pingRequest = { | ||
method: "ping", | ||
headers: { authorization: "" }, | ||
path: "", | ||
}; | ||
this.request(pingRequest); | ||
} | ||
_resetReconnectTimers() { | ||
clearTimeout(this._timeoutTimerID); | ||
clearTimeout(this._pingTimerID); | ||
this._pingTimerID = setTimeout(this._sendPing.bind(this), this._pingInterval); | ||
this._timeoutTimerID = setTimeout(this._reconnect.bind(this), this._pingInterval + 5000); | ||
} | ||
_reconnect() { | ||
this._ws = this._connect(); | ||
this._resetReconnectTimers(); | ||
} | ||
_connect() { | ||
this._status = ConnectionStatus.Connecting; | ||
return new Promise((resolve) => { | ||
const ws = new WebSocket("wss://" + this._domain, { | ||
@@ -38,17 +73,13 @@ origin: "https://" + this._domain, | ||
ws.onopen = () => { | ||
this._connected = true; | ||
this._status = ConnectionStatus.Connected; | ||
resolve(ws); | ||
}; | ||
ws.onclose = () => { | ||
this._connected = false; | ||
this._status = ConnectionStatus.Disconnected; | ||
}; | ||
ws.onmessage = this._receive.bind(this); | ||
}); | ||
this._q = new p_queue_1.default({ concurrency }); | ||
this._q.on("active", () => { | ||
trace(`WS Queue. Size: ${this._q.size} pending: ${this._q.pending}`); | ||
}); | ||
} | ||
async disconnect() { | ||
if (!this._connected) { | ||
if (this._status == ConnectionStatus.Disconnected) { | ||
return; | ||
@@ -59,8 +90,8 @@ } | ||
isConnected() { | ||
return this._connected; | ||
return this._status == ConnectionStatus.Connected; | ||
} | ||
request(req, callback) { | ||
return this._q.add(() => this.doRequest(req, callback)); | ||
request(req, callback, timeout) { | ||
return this._q.add(() => this.doRequest(req, callback, timeout)); | ||
} | ||
async doRequest(req, callback) { | ||
async doRequest(req, callback, timeout) { | ||
const requestId = req.requestId || ksuid_1.default.randomSync().string; | ||
@@ -70,3 +101,3 @@ req.requestId = requestId; | ||
(await this._ws).send(JSON.stringify(req)); | ||
return new Promise((resolve, reject) => { | ||
const request_promise = new Promise((resolve, reject) => { | ||
this._requests.set(requestId, { | ||
@@ -80,4 +111,21 @@ resolve, | ||
}); | ||
if (timeout && timeout > 0) { | ||
const timeout_promise = new Promise((resolve, reject) => { | ||
setTimeout(() => { | ||
const request = this._requests.get(requestId); | ||
if (request && !request.settled) { | ||
request.reject("Request timeout"); | ||
this._requests.delete(requestId); | ||
} | ||
reject("Request timeout"); | ||
}, timeout); | ||
}); | ||
return Promise.race([request_promise, timeout_promise]); | ||
} | ||
else { | ||
return request_promise; | ||
} | ||
} | ||
_receive(m) { | ||
this._resetReconnectTimers(); | ||
try { | ||
@@ -84,0 +132,0 @@ const msg = JSON.parse(m.data.toString()); |
{ | ||
"name": "@oada/client", | ||
"version": "1.0.4", | ||
"version": "1.1.0-alpha", | ||
"description": "A lightweight client tool to interact with an OADA-compliant server", | ||
@@ -20,3 +20,3 @@ "main": "dist/index.js", | ||
"dependencies": { | ||
"@oada/types": "^1.0.6", | ||
"@oada/types": "^1.2.0-beta.5", | ||
"debug": "^4.1.1", | ||
@@ -30,2 +30,3 @@ "isomorphic-ws": "^4.0.1", | ||
"@types/chai": "^4.2.11", | ||
"@types/chai-as-promised": "^7.1.3", | ||
"@types/debug": "^4.1.5", | ||
@@ -36,3 +37,5 @@ "@types/mocha": "^7.0.2", | ||
"@types/ws": "^7.2.4", | ||
"axios": "^0.20.0", | ||
"chai": "^4.2.0", | ||
"chai-as-promised": "^7.1.1", | ||
"mocha": "^7.1.1", | ||
@@ -39,0 +42,0 @@ "ts-node": "^8.8.2", |
# @oada/client | ||
A lightweight client tool for interacting with an OADA-complient server | ||
A lightweight client tool for interacting with an OADA-compliant server | ||
@@ -29,3 +29,6 @@ | | `@oada/client` | `@oada/oada-cache` | | ||
```javascript | ||
var response = await connection.get({ path: '/bookmarks/test' }) | ||
var response = await connection.get({ | ||
path: '/bookmarks/test', | ||
timeout: 1000 // timeout in milliseconds (optional) | ||
}) | ||
``` | ||
@@ -54,3 +57,4 @@ | ||
path: '/bookmarks/thing', | ||
tree: dataTree | ||
tree: dataTree, | ||
timeout: 1000 // timeout in milliseconds (optional) | ||
}) | ||
@@ -66,3 +70,4 @@ ``` | ||
console.log(d); | ||
} | ||
}, | ||
timeout: 1000 // timeout in milliseconds (optional) | ||
}) | ||
@@ -79,3 +84,4 @@ ``` | ||
data: { thing: "abc" }, | ||
contentType: "application/json" | ||
contentType: "application/json", | ||
timeout: 1000 // timeout in milliseconds (optional) | ||
}) | ||
@@ -106,3 +112,4 @@ ``` | ||
tree: dataTree, | ||
data: { test: "something" } | ||
data: { test: "something" }, | ||
timeout: 1000 // timeout in milliseconds (optional) | ||
}) | ||
@@ -114,3 +121,6 @@ ``` | ||
```javascript | ||
var response = await connection.head({ path: '/bookmarks/test' }) | ||
var response = await connection.head({ | ||
path: '/bookmarks/test', | ||
timeout: 1000 // timeout in milliseconds (optional) | ||
}) | ||
``` |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
42443
652
121
13
2
Updated@oada/types@^1.2.0-beta.5