From b035fce8659cb9a3294a10c9bcb49e8294e4ce94 Mon Sep 17 00:00:00 2001 From: Hans-Peter Herzog Date: Tue, 30 May 2017 15:45:54 +0200 Subject: [PATCH] TT#16811 Wait for late acknowledgements to complete transaction without exception Change-Id: Ida7ad9a0fcbaf17972a6449986142f2aa3ffc3cf --- package.json | 2 +- src/transaction.js | 33 ++++++++++++++++++---- test/transaction-spec.js | 61 +++++++++++++++++++++++++++++++++++----- 3 files changed, 83 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index f896eea..f43737a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "janus-videoroom-client", - "version": "3.2.1", + "version": "3.2.2", "main": "src/janus.js", "scripts": { "test": "mocha -R spec --full-trace test/*-spec.js" diff --git a/src/transaction.js b/src/transaction.js index 2b214e0..64f7ce5 100644 --- a/src/transaction.js +++ b/src/transaction.js @@ -12,6 +12,7 @@ var State = { new: 'new', started: 'started', sent: 'sent', + receiving: 'receiving', ended: 'ended' }; @@ -68,6 +69,13 @@ class Transaction { this.timeout = _.get(options, 'timeout', 12000); this.ack = _.get(options, 'ack', false); _.set(this.request, 'transaction', this.id); + this.ackReceived = false; + this.responseReceived = false; + this.lateAck = false; + } + + isLateAck() { + return this.lateAck; } getId() { @@ -87,7 +95,6 @@ class Transaction { this.state = State.started; this.startTimeout(); this.client.sendObject(this.getRequest()).then(()=>{ - this.state = State.sent; this.emitter.emit('sent', this.getRequest()); }).catch((err)=>{ this.error(err); @@ -102,15 +109,30 @@ class Transaction { assert.instanceOf(res, ClientResponse); assert.property(res.getResponse(), 'transaction', 'Missing transaction id'); assert.equal(res.getResponse().transaction, this.getId(), 'Invalid transaction id'); - if(this.state === State.sent) { + if(this.state === State.started || this.state === State.receiving) { + this.state = State.receiving; if(res.isError()) { this.error(new ResponseError(res)); - } else if(this.ack && res.isAck()) { - this.startTimeout(); + } else if(this.ack === true && res.isAck()) { + + this.ackReceived = true; this.emitter.emit(Event.ack, res); + if(this.responseReceived === true) { + this.lateAck = true; + this.end(); + } else { + this.startTimeout(); + } + } else { - this.end(); + + this.responseReceived = true; this.emitter.emit(Event.response, res); + if(this.ack === true && this.ackReceived === false) { + this.startTimeout(); + } else { + this.end(); + } } } else { this.error(new InvalidTransactionState(this)); @@ -176,3 +198,4 @@ class Transaction { module.exports.Transaction = Transaction; module.exports.TransactionTimeoutError = TransactionTimeoutError; module.exports.InvalidTransactionState = InvalidTransactionState; +module.exports.TransactionState = State; diff --git a/test/transaction-spec.js b/test/transaction-spec.js index 23846ea..e2506cb 100644 --- a/test/transaction-spec.js +++ b/test/transaction-spec.js @@ -1,6 +1,7 @@ 'use strict'; var Transaction = require('../src/transaction').Transaction; +var TransactionState = require('../src/transaction').TransactionState; var TransactionTimeoutError = require('../src/transaction').TransactionTimeoutError; var InvalidTransactionState = require('../src/transaction').InvalidTransactionState; var ClientResponse = require('../src/client/response').ClientResponse; @@ -67,10 +68,12 @@ describe('Transaction', function(){ transaction: transaction.getId() }; transaction.onSent(()=>{ + assert.equal(transaction.getState(), TransactionState.started); transaction.response(new ClientResponse(request, response)); }).onResponse((res)=>{ - assert.equal(transaction.getState(), 'ended'); + assert.equal(transaction.getState(), TransactionState.receiving); assert.deepEqual(res.getResponse(), response); + }).onEnd(()=>{ done(); }).start(); }); @@ -85,15 +88,17 @@ describe('Transaction', function(){ }); this.timeout(timeout + 500); transaction.onError(function(err){ - assert.equal(transaction.getState(), 'ended'); + assert.equal(transaction.getState(), TransactionState.ended); assert.instanceOf(err, TransactionTimeoutError); + }).onEnd(()=>{ + assert.equal(transaction.getState(), TransactionState.ended); done(); }).start(); }); it('should receive ack and response', function(done){ - var ack = true; + var hasAck = false; var transaction = new Transaction({ request: request, client: clientMock, @@ -103,14 +108,54 @@ describe('Transaction', function(){ janus: 'success', transaction: transaction.getId() }; + var ack = { + janus: 'ack', + transaction: transaction.getId() + }; transaction.onSent(()=>{ + assert.equal(transaction.getState(), TransactionState.started); + transaction.response(new ClientResponse(request, ack)); transaction.response(new ClientResponse(request, response)); }).onAck(()=>{ - ack = true; + assert.equal(transaction.getState(), TransactionState.receiving); + hasAck = true; }).onResponse((res)=>{ - assert.equal(transaction.getState(), 'ended'); + assert.equal(transaction.getState(), TransactionState.receiving); assert.deepEqual(res.getResponse(), response); - assert.isTrue(ack); + assert.isTrue(hasAck); + }).onEnd(()=>{ + done(); + }).start(); + }); + + it('should receive response and late ack ', function(done){ + + var hasResponse = true; + var transaction = new Transaction({ + request: request, + client: clientMock, + ack: true + }); + var response = { + janus: 'success', + transaction: transaction.getId() + }; + var ack = { + janus: 'ack', + transaction: transaction.getId() + }; + transaction.onSent(()=>{ + assert.equal(transaction.getState(), TransactionState.started); + transaction.response(new ClientResponse(request, response)); + transaction.response(new ClientResponse(request, ack)); + }).onAck(()=>{ + assert.equal(transaction.getState(), TransactionState.receiving); + assert.isTrue(hasResponse); + }).onResponse((res)=>{ + assert.equal(transaction.getState(), TransactionState.receiving); + hasResponse = true; + assert.deepEqual(res.getResponse(), response); + }).onEnd(()=>{ done(); }).start(); }); @@ -132,11 +177,13 @@ describe('Transaction', function(){ transaction: transaction.getId() }; transaction.onSent(()=>{ + assert.equal(transaction.getState(), TransactionState.started); transaction.response(new ClientResponse(request, response)); }).onAck(()=>{ + assert.equal(transaction.getState(), TransactionState.receiving); ack = true; }).onError(function(err){ - assert.equal(transaction.getState(), 'ended'); + assert.equal(transaction.getState(), TransactionState.ended); assert.instanceOf(err, TransactionTimeoutError); assert.isTrue(ack); done();