/** * Shell数据库管理模块 * 更新:2016/06/28 */ 'use strict'; const fs = require('fs'), dns = require('dns'), path = require('path'), CONF = require('./config'), Datastore = require('nedb'), qqwry = require("geoips").info(); var logger; class Database { /** * 初始化数据库 * @param {electron} electron electron对象 * @return {[type]} [description] */ constructor(electron) { logger = new electron.Logger('Database'); this.cursor = new Datastore({ filename: CONF.dataPath, autoload: true }); // 监听事件 electron.ipcMain .on('shell-add', this.addShell.bind(this)) .on('shell-del', this.delShell.bind(this)) .on('shell-edit', this.editShell.bind(this)) .on('shell-move', this.moveShell.bind(this)) .on('shell-find', this.findShell.bind(this)) .on('shell-clear', this.clearShell.bind(this)) .on('shell-findOne', this.findOneShell.bind(this)) .on('shell-addDataConf', this.addDataConf.bind(this)) .on('shell-editDataConf', this.editDataConf.bind(this)) .on('shell-delDataConf', this.delDataConf.bind(this)) .on('shell-getDataConf', this.getDataConf.bind(this)) .on('shell-renameCategory', this.renameShellCategory.bind(this)) .on('shell-updateHttpConf', this.updateHttpConf.bind(this)); } /** * 查询shell数据 * @param {Object} event ipcMain对象 * @param {Object} opts 查询配置 * @return {[type]} [description] */ findShell(event, opts = {}) { logger.debug('findShell', opts); this.cursor .find(opts) .sort({ utime: -1 }) .exec((err, ret) => { event.returnValue = ret || []; }); } /** * 查询单一shell数据 * @param {Object} event ipcMain对象 * @param {String} opts shell id * @return {[type]} [description] */ findOneShell(event, opts) { logger.debug('findOneShell', opts); this.cursor.findOne({ _id: opts }, (err, ret) => { event.returnValue = err || ret; }); } /** * 根据URL解析出IP&&地理位置 * @param {String} url URL地址 * @return {Promise} ip, addr */ _url2ip(url) { return new Promise((res, rej) => { // 解析domain const urlArr = url.match(/(\w+):\/\/([\w\.\-]+)[:]?([\d]*)([\s\S]*)/i); // 无效url if (!urlArr || urlArr.length < 3) { return rej('Unable to resolve domain name from URL'); } // 获取IP const domain = urlArr[2]; dns.lookup(domain, (err, ip) => { if (err) { return rej(err.toString()); } // 获取地理位置 const _addr = qqwry.searchIP(ip); return res({ ip: ip, addr: `${_addr.Country} ${_addr.Area}` }); }) }) } /** * 添加shell数据 * @param {Object} event ipcMain对象 * @param {Object} opts 数据(url,category,pwd,type,encode,encoder */ addShell(event, opts) { logger.info('addShell', opts); this._url2ip(opts.base['url']) .then((ret) => { this.cursor.insert({ category: opts.base['category'] || 'default', url: opts.base['url'], pwd: opts.base['pwd'], note: opts.base['note'], type: opts.base['type'], ip: ret['ip'], addr: ret['addr'], encode: opts.base['encode'], encoder: opts.base['encoder'], httpConf: opts.http, otherConf: opts.other, ctime: +new Date, utime: +new Date }, (_err, _ret) => { event.returnValue = _err || _ret; }); }) .catch((_err) => { event.returnValue = _err; }) } /** * 编辑shell数据 * @param {Object} event ipcMain对象 * @param {Object} opts 数据(old,new * @return {[type]} [description] */ editShell(event, opts) { logger.warn('editShell', opts); const _new = opts.new; const _old = opts.old; this._url2ip(_new.base['url']) .then((ret) => { this.cursor.update({ _id: _old['_id'] }, { $set: { ip: ret['ip'], addr: ret['addr'], url: _new.base['url'], pwd: _new.base['pwd'], note: _new.base['note'], type: _new.base['type'], encode: _new.base['encode'], encoder: _new.base['encoder'], httpConf: _new.http, otherConf: _new.other, utime: +new Date } }, (_err, _ret) => { event.returnValue = _err || _ret; }) }) .catch((_err) => { event.returnValue = _err; }); } /** * 更新httpConf配置信息(包含body&&headers * @param {[type]} event [description] * @param {[type]} opt = {} [description] * @return {[type]} [description] */ updateHttpConf(event, opt = {}) { logger.warn('updateHttpConf', opt); this.cursor.update({ _id: opt._id }, { $set: { httpConf: opt.conf, utime: +new Date } }, (_err, _ret) => { event.returnValue = _err || _ret; }); } /** * 删除shell数据 * @param {Object} event ipcMain对象 * @param {Array} opts 要删除的shell-id列表 * @return {[type]} [description] */ delShell(event, opts) { logger.warn('delShell', opts); this.cursor.remove({ _id: { $in: opts } }, { multi: true }, (err, num) => { event.returnValue = err || num; }) } /** * 删除分类shell数据 * @param {Object} event ipcMain对象 * @param {String} opts shell分类名 * @return {[type]} [description] */ clearShell(event, opts) { logger.fatal('clearShell', opts); this.cursor.remove({ category: opts }, { multi: true }, (err, num) => { event.returnValue = err || num; }) } /** * 重命名shell分类 * @param {Object} event ipcMain对象 * @param {Object} opts 配置(oldName,newName * @return {[type]} [description] */ renameShellCategory(event, opts) { logger.warn('renameShellCategory', opts); this.cursor.update({ category: opts['oldName'] }, { $set: { category: opts['newName'] } }, { multi: true }, (err, num) => { event.returnValue = err || num; }) } /** * 移动shell数据分类 * @param {Object} event ipcMain对象 * @param {Object} opts 配置(ids,category * @return {[type]} [description] */ moveShell(event, opts) { logger.info('moveShell', opts); this.cursor.update({ _id: { $in: opts['ids'] || [] } }, { $set: { category: opts['category'] || 'default', utime: +new Date } }, { multi: true }, (err, num) => { event.returnValue = err || num; }) } /** * 添加数据库配置 * @param {Object} event ipcMain对象 * @param {Object} opts 配置(_id,data */ addDataConf(event, opts) { logger.info('addDataConf', opts); // 1. 获取原配置列表 this.cursor.findOne({ _id: opts['_id'] }, (err, ret) => { let confs = ret['database'] || {}; // 随机Id(顺序增长 const random_id = parseInt(+new Date + Math.random() * 1000).toString(16); // 添加到配置 confs[random_id] = opts['data']; // 更新数据库 this.cursor.update({ _id: opts['_id'] }, { $set: { database: confs, utime: +new Date } }, (_err, _ret) => { event.returnValue = random_id; }); }); } /** * 修改数据库配置 * @param {Object} event ipcMain对象 * @param {Object} opts 配置(_id,id,data */ editDataConf(event, opts) { logger.info('editDataConf', opts); // 1. 获取原配置列表 this.cursor.findOne({ _id: opts['_id'] }, (err, ret) => { let confs = ret['database'] || {}; // 添加到配置 confs[opts['id']] = opts['data']; // 更新数据库 this.cursor.update({ _id: opts['_id'] }, { $set: { database: confs, utime: +new Date } }, (_err, _ret) => { event.returnValue = opts['id']; }); }); } /** * 删除数据库配置 * @param {Object} event ipcMain对象 * @param {Object} opts 配置(_id,id * @return {[type]} [description] */ delDataConf(event, opts) { logger.info('delDataConf', opts); // 1. 获取原配置 this.cursor.findOne({ _id: opts['_id'] }, (err, ret) => { let confs = ret['database'] || {}; // 2. 删除配置 delete confs[opts['id']]; // 3. 更新数据库 this.cursor.update({ _id: opts['_id'] }, { $set: { database: confs, utime: +new Date } }, (_err, _ret) => { event.returnValue = _err || _ret; }); }) } /** * 获取单个数据库配置 * @param {Object} event ipcMain对象 * @param {Object} opts 配置(_id,id * @return {[type]} [description] */ getDataConf(event, opts) { logger.info('getDatConf', opts); this.cursor.findOne({ _id: opts['_id'] }, (err, ret) => { const confs = ret['database'] || {}; event.returnValue = err || confs[opts['id']]; }); } } module.exports = Database;