85062559ac265ca8c4f5844bad3097f5289bb1a9
[aai/esr-gui.git] /
1 "use strict"
2
3 var os = require('os'),
4   f = require('util').format;
5
6 /**
7  * Emit event if it exists
8  * @method
9  */
10 function emitSDAMEvent(self, event, description) {
11   if(self.listeners(event).length > 0) {
12     self.emit(event, description);
13   }
14 }
15
16 // Get package.json variable
17 var driverVersion = require(__dirname + '/../../package.json').version;
18 var nodejsversion = f('Node.js %s, %s', process.version, os.endianness());
19 var type = os.type();
20 var name = process.platform;
21 var architecture = process.arch;
22 var release = os.release();
23
24 function createClientInfo(options) {
25   // Build default client information
26   var clientInfo = options.clientInfo ? clone(options.clientInfo) : {
27     driver: {
28       name: "nodejs-core",
29       version: driverVersion
30     },
31     os: {
32       type: type,
33       name: name,
34       architecture: architecture,
35       version: release
36     }
37   }
38
39   // Is platform specified
40   if(clientInfo.platform && clientInfo.platform.indexOf('mongodb-core') == -1) {
41     clientInfo.platform = f('%s, mongodb-core: %s', clientInfo.platform, driverVersion);
42   } else if(!clientInfo.platform){
43     clientInfo.platform = nodejsversion;
44   }
45
46   // Do we have an application specific string
47   if(options.appname) {
48     // Cut at 128 bytes
49     var buffer = new Buffer(options.appname);
50     // Return the truncated appname
51     var appname = buffer.length > 128 ? buffer.slice(0, 128).toString('utf8') : options.appname;
52     // Add to the clientInfo
53     clientInfo.application = { name: appname };
54   }
55
56   return clientInfo;
57 }
58
59 function clone(object) {
60   return JSON.parse(JSON.stringify(object));
61 }
62
63 var getPreviousDescription = function(self) {
64   if(!self.s.serverDescription) {
65     self.s.serverDescription = {
66       address: self.name,
67       arbiters: [], hosts: [], passives: [], type: 'Unknown'
68     }
69   }
70
71   return self.s.serverDescription;
72 }
73
74 var emitServerDescriptionChanged = function(self, description) {
75   if(self.listeners('serverDescriptionChanged').length > 0) {
76     // Emit the server description changed events
77     self.emit('serverDescriptionChanged', {
78       topologyId: self.s.topologyId != -1 ? self.s.topologyId : self.id, address: self.name,
79       previousDescription: getPreviousDescription(self),
80       newDescription: description
81     });
82
83     self.s.serverDescription = description;
84   }
85 }
86
87 var getPreviousTopologyDescription = function(self) {
88   if(!self.s.topologyDescription) {
89     self.s.topologyDescription = {
90       topologyType: 'Unknown',
91       servers: [{
92         address: self.name, arbiters: [], hosts: [], passives: [], type: 'Unknown'
93       }]
94     }
95   }
96
97   return self.s.topologyDescription;
98 }
99
100 var emitTopologyDescriptionChanged = function(self, description) {
101   if(self.listeners('topologyDescriptionChanged').length > 0) {
102     // Emit the server description changed events
103     self.emit('topologyDescriptionChanged', {
104       topologyId: self.s.topologyId != -1 ? self.s.topologyId : self.id, address: self.name,
105       previousDescription: getPreviousTopologyDescription(self),
106       newDescription: description
107     });
108
109     self.s.serverDescription = description;
110   }
111 }
112
113 var changedIsMaster = function(self, currentIsmaster, ismaster) {
114   var currentType = getTopologyType(self, currentIsmaster);
115   var newType = getTopologyType(self, ismaster);
116   if(newType != currentType) return true;
117   return false;
118 }
119
120 var getTopologyType = function(self, ismaster) {
121   if(!ismaster) {
122     ismaster = self.ismaster;
123   }
124
125   if(!ismaster) return 'Unknown';
126   if(ismaster.ismaster && !ismaster.hosts) return 'Standalone';
127   if(ismaster.ismaster && ismaster.msg == 'isdbgrid') return 'Mongos';
128   if(ismaster.ismaster) return 'RSPrimary';
129   if(ismaster.secondary) return 'RSSecondary';
130   if(ismaster.arbiterOnly) return 'RSArbiter';
131   return 'Unknown';
132 }
133
134 var inquireServerState = function(self) {
135   return function(callback) {
136     if(self.s.state == 'destroyed') return;
137     // Record response time
138     var start = new Date().getTime();
139
140     // emitSDAMEvent
141     emitSDAMEvent(self, 'serverHeartbeatStarted', { connectionId: self.name });
142
143     // Attempt to execute ismaster command
144     self.command('admin.$cmd', { ismaster:true },  { monitoring:true }, function(err, r) {
145       if(!err) {
146         // Legacy event sender
147         self.emit('ismaster', r, self);
148
149         // Calculate latencyMS
150         var latencyMS = new Date().getTime() - start;
151
152         // Server heart beat event
153         emitSDAMEvent(self, 'serverHeartbeatSucceeded', { durationMS: latencyMS, reply: r.result, connectionId: self.name });
154
155         // Did the server change
156         if(changedIsMaster(self, self.s.ismaster, r.result)) {
157           // Emit server description changed if something listening
158           emitServerDescriptionChanged(self, {
159             address: self.name, arbiters: [], hosts: [], passives: [], type: !self.s.inTopology ? 'Standalone' : getTopologyType(self)
160           });
161         }
162
163         // Updat ismaster view
164         self.s.ismaster = r.result;
165
166         // Set server response time
167         self.s.isMasterLatencyMS = latencyMS;
168       } else {
169         emitSDAMEvent(self, 'serverHeartbeatFailed', { durationMS: latencyMS, failure: err, connectionId: self.name });
170       }
171
172       // Peforming an ismaster monitoring callback operation
173       if(typeof callback == 'function') {
174         return callback(err, r);
175       }
176
177       // Perform another sweep
178       self.s.inquireServerStateTimeout = setTimeout(inquireServerState(self), self.s.haInterval);
179     });
180   };
181 }
182
183 // Object.assign method or polyfille
184 var assign = Object.assign ? Object.assign : function assign(target, firstSource) {
185   if (target === undefined || target === null) {
186     throw new TypeError('Cannot convert first argument to object');
187   }
188
189   var to = Object(target);
190   for (var i = 1; i < arguments.length; i++) {
191     var nextSource = arguments[i];
192     if (nextSource === undefined || nextSource === null) {
193       continue;
194     }
195
196     var keysArray = Object.keys(Object(nextSource));
197     for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
198       var nextKey = keysArray[nextIndex];
199       var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
200       if (desc !== undefined && desc.enumerable) {
201         to[nextKey] = nextSource[nextKey];
202       }
203     }
204   }
205   return to;
206 }
207
208 //
209 // Clone the options
210 var cloneOptions = function(options) {
211   var opts = {};
212   for(var name in options) {
213     opts[name] = options[name];
214   }
215   return opts;
216 }
217
218 module.exports.inquireServerState = inquireServerState
219 module.exports.getTopologyType = getTopologyType;
220 module.exports.emitServerDescriptionChanged = emitServerDescriptionChanged;
221 module.exports.emitTopologyDescriptionChanged = emitTopologyDescriptionChanged;
222 module.exports.cloneOptions = cloneOptions;
223 module.exports.assign = assign;
224 module.exports.createClientInfo = createClientInfo;
225 module.exports.clone = clone;