whistle
Version:
HTTP, HTTP2, HTTPS, Websocket debugging proxy
272 lines (240 loc) • 6.86 kB
JavaScript
var fs = require('fs');
var fse = require('fs-extra2');
var path = require('path');
var util = require('../util');
var config = require('../config');
var protocols = require('../rules/protocols');
var ORG_RE = /^@[\w-]+$/;
var WHISLTE_PLUGIN_RE = /^whistle\.[a-z\d_\-]+$/;
var PLUGIN_NAME_RE = /^(?:@[\w-]+\/)?(whistle\.[a-z\d_\-]+)$/;
var DEV_PLUGINS_PATH = config.DEV_PLUGINS_PATH;
var MAX_EXPIRE = 36000;
var UTF8_OPTIONS = { encoding: 'utf8' };
var workerScript = util.readFileSync(path.join(__dirname, '../../assets/js/worker.js'));
var workers = {};
function replaceScript(ctn) {
return workerScript && workerScript.replace('/*sourcecode*/', ctn);
}
exports.readWorkerSync = function(root, conf) {
var file = util.getWebWorker(conf);
file = file && util.readFileSync(path.join(root, file));
if (!file) {
return;
}
var id = util.createHash(file);
workers[id] = replaceScript(file);
return id;
};
exports.readWorker = function(root, conf, callback) {
var file = util.getWebWorker(conf);
if (!file) {
return callback();
}
readFile(path.join(root, file), function(err, ctn) {
if (err || !ctn) {
return callback();
}
var id = util.createHash(ctn);
workers[id] = replaceScript(ctn);
callback(id);
});
};
exports.getWorker = function(id) {
return workers[id];
};
exports.resetWorkers = function(plugins) {
var _workers = {};
Object.keys(plugins).forEach(function(key) {
var plugin = plugins[key];
_workers[plugin.webWorker] = workers[plugin.webWorker];
});
workers = _workers;
};
function isOrgModule(name) {
return ORG_RE.test(name);
}
exports.isOrgModule = isOrgModule;
exports.isPluginName = function(name) {
return PLUGIN_NAME_RE.test(name);
};
function isWhistleModule(name) {
return WHISLTE_PLUGIN_RE.test(name);
}
exports.isWhistleModule = isWhistleModule;
function getHomePageFromPackage(pkg) {
if (util.isUrl(pkg.homepage)) {
return pkg.homepage;
}
return extractUrl(pkg.repository) || '';
}
function extractUrl(repository) {
if (
!repository ||
repository.type != 'git' ||
typeof repository.url != 'string'
) {
return;
}
var url = repository.url.replace(/^git\+/i, '');
if (!util.isUrl(url)) {
url = url.replace(/^git@([^:]+):/, 'http://$1/');
}
return url.replace(/\.git\s*$/i, '');
}
exports.getHomePageFromPackage = getHomePageFromPackage;
exports.parseValues = function (val) {
if (val) {
val = util.parseJSON(val);
}
if (!val) {
return '';
}
Object.keys(val).forEach(function (key) {
val[key] = util.toString(val[key]);
});
return val;
};
exports.getPluginHomepage = function (pkg) {
var url = pkg.pluginHomepage || pkg.pluginHomePage;
return typeof url === 'string' ? url : undefined;
};
exports.excludePlugin = function (name) {
if (
protocols.contains(name) ||
(config.allowPluginList && config.allowPluginList.indexOf(name) === -1)
) {
return true;
}
return config.blockPluginList && config.blockPluginList.indexOf(name) !== -1;
};
function setPlugin(plugins, pkg, root, mtime, sync) {
if (PLUGIN_NAME_RE.test(pkg.name)) {
var name = sync ? RegExp.$1 : RegExp.$1.split('.', 2)[1];
plugins[name] = {
root: root,
mtime: mtime,
notUn: true,
isProj: true,
isDev: true
};
}
}
exports.readDevPluginsSync = function() {
var plugins = {};
try {
var files = fs.readdirSync(DEV_PLUGINS_PATH);
files.forEach(function(file) {
file = path.join(DEV_PLUGINS_PATH, file);
try {
var ctn = fs.readFileSync(file, UTF8_OPTIONS).split('\n');
if (Date.now() - ctn[0] < MAX_EXPIRE && ctn[1]) {
var root = ctn[1];
var pkgPath = path.join(root, 'package.json');
var stats = fs.statSync(pkgPath);
var pkg = fse.readJsonSync(pkgPath);
setPlugin(plugins, pkg, root, stats.mtime.getTime(), true);
} else {
fs.unlinkSync(file);
}
} catch (e) {}
});
} catch (e) {}
return plugins;
};
function readFile(filepath, callback) {
fs.readFile(filepath, UTF8_OPTIONS, function (err, text) {
if (!err) {
return callback(err, text);
}
fs.readFile(filepath, UTF8_OPTIONS, callback);
});
}
function readDir(dir, callback) {
fs.readdir(dir, function (err, list) {
if (!err) {
return callback(err, list);
}
fs.readdir(dir, callback);
});
}
function statFile(filepath, callback) {
fs.stat(filepath, function (_, stat1) {
if (stat1) {
return callback(stat1.isFile() && stat1);
}
fs.stat(filepath, function (_, stat2) {
callback(stat2 && stat2.isFile() && stat2);
});
});
}
exports.readFile = readFile;
exports.readDir = readDir;
exports.statFile = statFile;
exports.readDevPlugins = function(callback) {
var plugins = {};
readDir(DEV_PLUGINS_PATH, function(err, files) {
var len = files && files.length;
if (!len) {
return callback(plugins);
}
files.forEach(function(file) {
file = path.join(DEV_PLUGINS_PATH, file);
readFile(file, function(_, ctn) {
ctn = ctn && ctn.split('\n');
if (ctn && Date.now() - ctn[0] < MAX_EXPIRE && ctn[1]) {
var root = ctn[1];
var pkgPath = path.join(root, 'package.json');
readFile(pkgPath, function(_, pkg) {
if (pkg) {
try {
pkg = JSON.parse(pkg);
return statFile(pkgPath, function(stats) {
stats && setPlugin(plugins, pkg, root, stats.mtime.getTime());
--len === 0 && callback(plugins);
});
} catch (e) {}
}
--len === 0 && callback(plugins);
});
} else {
fs.unlink(file, util.noop);
--len === 0 && callback(plugins);
}
});
});
});
};
function fsExistsSync(filepath, retry) {
try {
return fs.existsSync(filepath);
} catch (e) {}
return !retry && fsExistsSync(filepath, true);
}
function fsExists(filepath, cb, retry) {
fs.stat(filepath, function(err, stat) {
if (err) {
if (retry || err.code === 'ENOENT') {
return cb();
}
return fsExists(filepath, cb, true);
}
cb(stat.isFile());
});
}
exports.getSysPathSync = function(dir, name, org) {
var root = org ? path.join(dir, name, 'node_modules', org, name) : path.join(dir, name, 'node_modules', name);
if (fsExistsSync(path.join(root, 'package.json'))) {
return root;
}
return path.join(dir, name);
};
exports.getSysPath = function(dir, name, isSys, cb) {
var root = path.join(dir, name);
if (!isSys) {
return cb(root);
}
var sysRoot = path.join(root, 'node_modules', name);
fsExists(path.join(sysRoot, 'package.json'), function(exists) {
cb(exists ? sysRoot : root);
});
};