Commit 66277927bc51526a20630df6b741059f576c0fa0
1 parent
a0f2ed6a5b
Exists in
master
isPartnerHealthy
Showing 2 changed files with 31 additions and 0 deletions Inline Diff
adaptor-xmpp.js
1 | var xmpp = require('simple-xmpp'); | 1 | var xmpp = require('simple-xmpp'); |
2 | var moment = require('moment'); | 2 | var moment = require('moment'); |
3 | var MatrixUtil = require('./matrix-util'); | 3 | var MatrixUtil = require('./matrix-util'); |
4 | 4 | ||
5 | var username; | 5 | var username; |
6 | var password; | 6 | var password; |
7 | 7 | ||
8 | var callbacks; | 8 | var callbacks; |
9 | var matrix; | 9 | var matrix; |
10 | var matrixUtil; | 10 | var matrixUtil; |
11 | 11 | ||
12 | function onOnline(data) { | 12 | function onOnline(data) { |
13 | logger.info('XMPP login successful', {data: data}); | 13 | logger.info('XMPP login successful', {data: data}); |
14 | 14 | ||
15 | xmpp.getRoster(); | 15 | xmpp.getRoster(); |
16 | 16 | ||
17 | if (callbacks.onOnline) { | 17 | if (callbacks.onOnline) { |
18 | callbacks.onOnline(); | 18 | callbacks.onOnline(); |
19 | } | 19 | } |
20 | } | 20 | } |
21 | 21 | ||
22 | function onPM(sender, msg) { | 22 | function onPM(sender, msg) { |
23 | if (sender.toLowerCase() == username.replace(/\/.*/, '').toLowerCase()) { | 23 | if (sender.toLowerCase() == username.replace(/\/.*/, '').toLowerCase()) { |
24 | return; | 24 | return; |
25 | } | 25 | } |
26 | 26 | ||
27 | logger.verbose('Got a message', {from: sender, msg: msg}); | 27 | logger.verbose('Got a message', {from: sender, msg: msg}); |
28 | 28 | ||
29 | if (callbacks.onPM) { | 29 | if (callbacks.onPM) { |
30 | callbacks.onPM(sender, msg); | 30 | callbacks.onPM(sender, msg); |
31 | } | 31 | } |
32 | 32 | ||
33 | matrixUtil.updateLastIncoming(sender, msg); | 33 | matrixUtil.updateLastIncoming(sender, msg); |
34 | } | 34 | } |
35 | 35 | ||
36 | function onError(err) { | 36 | function onError(err) { |
37 | logger.warn('XMPP error, terminating in 3 secs', {err: err}); | 37 | logger.warn('XMPP error, terminating in 3 secs', {err: err}); |
38 | setTimeout(process.exit, 3000, 1); | 38 | setTimeout(process.exit, 3000, 1); |
39 | } | 39 | } |
40 | 40 | ||
41 | function onSubscribe(sender) { | 41 | function onSubscribe(sender) { |
42 | xmpp.acceptSubscription(sender); | 42 | xmpp.acceptSubscription(sender); |
43 | } | 43 | } |
44 | 44 | ||
45 | function onUnsubscribe(sender) { | 45 | function onUnsubscribe(sender) { |
46 | xmpp.acceptUnsubscription(sender); | 46 | xmpp.acceptUnsubscription(sender); |
47 | } | 47 | } |
48 | 48 | ||
49 | function onBuddy(jid, state, statusText, resource) { | 49 | function onBuddy(jid, state, statusText, resource) { |
50 | matrixUtil.updateBuddyState(jid, state, statusText, resource); | 50 | matrixUtil.updateBuddyState(jid, state, statusText, resource); |
51 | } | 51 | } |
52 | 52 | ||
53 | function isPartnerOffline(partner) { | 53 | function isPartnerOffline(partner) { |
54 | return matrixUtil.isPartnerOffline(partner); | 54 | return matrixUtil.isPartnerOffline(partner); |
55 | } | 55 | } |
56 | 56 | ||
57 | function isPartnerHealthy(partner) { | ||
58 | return matrixUtil.isPartnerHealthy(partner); | ||
59 | } | ||
60 | |||
57 | function init(_username, _password, _logger, _callbacks) { | 61 | function init(_username, _password, _logger, _callbacks) { |
58 | username = _username; | 62 | username = _username; |
59 | password = _password; | 63 | password = _password; |
60 | logger = _logger; | 64 | logger = _logger; |
61 | callbacks = _callbacks; | 65 | callbacks = _callbacks; |
62 | 66 | ||
63 | xmpp.on('online', onOnline); | 67 | xmpp.on('online', onOnline); |
64 | xmpp.on('chat', onPM); | 68 | xmpp.on('chat', onPM); |
65 | xmpp.on('error', onError); | 69 | xmpp.on('error', onError); |
66 | xmpp.on('subscribe', onSubscribe); | 70 | xmpp.on('subscribe', onSubscribe); |
67 | xmpp.on('unsubscribe', onUnsubscribe); | 71 | xmpp.on('unsubscribe', onUnsubscribe); |
68 | xmpp.on('buddy', onBuddy); | 72 | xmpp.on('buddy', onBuddy); |
69 | 73 | ||
70 | xmpp.unsubscribe(); | 74 | xmpp.unsubscribe(); |
71 | 75 | ||
72 | xmpp.connect({ | 76 | xmpp.connect({ |
73 | jid: username, | 77 | jid: username, |
74 | password: password | 78 | password: password |
75 | }); | 79 | }); |
76 | } | 80 | } |
77 | 81 | ||
78 | function setOptions(options) { | 82 | function setOptions(options) { |
79 | if (!options.matrix) { | 83 | if (!options.matrix) { |
80 | return; | 84 | return; |
81 | } | 85 | } |
82 | 86 | ||
83 | matrix = options.matrix; | 87 | matrix = options.matrix; |
84 | matrixUtil = new MatrixUtil({matrix: matrix, logger: logger}); | 88 | matrixUtil = new MatrixUtil({matrix: matrix, logger: logger}); |
85 | } | 89 | } |
86 | 90 | ||
87 | function sendMessage(destination, msg) { | 91 | function sendMessage(destination, msg) { |
88 | if (!destination) { | 92 | if (!destination) { |
89 | logger.warn('adaptorXmpp.sendMessage: Undefined destination, send message aborted', {destination: destination, msg: msg}); | 93 | logger.warn('adaptorXmpp.sendMessage: Undefined destination, send message aborted', {destination: destination, msg: msg}); |
90 | } | 94 | } |
91 | 95 | ||
92 | if (!msg) { | 96 | if (!msg) { |
93 | logger.warn('adaptorXmpp.sendMessage: Undefined message, send message aborted', {destination: destination, msg: msg}); | 97 | logger.warn('adaptorXmpp.sendMessage: Undefined message, send message aborted', {destination: destination, msg: msg}); |
94 | } | 98 | } |
95 | 99 | ||
96 | 100 | ||
97 | if (destination.toLowerCase() != username.replace(/\/.*/, '').toLowerCase()) { | 101 | if (destination.toLowerCase() != username.replace(/\/.*/, '').toLowerCase()) { |
98 | logger.verbose('Sending message', {from: username, destination: destination, msg: msg}); | 102 | logger.verbose('Sending message', {from: username, destination: destination, msg: msg}); |
99 | } | 103 | } |
100 | 104 | ||
101 | xmpp.send(destination, msg); | 105 | xmpp.send(destination, msg); |
102 | 106 | ||
103 | matrixUtil.updateLastOutgoing(destination, msg); | 107 | matrixUtil.updateLastOutgoing(destination, msg); |
104 | } | 108 | } |
105 | 109 | ||
106 | function addFriend(friend) { | 110 | function addFriend(friend) { |
107 | logger.verbose('Adding XMPP friend: ' + friend); | 111 | logger.verbose('Adding XMPP friend: ' + friend); |
108 | xmpp.subscribe(friend); | 112 | xmpp.subscribe(friend); |
109 | } | 113 | } |
110 | 114 | ||
111 | exports.init = init; | 115 | exports.init = init; |
112 | exports.sendMessage = sendMessage; | 116 | exports.sendMessage = sendMessage; |
113 | exports.setOptions = setOptions; | 117 | exports.setOptions = setOptions; |
114 | exports.addFriend = addFriend; | 118 | exports.addFriend = addFriend; |
115 | exports.isPartnerOffline = isPartnerOffline; | 119 | exports.isPartnerOffline = isPartnerOffline; |
116 | 120 |
matrix-util.js
1 | 'use strict'; | 1 | 'use strict'; |
2 | 2 | ||
3 | var moment = require('moment'); | 3 | var moment = require('moment'); |
4 | var momentFormat = 'YYYY-MM-DD HH:mm:ss'; | 4 | var momentFormat = 'YYYY-MM-DD HH:mm:ss'; |
5 | var maxHealthyWaitMs = 60 * 1000; | ||
5 | 6 | ||
6 | module.exports = MatrixUtil; | 7 | module.exports = MatrixUtil; |
7 | 8 | ||
8 | function _cleanPartnerId(partnerId) { | 9 | function _cleanPartnerId(partnerId) { |
9 | let cleaned = partnerId; | 10 | let cleaned = partnerId; |
10 | 11 | ||
11 | try { | 12 | try { |
12 | cleaned = cleaned.toLocaleString(); | 13 | cleaned = cleaned.toLocaleString(); |
13 | cleaned = cleaned.trim().toLowerCase(); | 14 | cleaned = cleaned.trim().toLowerCase(); |
14 | } catch(e) { | 15 | } catch(e) { |
15 | return partnerId; | 16 | return partnerId; |
16 | } | 17 | } |
17 | 18 | ||
18 | return cleaned; | 19 | return cleaned; |
19 | } | 20 | } |
20 | 21 | ||
21 | function MatrixUtil(options) { | 22 | function MatrixUtil(options) { |
22 | if (!options) { | 23 | if (!options) { |
23 | console.trace('Undefined options'); | 24 | console.trace('Undefined options'); |
24 | process.exit(1); | 25 | process.exit(1); |
25 | } | 26 | } |
26 | 27 | ||
27 | this.matrix = options.matrix; | 28 | this.matrix = options.matrix; |
28 | if (!this.matrix) { | 29 | if (!this.matrix) { |
29 | console.trace("Matrix not set"); | 30 | console.trace("Matrix not set"); |
30 | process.exit(1); | 31 | process.exit(1); |
31 | } | 32 | } |
32 | 33 | ||
33 | this.logger = options.logger; | 34 | this.logger = options.logger; |
34 | if (!this.logger) { | 35 | if (!this.logger) { |
35 | console.trace("Logger not set"); | 36 | console.trace("Logger not set"); |
36 | process.exit(1); | 37 | process.exit(1); |
37 | } | 38 | } |
38 | } | 39 | } |
39 | 40 | ||
40 | MatrixUtil.prototype.updateBuddyState = function(jid, state, statusText, resource) { | 41 | MatrixUtil.prototype.updateBuddyState = function(jid, state, statusText, resource) { |
41 | if (!jid) {return; } | 42 | if (!jid) {return; } |
42 | if (jid == 'undefined') {return; } | 43 | if (jid == 'undefined') {return; } |
43 | 44 | ||
44 | jid = _cleanPartnerId(jid); | 45 | jid = _cleanPartnerId(jid); |
45 | 46 | ||
46 | if (!resource) { | 47 | if (!resource) { |
47 | resource = 'undefined'; | 48 | resource = 'undefined'; |
48 | } | 49 | } |
49 | 50 | ||
50 | let logger = this.logger; | 51 | let logger = this.logger; |
51 | let matrix = this.matrix; | 52 | let matrix = this.matrix; |
52 | 53 | ||
53 | logger.verbose('Buddy state change', {jid: jid, state: state, statusText: statusText, resource: resource}); | 54 | logger.verbose('Buddy state change', {jid: jid, state: state, statusText: statusText, resource: resource}); |
54 | 55 | ||
55 | if (!matrix) { | 56 | if (!matrix) { |
56 | return; | 57 | return; |
57 | } | 58 | } |
58 | 59 | ||
59 | if (!matrix.buddies) { | 60 | if (!matrix.buddies) { |
60 | matrix.buddies = {}; | 61 | matrix.buddies = {}; |
61 | } | 62 | } |
62 | 63 | ||
63 | if (!matrix.buddies[jid]) { | 64 | if (!matrix.buddies[jid]) { |
64 | matrix.buddies[jid] = {resources: {}}; | 65 | matrix.buddies[jid] = {resources: {}}; |
65 | } | 66 | } |
66 | 67 | ||
67 | try { | 68 | try { |
68 | matrix.buddies[jid]['resources'][resource] = { | 69 | matrix.buddies[jid]['resources'][resource] = { |
69 | state: state, | 70 | state: state, |
70 | statusText: statusText, | 71 | statusText: statusText, |
71 | last_update: moment().format(momentFormat) | 72 | last_update: moment().format(momentFormat) |
72 | } | 73 | } |
73 | } | 74 | } |
74 | catch(e) { | 75 | catch(e) { |
75 | logger.warn('MatrixUtil: Exception on update resources on matrix', {jid: jid, state: state, statusText: statusText, resource: resource}); | 76 | logger.warn('MatrixUtil: Exception on update resources on matrix', {jid: jid, state: state, statusText: statusText, resource: resource}); |
76 | } | 77 | } |
77 | 78 | ||
78 | if (resource != 'undefined' && matrix.buddies[jid].resources['undefined']) { | 79 | if (resource != 'undefined' && matrix.buddies[jid].resources['undefined']) { |
79 | try { | 80 | try { |
80 | delete matrix.buddies[jid].resources['undefined']; | 81 | delete matrix.buddies[jid].resources['undefined']; |
81 | } | 82 | } |
82 | catch(e) {}; | 83 | catch(e) {}; |
83 | } | 84 | } |
84 | } | 85 | } |
85 | 86 | ||
86 | MatrixUtil.prototype.isPartnerOffline = function(partner) { | 87 | MatrixUtil.prototype.isPartnerOffline = function(partner) { |
87 | if (!partner) { return; } | 88 | if (!partner) { return; } |
88 | 89 | ||
89 | partner = _cleanPartnerId(partner); | 90 | partner = _cleanPartnerId(partner); |
90 | 91 | ||
91 | let matrix = this.matrix; | 92 | let matrix = this.matrix; |
92 | let logger = this.logger; | 93 | let logger = this.logger; |
93 | 94 | ||
94 | if (!matrix) { return false; } | 95 | if (!matrix) { return false; } |
95 | 96 | ||
96 | if (!matrix.buddies[partner]) { return true; } | 97 | if (!matrix.buddies[partner]) { return true; } |
97 | if (!matrix.buddies[partner].resources) { return true; }; | 98 | if (!matrix.buddies[partner].resources) { return true; }; |
98 | 99 | ||
99 | let resources = matrix.buddies[partner].resources; | 100 | let resources = matrix.buddies[partner].resources; |
100 | for (let key in resources) { | 101 | for (let key in resources) { |
101 | if (resources.hasOwnProperty(key)) { | 102 | if (resources.hasOwnProperty(key)) { |
102 | let resource = resources[key]; | 103 | let resource = resources[key]; |
103 | if (resources[key].state == 'online') { | 104 | if (resources[key].state == 'online') { |
104 | return false; | 105 | return false; |
105 | } | 106 | } |
106 | } | 107 | } |
107 | } | 108 | } |
108 | logger.verbose('Offline partner detected: ' + partner); | 109 | logger.verbose('Offline partner detected: ' + partner); |
109 | return true; | 110 | return true; |
110 | } | 111 | } |
111 | 112 | ||
113 | MatrixUtil.prototype.isPartnerHealthy = function(partner) { | ||
114 | if (!partner) { return; } | ||
115 | partner = _cleanPartnerId(partner); | ||
116 | |||
117 | if (this.isPartnerOffline(partner)) { | ||
118 | return; | ||
119 | } | ||
120 | |||
121 | let matrix = this.matrix; | ||
122 | let logger = this.logger; | ||
123 | |||
124 | if (!matrix) { return false; } | ||
125 | |||
126 | if (!matrix.buddies[partner]) { return false; } | ||
127 | if (!matrix.buddies[partner]['waiting_for_response']) { return true; } | ||
128 | if (!matrix.buddies[partner]['last_outgoing']) { return true; } | ||
129 | if (!matrix.buddies[partner]['last_outgoing']['last_update_ts']) { return true; } | ||
130 | |||
131 | let delta = Date.now() - Number(matrix.buddies[partner]['last_outgoing']['last_update_ts']); | ||
132 | let isHealthy = delta <= maxHealthyWaitMs; | ||
133 | |||
134 | logger.verbose('Partner healthy analized', {partner: partner, isHealthy: isHealthy, delta: delta, maxHealthyWaitMs: maxHealthyWaitMs}); | ||
135 | return isHealthy; | ||
136 | } | ||
137 | |||
138 | |||
112 | MatrixUtil.prototype._updateLastResponseTime = function(partner) { | 139 | MatrixUtil.prototype._updateLastResponseTime = function(partner) { |
113 | let matrix = this.matrix; | 140 | let matrix = this.matrix; |
114 | let logger = this.logger; | 141 | let logger = this.logger; |
115 | 142 | ||
116 | if (!matrix.buddies[partner]['last_outgoing']) { | 143 | if (!matrix.buddies[partner]['last_outgoing']) { |
117 | logger.verbose('No outgoing yet, skip updateLastResponseTime'); | 144 | logger.verbose('No outgoing yet, skip updateLastResponseTime'); |
118 | return; | 145 | return; |
119 | } | 146 | } |
120 | 147 | ||
121 | if (!matrix.buddies[partner]['last_outgoing']['last_update_ts']) { | 148 | if (!matrix.buddies[partner]['last_outgoing']['last_update_ts']) { |
122 | logger.verbose('No outgoing timestamp yet, skip updateLastResponseTime'); | 149 | logger.verbose('No outgoing timestamp yet, skip updateLastResponseTime'); |
123 | return; | 150 | return; |
124 | } | 151 | } |
125 | 152 | ||
126 | if ( | 153 | if ( |
127 | matrix.buddies[partner]['last_incoming'] | 154 | matrix.buddies[partner]['last_incoming'] |
128 | && (Number(matrix.buddies[partner]['last_incoming']['last_update_ts']) > Number(matrix.buddies[partner]['last_outgoing']['last_update_ts'])) | 155 | && (Number(matrix.buddies[partner]['last_incoming']['last_update_ts']) > Number(matrix.buddies[partner]['last_outgoing']['last_update_ts'])) |
129 | ) { | 156 | ) { |
130 | return; | 157 | return; |
131 | } | 158 | } |
132 | 159 | ||
133 | let delta = Date.now() - Number(matrix.buddies[partner]['last_outgoing']['last_update_ts']); | 160 | let delta = Date.now() - Number(matrix.buddies[partner]['last_outgoing']['last_update_ts']); |
134 | delta = (delta / 1000).toFixed(2); | 161 | delta = (delta / 1000).toFixed(2); |
135 | logger.verbose('MatrixUtil: Response time in ' + delta + ' seconds', {partner: partner}); | 162 | logger.verbose('MatrixUtil: Response time in ' + delta + ' seconds', {partner: partner}); |
136 | matrix.buddies[partner]['last_response_time_in_secs'] = delta; | 163 | matrix.buddies[partner]['last_response_time_in_secs'] = delta; |
137 | } | 164 | } |
138 | 165 | ||
139 | MatrixUtil.prototype._updateLastMessage = function(partner, msg, direction) { | 166 | MatrixUtil.prototype._updateLastMessage = function(partner, msg, direction) { |
140 | if (!partner) { return; } | 167 | if (!partner) { return; } |
141 | partner = _cleanPartnerId(partner); | 168 | partner = _cleanPartnerId(partner); |
142 | 169 | ||
143 | let matrix = this.matrix; | 170 | let matrix = this.matrix; |
144 | let logger = this.logger; | 171 | let logger = this.logger; |
145 | 172 | ||
146 | if (!matrix) { | 173 | if (!matrix) { |
147 | return; | 174 | return; |
148 | } | 175 | } |
149 | 176 | ||
150 | if (!matrix.buddies) { | 177 | if (!matrix.buddies) { |
151 | matrix.buddies = {}; | 178 | matrix.buddies = {}; |
152 | } | 179 | } |
153 | 180 | ||
154 | if (!matrix.buddies[partner]) { | 181 | if (!matrix.buddies[partner]) { |
155 | matrix.buddies[partner] = {}; | 182 | matrix.buddies[partner] = {}; |
156 | } | 183 | } |
157 | 184 | ||
158 | if (direction == 'incoming') { | 185 | if (direction == 'incoming') { |
159 | try { | 186 | try { |
160 | this._updateLastResponseTime(partner); | 187 | this._updateLastResponseTime(partner); |
161 | } | 188 | } |
162 | catch(e) { | 189 | catch(e) { |
163 | logger.warn('Exception when updateLastResponseTime', {err: e}); | 190 | logger.warn('Exception when updateLastResponseTime', {err: e}); |
164 | } | 191 | } |
165 | } | 192 | } |
166 | 193 | ||
167 | matrix.buddies[partner]['waiting_for_response'] = (direction == 'outgoing'); | 194 | matrix.buddies[partner]['waiting_for_response'] = (direction == 'outgoing'); |
168 | 195 | ||
169 | matrix.buddies[partner]['last_' + direction] = { | 196 | matrix.buddies[partner]['last_' + direction] = { |
170 | msg: msg, | 197 | msg: msg, |
171 | last_update: moment().format(momentFormat), | 198 | last_update: moment().format(momentFormat), |
172 | last_update_ts: Date.now() | 199 | last_update_ts: Date.now() |
173 | } | 200 | } |
174 | 201 | ||
175 | if (direction == 'outgoing') { | 202 | if (direction == 'outgoing') { |
176 | return; | 203 | return; |
177 | } | 204 | } |
178 | } | 205 | } |
179 | 206 | ||
180 | 207 | ||
181 | MatrixUtil.prototype.updateLastIncoming = function(partner, msg) { | 208 | MatrixUtil.prototype.updateLastIncoming = function(partner, msg) { |
182 | this._updateLastMessage(partner, msg, 'incoming'); | 209 | this._updateLastMessage(partner, msg, 'incoming'); |
183 | } | 210 | } |
184 | 211 | ||
185 | MatrixUtil.prototype.updateLastOutgoing = function(partner, msg) { | 212 | MatrixUtil.prototype.updateLastOutgoing = function(partner, msg) { |
186 | this._updateLastMessage(partner, msg, 'outgoing'); | 213 | this._updateLastMessage(partner, msg, 'outgoing'); |
187 | } | 214 | } |
188 | 215 |