zan-proxy
Version:
273 lines • 10.8 kB
JavaScript
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const es6_promisify_1 = require("es6-promisify");
const events_1 = __importDefault(require("events"));
const fs_1 = __importDefault(require("fs"));
const jsonfile_1 = __importDefault(require("jsonfile"));
const lodash_1 = require("lodash");
const node_fetch_1 = __importDefault(require("node-fetch"));
const path_1 = __importDefault(require("path"));
const typedi_1 = require("typedi");
const appInfo_1 = require("./appInfo");
const ipReg = /((?:(?:25[0-5]|2[0-4]\d|[01]?\d?\d)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d?\d))/;
const jsonWriteFile = es6_promisify_1.promisify(jsonfile_1.default.writeFile);
const fsUnlink = es6_promisify_1.promisify(fs_1.default.unlink);
const fsExists = (p) => new Promise(resolve => {
fs_1.default.exists(p, exists => {
resolve(exists);
});
});
/**
* Created by tsxuehu on 8/3/17.
*/
let HostService = class HostService extends events_1.default {
constructor(appInfoService) {
super();
// userId -> { filename -> content}
this.userHostFilesMap = {};
// 缓存
// userId, {globHostMap, hostMap}
this.inUsingHostsMapCache = {};
const proxyDataDir = appInfoService.getProxyDataDir();
this.hostSaveDir = path_1.default.join(proxyDataDir, 'host');
const contentMap = fs_1.default
.readdirSync(this.hostSaveDir)
.filter(name => name.endsWith('.json'))
.reduce((prev, curr) => {
try {
prev[curr] = jsonfile_1.default.readFileSync(path_1.default.join(this.hostSaveDir, curr));
}
catch (e) {
// ignore
}
return prev;
}, {});
lodash_1.forEach(contentMap, (content, fileName) => {
const hostName = content.name;
const userId = fileName.substr(0, this._getUserIdLength(fileName, hostName));
this.userHostFilesMap[userId] = this.userHostFilesMap[userId] || {};
this.userHostFilesMap[userId][hostName] = content;
});
}
resolveHost(userId, hostname) {
return __awaiter(this, void 0, void 0, function* () {
if (!hostname) {
return hostname;
}
if (ipReg.test(hostname)) {
return hostname;
}
let ip;
const inUsingHosts = this.getInUsingHosts(userId);
ip = inUsingHosts.hostMap[hostname];
if (ip) {
return ip;
}
// 配置 *开头的host 计算属性globHostMap已经将*去除
ip = lodash_1.find(inUsingHosts.globHostMap, (_, host) => {
return hostname.endsWith(host);
});
if (ip) {
return ip;
}
return hostname;
});
}
/**
* 获取用户的host文件列表
* @param userId
* @returns {Array}
*/
getHostFileList(userId) {
const fileList = [];
lodash_1.forEach(this.userHostFilesMap[userId], content => {
fileList.push({
checked: content.checked,
description: content.description,
meta: content.meta,
name: content.name,
});
});
return fileList;
}
/**
* 创建host文件
* @param userId
* @param name
* @param description
* @returns {boolean}
*/
createHostFile(userId, name, description) {
return __awaiter(this, void 0, void 0, function* () {
if (this.userHostFilesMap[userId] && this.userHostFilesMap[userId][name]) {
// 文件已经存在不让创建
return false;
}
const content = {
checked: false,
content: {},
description,
meta: {
local: true,
},
name,
};
this.userHostFilesMap[userId] = this.userHostFilesMap[userId] || {};
this.userHostFilesMap[userId][name] = content;
const hostfileName = this._getHostFilePath(userId, name);
yield jsonWriteFile(hostfileName, content, { encoding: 'utf-8' });
this.emit('data-change', userId, this.getHostFileList(userId));
this.emit('host-saved', userId, name, content);
return true;
});
}
deleteHostFile(userId, name) {
return __awaiter(this, void 0, void 0, function* () {
delete this.userHostFilesMap[userId][name];
delete this.inUsingHostsMapCache[userId];
/**
* 删除文件
*/
const filePath = this._getHostFilePath(userId, name);
const exists = yield fsExists(filePath);
if (exists) {
yield fsUnlink(filePath);
}
this.emit('data-change', userId, this.getHostFileList(userId));
this.emit('host-deleted', userId, name);
});
}
toggleUseHost(userId, filename) {
return __awaiter(this, void 0, void 0, function* () {
const toSaveFileName = [];
lodash_1.forEach(this.userHostFilesMap[userId], (content, name) => {
if (content.name === filename) {
content.checked = !content.checked;
toSaveFileName.push(name);
}
});
// 保存文件
for (const name of toSaveFileName) {
const hostfileName = this._getHostFilePath(userId, name);
const content = this.userHostFilesMap[userId][name];
yield jsonWriteFile(hostfileName, content, { encoding: 'utf-8' });
}
delete this.inUsingHostsMapCache[userId];
this.emit('data-change', userId, this.getHostFileList(userId));
});
}
getHostFile(userId, name) {
if (!this.userHostFilesMap[userId]) {
return {};
}
return this.userHostFilesMap[userId][name];
}
saveHostFile(userId, name, content) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.userHostFilesMap[userId]) {
this.userHostFilesMap[userId] = {};
}
this.userHostFilesMap[userId][name] = content;
// 如果正在使用,则删除
if (content.checked) {
delete this.inUsingHostsMapCache[userId];
}
const hostfileName = this._getHostFilePath(userId, name);
yield jsonWriteFile(hostfileName, content, { encoding: 'utf-8' });
this.emit('host-saved', userId, name, content);
this.emit('data-change', userId, this.getHostFileList(userId));
});
}
importRemoteHostFile(userId, url) {
return __awaiter(this, void 0, void 0, function* () {
const resp = yield node_fetch_1.default(url);
const f = yield resp.json();
f.meta = {
local: false,
url,
};
if (!f.content) {
f.content = {};
}
if (!f.name) {
f.name = url.split('/').slice(-1)[0] || url;
}
if (this.getHostFile(userId, f.name) &&
this.getHostFile(userId, f.name).checked) {
f.checked = true;
}
else {
f.checked = false;
}
return yield this.saveHostFile(userId, f.name, f);
});
}
_getHostFilePath(userId, hostName) {
const fileName = `${userId}_${hostName}.json`;
const filePath = path_1.default.join(this.hostSaveDir, fileName);
return filePath;
}
_getUserIdLength(ruleFileName, hostName) {
return ruleFileName.length - hostName.length - 6;
}
/**
* 获取用户生效的host
* @param userId
* @returns {*}
*/
getInUsingHosts(userId) {
let hosts = this.inUsingHostsMapCache[userId];
if (!hosts) {
// 读文件加载host
const hostMap = {};
const globHostMap = {};
const userHostFile = this.userHostFilesMap[userId] || {};
Object.keys(userHostFile).forEach(name => {
const file = this.userHostFilesMap[userId][name];
if (!file.checked) {
return;
}
lodash_1.forEach(file.content, (ip, host) => {
if (host.startsWith('*')) {
globHostMap[host.substr(1, host.length)] = ip;
}
else {
hostMap[host] = ip;
}
});
});
hosts = {
globHostMap,
hostMap,
};
this.inUsingHostsMapCache[userId] = hosts;
}
return hosts;
}
};
HostService = __decorate([
typedi_1.Service(),
__metadata("design:paramtypes", [appInfo_1.AppInfoService])
], HostService);
exports.HostService = HostService;
//# sourceMappingURL=host.js.map