whistle
Version:
HTTP, HTTP2, HTTPS, Websocket debugging proxy
223 lines (210 loc) • 5.52 kB
JavaScript
var fork = require('pfork').fork;
var path = require('path');
var LRU = require('lru-cache');
var rulesUtil = require('../rules/util');
var ca = require('../https/ca');
var pluginMgr = require('../plugins');
var request = require('../util/http-mgr').request;
var config = require('../config');
var SCRIPT = path.join(__dirname, 'service.js');
var errors = new LRU({ max: 60, maxAge: 10000 });
var forkOptions;
var curChild;
var curOptions;
var getOptions = function() {
if (!forkOptions) {
forkOptions = {};
/*eslint no-console: "off"*/
Object.keys(config).forEach(function (name) {
var value = config[name];
var type = typeof value;
if (type == 'string' || type == 'number' || type === 'boolean') {
forkOptions[name] = value;
}
});
delete forkOptions.value;
forkOptions.script = SCRIPT;
}
return forkOptions;
};
function handleError(data) {
var error = data.error || 'unknown error';
var list = errors.get(data.clientId) || [];
if (list.indexOf(error) !== -1) {
return;
}
list.push(error);
if (list.length > 12) {
list.shift();
}
errors.set(data.clientId, list);
}
function loadService(callback) {
if (curChild) {
return callback(null, curOptions, curChild);
}
fork(getOptions(), function (err, options, child) {
if (err) {
return callback(err);
}
config.whistleId = options && options.whistleId;
curOptions = options;
curChild = child;
child.once('close', function () {
curChild = null;
});
child.on('data', function (data) {
if (!data) {
return;
}
var type = data.type;
if (type === 'w2NetworkInterfacesChange') {
return process.emit('w2NetworkInterfacesChange');
}
if (type === 'whistleIdChange') {
config.whistleId = data.whistleId;
config.hasWhistleToken = data.hasWhistleToken;
child.sendData({ type: 'whistleId', whistleId: config.whistleId, hasWhistleToken: config.hasWhistleToken });
return;
}
if (type === 'error') {
return handleError(data);
}
if (type === 'installPlugins' && config.installPlugins) {
return config.installPlugins(data.data);
}
});
callback(null, options, child);
}
);
}
function formatData(list) {
if (Array.isArray(list)) {
return list.map(function (item) {
return {
name: item.name,
value: item.data
};
});
}
return Object.keys(list).map(function (key) {
return list[key];
});
}
var notEqual = function(oldData, newData) {
if (!oldData) {
return true;
}
var newLen;
var len;
var i;
var newItem;
var oldItem;
if (Array.isArray(oldData)) {
newLen = newData.length;
if (!newLen) {
return false;
}
len = oldData.length;
if (len !== newLen) {
return true;
}
for (i = 0; i < len; i++) {
oldItem = oldData[i];
newItem = newData[i];
if (oldItem.name !== newItem.name || oldItem.data !== newItem.data) {
return true;
}
}
} else {
var newKeys = Object.keys(newData);
newLen = newKeys.length;
if (!newLen) {
return false;
}
var oldKeys = Object.keys(oldData);
len = oldKeys.length;
if (len !== newLen) {
return true;
}
for (i = 0; i < len; i++) {
var key = oldKeys[i];
newItem = newData[key];
if (!newItem) {
return true;
}
oldItem = oldData[key];
if (oldItem.key !== newItem.key || oldItem.cert !== newItem.cert ||
oldItem.version !== newItem.version || oldItem.registry !== newItem.registry ||
oldItem.type !== newItem.type) {
return true;
}
}
}
return false;
};
var preDataMap = {};
var saveData = function(type, data) {
if (!notEqual(preDataMap[type], data)) {
return;
}
var str;
try {
str = JSON.stringify(formatData(data));
} catch (e) {}
if (!str || str.length < 3) {
return;
}
var body = { type: 'data' };
body[type] = str;
var sendRequest = function(isRetry) {
request({
method: 'POST',
url: 'http://127.0.0.1:' + curOptions.port + '/cgi-bin/service/save',
strictMode: true,
headers: { 'content-type': 'application/json' },
body: body
}, function (err) {
if (err) {
!isRetry && sendRequest(true);
} else {
preDataMap[type] = data;
}
});
};
sendRequest();
};
function sendData() {
loadService(function (err) {
setTimeout(sendData, 3600);
if (err || !config.hasWhistleToken) {
return;
}
var rulesData = rulesUtil.rules.getAllData().list;
var valuesData = rulesUtil.values.list();
var certsData = ca.getPureCertFiles();
var pluginsData = {};
var plugins = pluginMgr.getPlugins();
Object.keys(plugins).sort().forEach(function (name) {
var plugin = plugins[name];
if (plugin && !plugin.isDev && !plugin.notUn && !plugin.isProj) {
pluginsData[plugin.moduleName] = {
name: plugin.moduleName,
version: plugin.version,
registry: plugin.registry
};
}
});
saveData('rules', rulesData);
saveData('values', valuesData);
saveData('certs', certsData);
saveData('plugins', pluginsData);
});
}
process.on('whistleStarted', sendData);
module.exports = loadService;
config.getInstallPluginErrors = function(clientId) {
var list = errors.get(clientId);
errors.del(clientId);
return list;
};