Commit 66277927bc51526a20630df6b741059f576c0fa0

Authored by Adhidarma Hadiwinoto
1 parent a0f2ed6a5b
Exists in master

isPartnerHealthy

Showing 2 changed files with 31 additions and 0 deletions Inline Diff

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
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