Skip to content

Commit e04d44b

Browse files
committed
Merge branch 'master' into breaking-changes
2 parents a2ba9aa + 7653693 commit e04d44b

File tree

7 files changed

+152
-4
lines changed

7 files changed

+152
-4
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ await cli.connect();
250250
- `protocols` {Array<String>} - Array of subprotocols supported by this server. Can be overridden in an [auth](#serverauthcallback) callback. Defaults to `[]`.
251251
- `callTimeoutMs` {Number} - Milliseconds to wait before unanswered outbound calls are rejected automatically. Defaults to `30000`.
252252
- `pingIntervalMs` {Number} - Milliseconds between WebSocket pings to connected clients. Defaults to `30000`.
253+
- `deferPingsOnActivity` {Boolean} - Should connected clients skip sending pings if activity received? Defaults to `false`.
253254
- `respondWithDetailedErrors` {Boolean} - Specifies whether to send detailed errors (including stack trace) to remote party upon an error being thrown by a handler. Defaults to `false`.
254255
- `callConcurrency` {Number} - The number of concurrent in-flight outbound calls permitted at any one time. Additional calls are queued. (There is no limit on inbound calls.) Defaults to `1`.
255256
- `strictMode` {Boolean} - Enable strict validation of calls & responses. Defaults to `false`. (See [Strict Validation](#strict-validation) to understand how this works.)
@@ -388,6 +389,7 @@ Returns a `Promise` which resolves when the server has completed closing.
388389
- `query` {Object|String} - An optional query string or object to append as the query string of the connection URL. Defaults to `''`.
389390
- `callTimeoutMs` {Number} - Milliseconds to wait before unanswered outbound calls are rejected automatically. Defaults to `60000`.
390391
- `pingIntervalMs` {Number} - Milliseconds between WebSocket pings. Defaults to `30000`.
392+
- `deferPingsOnActivity` {Boolean} - Should the client skip sending pings if activity received? Defaults to `false`.
391393
- `strictMode` {Boolean} - Enable strict validation of calls & responses. Defaults to `false`. (See [Strict Validation](#strict-validation) to understand how this works.)
392394
- `strictModeValidators` {Array<Validator>} - Optional additional validators to be used in conjunction with `strictMode`. (See [Strict Validation](#adding-additional-validation-schemas) to understand how this works.)
393395
- `respondWithDetailedErrors` {Boolean} - Specifies whether to send detailed errors (including stack trace) to remote party upon an error being thrown by a handler. Defaults to `false`.

lib/client.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class RPCClient extends EventEmitter {
3030
this._keepAliveAbortController = undefined;
3131
this._pendingPingResponse = false;
3232
this._lastPingTime = 0;
33+
this._skipNextPing = false;
3334
this._closePromise = undefined;
3435
this._protocolOptions = [];
3536
this._protocol = undefined;
@@ -51,6 +52,7 @@ class RPCClient extends EventEmitter {
5152
password: null,
5253
callTimeoutMs: 1000*60,
5354
pingIntervalMs: 1000*30,
55+
deferPingsOnActivity: false,
5456
wsOpts: {},
5557
headers: {},
5658
protocols: [],
@@ -582,13 +584,18 @@ class RPCClient extends EventEmitter {
582584
break;
583585
}
584586

587+
if (this._skipNextPing) {
588+
this._skipNextPing = false;
589+
continue;
590+
}
591+
585592
if (this._pendingPingResponse) {
586593
// we didn't get a response to our last ping
587594
throw Error("Ping timeout");
588595
}
589596

590597
this._lastPingTime = Date.now();
591-
this._pendingPingResponse = true;
598+
this._pendingPingResponse = true;
592599
this._ws.ping();
593600
}
594601

@@ -641,6 +648,10 @@ class RPCClient extends EventEmitter {
641648
}
642649

643650
_onMessage(buffer) {
651+
if (this._options.deferPingsOnActivity) {
652+
this._skipNextPing = true;
653+
}
654+
644655
const message = buffer.toString('utf8');
645656

646657
if (!message.length) {

lib/server.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ class RPCServer extends EventEmitter {
2222
protocols: [],
2323
callTimeoutMs: 1000*30,
2424
pingIntervalMs: 1000*30,
25+
deferPingsOnActivity: false,
2526
respondWithDetailedErrors: false,
2627
callConcurrency: 1,
2728
maxBadMessages: Infinity,
@@ -231,6 +232,7 @@ class RPCServer extends EventEmitter {
231232
reconnect: false,
232233
callTimeoutMs: this._options.callTimeoutMs,
233234
pingIntervalMs: this._options.pingIntervalMs,
235+
deferPingsOnActivity: this._options.deferPingsOnActivity,
234236
respondWithDetailedErrors: this._options.respondWithDetailedErrors,
235237
callConcurrency: this._options.callConcurrency,
236238
strictMode: this._options.strictMode,

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ocpp-rpc",
3-
"version": "1.9.0",
3+
"version": "1.10.0",
44
"description": "A client & server implementation of the WAMP-like RPC-over-websocket system defined in the OCPP protcols (e.g. OCPP1.6-J and OCPP2.0.1).",
55
"main": "index.js",
66
"scripts": {

test/client.js

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2471,6 +2471,77 @@ describe('RPCClient', function(){
24712471

24722472
});
24732473

2474+
2475+
it('should skip pinging client if other activity received with option deferPingsOnActivity', async () => {
2476+
2477+
let pings = 0;
2478+
const {endpoint, close, server} = await createServer({}, {
2479+
withClient: async (client) => {
2480+
client.handle('Echo', async ({params}) => {
2481+
return params;
2482+
});
2483+
for (let i = 0; i < 4; i++) {
2484+
await cli.call('Echo', {});
2485+
await setTimeout(25);
2486+
}
2487+
await client.close();
2488+
}
2489+
});
2490+
const cli = new RPCClient({
2491+
endpoint,
2492+
identity: 'X',
2493+
reconnect: false,
2494+
deferPingsOnActivity: true,
2495+
pingIntervalMs: 40
2496+
});
2497+
2498+
cli.on('ping', () => {++pings;});
2499+
2500+
try {
2501+
await cli.connect();
2502+
await once(cli, 'close');
2503+
assert.equal(pings, 0);
2504+
} finally {
2505+
await cli.close();
2506+
close();
2507+
}
2508+
});
2509+
2510+
it('should allow pinging client if other activity received without option deferPingsOnActivity', async () => {
2511+
2512+
let pings = 0;
2513+
const {endpoint, close, server} = await createServer({}, {
2514+
withClient: async (client) => {
2515+
client.handle('Echo', async ({params}) => {
2516+
return params;
2517+
});
2518+
for (let i = 0; i < 4; i++) {
2519+
await cli.call('Echo', {});
2520+
await setTimeout(25);
2521+
}
2522+
await client.close();
2523+
}
2524+
});
2525+
const cli = new RPCClient({
2526+
endpoint,
2527+
identity: 'X',
2528+
reconnect: false,
2529+
deferPingsOnActivity: false,
2530+
pingIntervalMs: 40
2531+
});
2532+
2533+
cli.on('ping', () => {++pings;});
2534+
2535+
try {
2536+
await cli.connect();
2537+
await once(cli, 'close');
2538+
assert.ok(pings > 0);
2539+
} finally {
2540+
await cli.close();
2541+
close();
2542+
}
2543+
});
2544+
24742545
});
24752546

24762547

test/server.js

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -767,6 +767,68 @@ describe('RPCServer', function(){
767767
}
768768
});
769769

770+
it('should skip pinging client if other activity received with option deferPingsOnActivity', async () => {
771+
772+
let pings = 0;
773+
const {endpoint, close, server} = await createServer({
774+
pingIntervalMs: 40,
775+
deferPingsOnActivity: true,
776+
}, {
777+
withClient: async (client) => {
778+
client.on('ping', () => {++pings;});
779+
}
780+
});
781+
const cli = new RPCClient({
782+
endpoint,
783+
identity: 'X',
784+
reconnect: false,
785+
});
786+
787+
try {
788+
await cli.connect();
789+
for (let i = 0; i < 4; i++) {
790+
await cli.call('Echo', {});
791+
await setTimeout(25);
792+
}
793+
await cli.close();
794+
assert.equal(pings, 0);
795+
} finally {
796+
await cli.close();
797+
close();
798+
}
799+
});
800+
801+
it('should allow pinging client if other activity received without option deferPingsOnActivity', async () => {
802+
803+
let pings = 0;
804+
const {endpoint, close, server} = await createServer({
805+
pingIntervalMs: 40,
806+
deferPingsOnActivity: false,
807+
}, {
808+
withClient: async (client) => {
809+
client.on('ping', () => {++pings;});
810+
}
811+
});
812+
const cli = new RPCClient({
813+
endpoint,
814+
identity: 'X',
815+
reconnect: false,
816+
});
817+
818+
try {
819+
await cli.connect();
820+
for (let i = 0; i < 4; i++) {
821+
await cli.call('Echo', {});
822+
await setTimeout(25);
823+
}
824+
await cli.close();
825+
assert.ok(pings > 0);
826+
} finally {
827+
await cli.close();
828+
close();
829+
}
830+
});
831+
770832

771833
it('should reject non-websocket requests with a 404', async () => {
772834

0 commit comments

Comments
 (0)