refactor: 插件化
							parent
							
								
									2be957968e
								
							
						
					
					
						commit
						3f81235e86
					
				|  | @ -32,6 +32,9 @@ const configApi = { | |||
|   getDefault () { | ||||
|     return lodash.cloneDeep(defConfig) | ||||
|   }, | ||||
|   addDefault (key, defValue) { | ||||
|     lodash.set(defConfig, key, defValue) | ||||
|   }, | ||||
|   resetDefault () { | ||||
|     configTarget = lodash.cloneDeep(defConfig) | ||||
|   }, | ||||
|  |  | |||
|  | @ -1,145 +1,118 @@ | |||
| module.exports = { | ||||
|   server: { | ||||
|     port: 1181 | ||||
|   }, | ||||
|   intercepts: { | ||||
|     'github.com': [ | ||||
|       { | ||||
|         // "release archive 下载链接替换",
 | ||||
|         regexp: [ | ||||
|           '/.*/.*/releases/download/', | ||||
|           '/.*/.*/archive/' | ||||
|         ], | ||||
|         redirect: 'download.fastgit.org' | ||||
|       }, | ||||
|       { | ||||
|         regexp: [ | ||||
|           '/.*/.*/raw/', | ||||
|           '/.*/.*/blame/' | ||||
|         ], | ||||
|         redirect: 'hub.fastgit.org' | ||||
|       } | ||||
|     ], | ||||
|     // 'codeload.github.com': [
 | ||||
|     //     {
 | ||||
|     //         regexp: '.*',
 | ||||
|     //         redirect:"download.fastgit.org"
 | ||||
|     //     }
 | ||||
|     // ],
 | ||||
|     'raw.githubusercontent.com': [{ proxy: 'raw.fastgit.org' }], | ||||
|     'github.githubassets.com': [ | ||||
|       { | ||||
|         proxy: 'assets.fastgit.org' | ||||
|       } | ||||
|     ], | ||||
|     'customer-stories-feed.github.com': [ | ||||
|       { | ||||
|         proxy: 'customer-stories-feed.fastgit.org' | ||||
|       } | ||||
|     ], | ||||
|     enabled: true, | ||||
|     port: 1181, | ||||
|     intercepts: { | ||||
|       'github.com': [ | ||||
|         { | ||||
|           // "release archive 下载链接替换",
 | ||||
|           regexp: [ | ||||
|             '/.*/.*/releases/download/', | ||||
|             '/.*/.*/archive/' | ||||
|           ], | ||||
|           redirect: 'download.fastgit.org' | ||||
|         }, | ||||
|         { | ||||
|           regexp: [ | ||||
|             '/.*/.*/raw/', | ||||
|             '/.*/.*/blame/' | ||||
|           ], | ||||
|           redirect: 'hub.fastgit.org' | ||||
|         } | ||||
|       ], | ||||
|       // 'codeload.github.com': [
 | ||||
|       //     {
 | ||||
|       //         regexp: '.*',
 | ||||
|       //         redirect:"download.fastgit.org"
 | ||||
|       //     }
 | ||||
|       // ],
 | ||||
|       'raw.githubusercontent.com': [{ proxy: 'raw.fastgit.org' }], | ||||
|       'github.githubassets.com': [ | ||||
|         { | ||||
|           proxy: 'assets.fastgit.org' | ||||
|         } | ||||
|       ], | ||||
|       'customer-stories-feed.github.com': [ | ||||
|         { | ||||
|           proxy: 'customer-stories-feed.fastgit.org' | ||||
|         } | ||||
|       ], | ||||
| 
 | ||||
|     // google cdn
 | ||||
|     'ajax.googleapis.com': [ | ||||
|       { | ||||
|         proxy: 'ajax.loli.net', | ||||
|         backup: ['ajax.proxy.ustclug.org'], | ||||
|         case: 'ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js' | ||||
|       } | ||||
|     ], | ||||
|     'fonts.googleapis.com': [ | ||||
|       { | ||||
|         proxy: 'fonts.loli.net', | ||||
|         backup: ['fonts.proxy.ustclug.org'], | ||||
|         case: 'https://fonts.googleapis.com/css?family=Oswald' | ||||
|       } | ||||
|     ], | ||||
|     'themes.googleapis.com': [ | ||||
|       { | ||||
|         proxy: 'themes.loli.net', | ||||
|         backup: ['themes.proxy.ustclug.org'] | ||||
|       } | ||||
|     ], | ||||
|     'themes.googleusercontent.com': [ | ||||
|       { proxy: 'google-themes.proxy.ustclug.org' } | ||||
|     ], | ||||
|     'www.google.com': [ | ||||
|       { | ||||
|         regexp: '/recaptcha/.*', | ||||
|         proxy: 'www.recaptcha.net' | ||||
|       } | ||||
|     ], | ||||
|     'fonts.gstatic.com': [ | ||||
|       { | ||||
|         proxy: 'fonts-gstatic.proxy.ustclug.org', | ||||
|         backup: ['gstatic.loli.net'] | ||||
|       } | ||||
|     ], | ||||
|     'clients*.google.com': [{ abort: true }], | ||||
|     'www.googleapis.com': [{ abort: true }], | ||||
|     'lh*.googleusercontent.com': [{ abort: true }], | ||||
|     // mapbox-node-binary.s3.amazonaws.com/sqlite3/v5.0.0/napi-v3-win32-x64.tar.gz
 | ||||
|     '*.s3.amazonaws.com': [ | ||||
|       { | ||||
|         regexp: '/sqlite3/.*', | ||||
|         redirect: 'npm.taobao.org/mirrors' | ||||
|       } | ||||
|     ], | ||||
|     'registry-1.docker.io': [{ proxy: 'docker.mirrors.ustc.edu.cn' }], | ||||
|     'packages.elastic.co': [{ proxy: 'elastic.proxy.ustclug.org' }], | ||||
|     'ppa.launchpad.net': [{ proxy: 'launchpad.proxy.ustclug.org' }], | ||||
|     'archive.cloudera.com': [{ regexp: '/cdh5/.*', proxy: 'cloudera.proxy.ustclug.org' }], | ||||
|     'downloads.lede-project.org': [{ proxy: 'lede.proxy.ustclug.org' }], | ||||
|     'downloads.openwrt.org': [{ proxy: 'openwrt.proxy.ustclug.org' }], | ||||
|     'secure.gravatar.com': [{ proxy: 'gravatar.proxy.ustclug.org' }] | ||||
|   }, | ||||
|   dns: { | ||||
|     providers: { | ||||
|       aliyun: { | ||||
|         type: 'https', | ||||
|         server: 'dns.alidns.com/dns-query', | ||||
|         cacheSize: 1000 | ||||
|       }, | ||||
|       usa: { | ||||
|         type: 'https', | ||||
|         server: 'cloudflare-dns.com/dns-query', | ||||
|         cacheSize: 1000 | ||||
|       } | ||||
|       // google cdn
 | ||||
|       'ajax.googleapis.com': [ | ||||
|         { | ||||
|           proxy: 'ajax.loli.net', | ||||
|           backup: ['ajax.proxy.ustclug.org'], | ||||
|           case: 'ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js' | ||||
|         } | ||||
|       ], | ||||
|       'fonts.googleapis.com': [ | ||||
|         { | ||||
|           proxy: 'fonts.loli.net', | ||||
|           backup: ['fonts.proxy.ustclug.org'], | ||||
|           case: 'https://fonts.googleapis.com/css?family=Oswald' | ||||
|         } | ||||
|       ], | ||||
|       'themes.googleapis.com': [ | ||||
|         { | ||||
|           proxy: 'themes.loli.net', | ||||
|           backup: ['themes.proxy.ustclug.org'] | ||||
|         } | ||||
|       ], | ||||
|       'themes.googleusercontent.com': [ | ||||
|         { proxy: 'google-themes.proxy.ustclug.org' } | ||||
|       ], | ||||
|       'www.google.com': [ | ||||
|         { | ||||
|           regexp: '/recaptcha/.*', | ||||
|           proxy: 'www.recaptcha.net' | ||||
|         } | ||||
|       ], | ||||
|       'fonts.gstatic.com': [ | ||||
|         { | ||||
|           proxy: 'fonts-gstatic.proxy.ustclug.org', | ||||
|           backup: ['gstatic.loli.net'] | ||||
|         } | ||||
|       ], | ||||
|       'clients*.google.com': [{ abort: true }], | ||||
|       'www.googleapis.com': [{ abort: true }], | ||||
|       'lh*.googleusercontent.com': [{ abort: true }], | ||||
|       // mapbox-node-binary.s3.amazonaws.com/sqlite3/v5.0.0/napi-v3-win32-x64.tar.gz
 | ||||
|       '*.s3.amazonaws.com': [ | ||||
|         { | ||||
|           regexp: '/sqlite3/.*', | ||||
|           redirect: 'npm.taobao.org/mirrors' | ||||
|         } | ||||
|       ], | ||||
|       'registry-1.docker.io': [{ proxy: 'docker.mirrors.ustc.edu.cn' }], | ||||
|       'packages.elastic.co': [{ proxy: 'elastic.proxy.ustclug.org' }], | ||||
|       'ppa.launchpad.net': [{ proxy: 'launchpad.proxy.ustclug.org' }], | ||||
|       'archive.cloudera.com': [{ regexp: '/cdh5/.*', proxy: 'cloudera.proxy.ustclug.org' }], | ||||
|       'downloads.lede-project.org': [{ proxy: 'lede.proxy.ustclug.org' }], | ||||
|       'downloads.openwrt.org': [{ proxy: 'openwrt.proxy.ustclug.org' }], | ||||
|       'secure.gravatar.com': [{ proxy: 'gravatar.proxy.ustclug.org' }] | ||||
|     }, | ||||
|     mapping: { | ||||
|       // "解决push的时候需要输入密码的问题",
 | ||||
|       'api.github.com': 'usa', | ||||
|       'gist.github.com': 'usa' | ||||
|       // "avatars*.githubusercontent.com": "usa"
 | ||||
|     } | ||||
|   }, | ||||
|   variables: { | ||||
|     npm: { | ||||
|       SASS_BINARY_SITE: 'https://npm.taobao.org/mirrors/node-sass/', | ||||
|       PHANTOMJS_CDNURL: 'https://npm.taobao.org/mirrors/phantomjs/', | ||||
|       ELECTRON_MIRROR: 'https://npm.taobao.org/mirrors/electron/', | ||||
|       CYPRESS_DOWNLOAD_MIRROR: 'https://cdn.cypress.io', | ||||
|       NVM_NODEJS_ORG_MIRROR: 'https://npm.taobao.org/mirrors/node', | ||||
|       CHROMEDRIVER_CDNURL: 'https://npm.taobao.org/mirrors/chromedriver', | ||||
|       OPERADRIVER: 'https://npm.taobao.org/mirrors/operadriver', | ||||
|       ELECTRON_BUILDER_BINARIES_MIRROR: 'https://npm.taobao.org/mirrors/electron-builder-binaries/', | ||||
|       PYTHON_MIRROR: 'https://npm.taobao.org/mirrors/python' | ||||
|     }, | ||||
|     system: { | ||||
|       // eslint-disable-next-line no-template-curly-in-string
 | ||||
|       NODE_EXTRA_CA_CERTS: '${ca_cert_path}' | ||||
|     } | ||||
|   }, | ||||
|   setting: { | ||||
|     startup: { // 开机启动
 | ||||
|       server: true, | ||||
|       proxy: { | ||||
|         system: true, | ||||
|         npm: true, | ||||
|         yarn: true | ||||
|     dns: { | ||||
|       providers: { | ||||
|         aliyun: { | ||||
|           type: 'https', | ||||
|           server: 'dns.alidns.com/dns-query', | ||||
|           cacheSize: 1000 | ||||
|         }, | ||||
|         usa: { | ||||
|           type: 'https', | ||||
|           server: 'cloudflare-dns.com/dns-query', | ||||
|           cacheSize: 1000 | ||||
|         } | ||||
|       }, | ||||
|       variables: { | ||||
|         npm: true | ||||
|       mapping: { | ||||
|         // "解决push的时候需要输入密码的问题",
 | ||||
|         'api.github.com': 'usa', | ||||
|         'gist.github.com': 'usa' | ||||
|         // "avatars*.githubusercontent.com": "usa"
 | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   }, | ||||
|   proxy: {}, | ||||
|   plugin: {} | ||||
| } | ||||
|  |  | |||
|  | @ -1,60 +1,134 @@ | |||
| const server = require('./server/index.js') | ||||
| const proxy = require('./switch/proxy/index.js') | ||||
| const status = require('./status') | ||||
| const config = require('./config') | ||||
| const event = require('./event') | ||||
| const shell = require('./shell') | ||||
| async function proxyStartup ({ ip, port }) { | ||||
|   for (const key in proxy) { | ||||
|     if (config.get().setting.startup.proxy[key]) { | ||||
|       await proxy[key].open({ ip, port }) | ||||
|     } | ||||
|   } | ||||
| const modules = require('./modules') | ||||
| const proxyConfig = require('./lib/proxy/common/config') | ||||
| const lodash = require('lodash') | ||||
| const context = { | ||||
|   config, | ||||
|   shell, | ||||
|   status, | ||||
|   event, | ||||
|   rootCaFile: proxyConfig.getDefaultCACertPath() | ||||
| } | ||||
| async function proxyShutdown () { | ||||
|   for (const key in proxy) { | ||||
|     if (status.proxy[key] === false) { | ||||
|       continue | ||||
|     } | ||||
|     await proxy[key].close() | ||||
|   } | ||||
| 
 | ||||
| function setupPlugin (key, plugin, context, config) { | ||||
|   const pluginConfig = plugin.config | ||||
|   const PluginClass = plugin.plugin | ||||
|   const pluginStatus = plugin.status | ||||
|   const api = PluginClass(context) | ||||
|   config.addDefault(key, pluginConfig) | ||||
|   lodash.set(status, key, pluginStatus) | ||||
|   return api | ||||
| } | ||||
| 
 | ||||
| function fireStatus (target) { | ||||
|   event.fire('status', target) | ||||
| } | ||||
| 
 | ||||
| const server = modules.server | ||||
| const proxy = setupPlugin('proxy', modules.proxy, context, config) | ||||
| const plugin = {} | ||||
| for (const key in modules.plugin) { | ||||
|   const target = modules.plugin[key] | ||||
|   const api = setupPlugin('plugin.' + key, target, context, config) | ||||
|   plugin[key] = api | ||||
| } | ||||
| config.resetDefault() | ||||
| 
 | ||||
| module.exports = { | ||||
|   status, | ||||
|   api: { | ||||
|     server, | ||||
|     proxy, | ||||
|     config, | ||||
|     startup: async (newConfig) => { | ||||
|       if (newConfig) { | ||||
|         config.set(newConfig) | ||||
|       } | ||||
|       try { | ||||
|         const startup = config.get().setting.startup | ||||
|         if (startup.server) { | ||||
|           server.start(newConfig) | ||||
|       const conf = config.get() | ||||
|       if (conf.server.enabled) { | ||||
|         try { | ||||
|           const cfg = await server.start() | ||||
|           fireStatus({ key: 'server.enabled', value: true }) | ||||
|           console.log('代理服务已启动:127.0.0.1:' + cfg.port) | ||||
|         } catch (err) { | ||||
|           fireStatus({ key: 'server.enabled', value: false }) | ||||
|           console.error('代理服务启动失败:', err) | ||||
|         } | ||||
|         await proxyStartup({ ip: '127.0.0.1', port: config.get().server.port }) | ||||
| 
 | ||||
|         if (startup.variables.npm) { | ||||
|           await config.setVariables('npm') | ||||
|         } | ||||
|       } catch (error) { | ||||
|         console.log(error) | ||||
|       } | ||||
|       if (conf.proxy.enabled) { | ||||
|         try { | ||||
|           const ret = await proxy.start() | ||||
|           fireStatus({ key: 'proxy.enabled', value: true }) | ||||
|           console.log(`开启系统代理成功:${ret.ip}:${ret.port}`) | ||||
|         } catch (err) { | ||||
|           fireStatus({ key: 'proxy.enabled', value: false }) | ||||
|           console.error('开启系统代理失败:', err) | ||||
|         } | ||||
|       } | ||||
|       const plugins = [] | ||||
|       for (const key in plugin) { | ||||
|         if (conf.plugin[key].enabled) { | ||||
|           const start = async () => { | ||||
|             try { | ||||
|               await plugin[key].start() | ||||
|               console.log(`插件【${key}】已启动`) | ||||
|             } catch (err) { | ||||
|               console.log(`插件【${key}】启动失败`, err) | ||||
|             } | ||||
|           } | ||||
|           plugins.push(start()) | ||||
|         } | ||||
|       } | ||||
|       await Promise.all(plugins) | ||||
|     }, | ||||
|     shutdown: async () => { | ||||
|       try { | ||||
|         await proxyShutdown() | ||||
|         return new Promise(resolve => { | ||||
|           server.close() | ||||
|           resolve() | ||||
|         }) | ||||
|         const plugins = [] | ||||
|         for (const key in plugin) { | ||||
|           if (status.plugin[key].enabled && plugin[key].close) { | ||||
|             const close = async () => { | ||||
|               try { | ||||
|                 await plugin[key].close() | ||||
|                 console.log(`插件【${key}】已关闭`) | ||||
|               } catch (err) { | ||||
|                 console.log(`插件【${key}】关闭失败`, err) | ||||
|               } | ||||
|             } | ||||
|             plugins.push(close()) | ||||
|           } | ||||
|         } | ||||
|         await Promise.all(plugins) | ||||
| 
 | ||||
|         if (status.proxy.enabled) { | ||||
|           try { | ||||
|             await proxy.close() | ||||
|             console.log('系统代理已关闭') | ||||
|           } catch (err) { | ||||
|             console.log('系统代理关闭失败', err) | ||||
|           } | ||||
|         } | ||||
|         if (status.server.enabled) { | ||||
|           try { | ||||
|             await server.close() | ||||
|             console.log('代理服务已关闭') | ||||
|           } catch (err) { | ||||
|             console.log('代理服务关闭失败', err) | ||||
|           } | ||||
|         } | ||||
|       } catch (error) { | ||||
|         console.log(error) | ||||
|       } | ||||
|     }, | ||||
|     status: { | ||||
|       get () { | ||||
|         return status | ||||
|       } | ||||
|     }, | ||||
|     config, | ||||
|     event, | ||||
|     shell | ||||
|     shell, | ||||
|     server, | ||||
|     proxy, | ||||
|     plugin | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -62,7 +62,7 @@ module.exports = function createRequestHandler (requestInterceptor, responseInte | |||
|         function onFree () { | ||||
|           const url = `${rOptions.protocol}//${rOptions.hostname}:${rOptions.port}${rOptions.path}` | ||||
|           const start = new Date().getTime() | ||||
|           console.log('代理请求:', url) | ||||
|           console.log('代理请求:', url, rOptions.method) | ||||
| 
 | ||||
|           proxyReq = (rOptions.protocol === 'https:' ? https : http).request(rOptions, (proxyRes) => { | ||||
|             const end = new Date().getTime() | ||||
|  | @ -73,7 +73,7 @@ module.exports = function createRequestHandler (requestInterceptor, responseInte | |||
|           }) | ||||
| 
 | ||||
|           proxyReq.on('timeout', () => { | ||||
|             console.error('代理请求超时', rOptions.hostname, rOptions.path) | ||||
|             console.error('代理请求超时', rOptions.protocol, rOptions.hostname, rOptions.path) | ||||
|             reject(new Error(`${rOptions.host}:${rOptions.port}, 代理请求超时`)) | ||||
|           }) | ||||
| 
 | ||||
|  |  | |||
|  | @ -0,0 +1,19 @@ | |||
| class AbstractPlugin { | ||||
|   constructor (context) { | ||||
|     this._context = context | ||||
|   } | ||||
| 
 | ||||
|   _getConfig () { | ||||
|     return this._context.config.get() | ||||
|   } | ||||
| 
 | ||||
|   _getShell () { | ||||
|     return this._context.shell | ||||
|   } | ||||
| 
 | ||||
|   _fireStatus (event) { | ||||
|     this._context.event.fire('status', event) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| module.exports = AbstractPlugin | ||||
|  | @ -0,0 +1,11 @@ | |||
| const server = require('./server') | ||||
| 
 | ||||
| const proxy = require('./proxy') | ||||
| 
 | ||||
| const plugin = require('./plugin') | ||||
| 
 | ||||
| module.exports = { | ||||
|   server, | ||||
|   proxy, | ||||
|   plugin | ||||
| } | ||||
|  | @ -0,0 +1,4 @@ | |||
| const node = require('./node') | ||||
| module.exports = { | ||||
|   node | ||||
| } | ||||
|  | @ -0,0 +1,29 @@ | |||
| module.exports = { | ||||
|   name: 'NPM加速', | ||||
|   enabled: true, | ||||
|   startup: { | ||||
|     npm: true, | ||||
|     yarn: true, | ||||
|     variables: true | ||||
|   }, | ||||
|   setting: { | ||||
|     'strict-ssl': false, | ||||
|     cafile: true, | ||||
|     NODE_EXTRA_CA_CERTS: true, | ||||
|     NODE_TLS_REJECT_UNAUTHORIZED: false | ||||
|   }, | ||||
|   intercepts: { | ||||
|     'cdn.cypress.io': [{ regexp: '/desktop/.*', proxy: 'http://npm.taobao.org/mirrors/cypress/' }] | ||||
|   }, | ||||
|   variables: { | ||||
|     SASS_BINARY_SITE: 'https://npm.taobao.org/mirrors/node-sass/', | ||||
|     PHANTOMJS_CDNURL: 'https://npm.taobao.org/mirrors/phantomjs/', | ||||
|     ELECTRON_MIRROR: 'https://npm.taobao.org/mirrors/electron/', | ||||
|     // CYPRESS_DOWNLOAD_MIRROR: 'https://cdn.cypress.io',
 | ||||
|     NVM_NODEJS_ORG_MIRROR: 'https://npm.taobao.org/mirrors/node', | ||||
|     CHROMEDRIVER_CDNURL: 'https://npm.taobao.org/mirrors/chromedriver', | ||||
|     OPERADRIVER: 'https://npm.taobao.org/mirrors/operadriver', | ||||
|     ELECTRON_BUILDER_BINARIES_MIRROR: 'https://npm.taobao.org/mirrors/electron-builder-binaries/', | ||||
|     PYTHON_MIRROR: 'https://npm.taobao.org/mirrors/python' | ||||
|   } | ||||
| } | ||||
|  | @ -0,0 +1,145 @@ | |||
| const nodeConfig = require('./config') | ||||
| const NodePlugin = function (context) { | ||||
|   const { config, shell, event, rootCaFile } = context | ||||
|   const api = { | ||||
|     async start () { | ||||
|       try { | ||||
|         await api.setVariables() | ||||
|       } catch (err) { | ||||
|         console.warn('set variables error', err) | ||||
|       } | ||||
| 
 | ||||
|       const ip = '127.0.0.1' | ||||
|       const port = config.get().server.port | ||||
|       await api.setProxy(ip, port) | ||||
|       return { ip, port } | ||||
|     }, | ||||
| 
 | ||||
|     async close () { | ||||
|       return api.unsetProxy() | ||||
|     }, | ||||
| 
 | ||||
|     async restart () { | ||||
|       await api.close() | ||||
|       await api.start() | ||||
|     }, | ||||
| 
 | ||||
|     async save (newConfig) { | ||||
|       api.setVariables() | ||||
|     }, | ||||
|     async getNpmEnv () { | ||||
|       const ret = await shell.exec(['npm config list --json'], { type: 'cmd' }) | ||||
|       if (ret != null) { | ||||
|         const json = ret.substring(ret.indexOf('{')) | ||||
|         return JSON.parse(json) | ||||
|       } | ||||
|       return {} | ||||
|     }, | ||||
| 
 | ||||
|     async setNpmEnv (list) { | ||||
|       const cmds = [] | ||||
|       for (const item of list) { | ||||
|         cmds.push(`npm config set ${item.key}  ${item.value}`) | ||||
|       } | ||||
|       const ret = await shell.exec(cmds, { type: 'cmd' }) | ||||
|       return ret | ||||
|     }, | ||||
| 
 | ||||
|     async unsetNpmEnv (list) { | ||||
|       const cmds = [] | ||||
|       for (const item of list) { | ||||
|         cmds.push(`npm config delete ${item} `) | ||||
|       } | ||||
|       const ret = await shell.exec(cmds, { type: 'cmd' }) | ||||
|       return ret | ||||
|     }, | ||||
| 
 | ||||
|     async getVariables () { | ||||
|       const currentMap = await api.getNpmEnv() | ||||
|       const list = [] | ||||
|       const map = config.get().plugin.node.variables | ||||
|       for (const key in map) { | ||||
|         const exists = currentMap[key] != null | ||||
|         list.push({ | ||||
|           key, | ||||
|           value: map[key], | ||||
|           exists | ||||
|         }) | ||||
|       } | ||||
|       return list | ||||
|     }, | ||||
| 
 | ||||
|     async setVariables () { | ||||
|       const list = await api.getVariables() | ||||
|       const noSetList = list.filter(item => { | ||||
|         return !item.exists | ||||
|       }) | ||||
|       if (noSetList.length > 0) { | ||||
|         return api.setNpmEnv(noSetList) | ||||
|       } | ||||
|     }, | ||||
| 
 | ||||
|     async setProxy (ip, port) { | ||||
|       const cmds = [ | ||||
|         `npm config set proxy=http://${ip}:${port}`, | ||||
|         `npm config set https-proxy=http://${ip}:${port}` | ||||
|       ] | ||||
| 
 | ||||
|       const env = [] | ||||
| 
 | ||||
|       /** | ||||
|        *  'strict-ssl': false, | ||||
|        cafile: true, | ||||
|        NODE_EXTRA_CA_CERTS: true, | ||||
|        NODE_TLS_REJECT_UNAUTHORIZED: false | ||||
|        */ | ||||
|       const nodeConfig = config.get().plugin.node | ||||
|       if (nodeConfig.setting['strict-ssl']) { | ||||
|         cmds.push('npm nodeConfig set strict-ssl false') | ||||
|       } | ||||
|       if (nodeConfig.setting.cafile) { | ||||
|         cmds.push(`npm config set cafile "${rootCaFile}"`) | ||||
|       } | ||||
| 
 | ||||
|       if (nodeConfig.setting.NODE_EXTRA_CA_CERTS) { | ||||
|         cmds.push(`npm config set NODE_EXTRA_CA_CERTS "${rootCaFile}"`) | ||||
|         env.push({ key: 'NODE_EXTRA_CA_CERTS', value: rootCaFile }) | ||||
|       } | ||||
| 
 | ||||
|       if (nodeConfig.setting.NODE_TLS_REJECT_UNAUTHORIZED) { | ||||
|         cmds.push('npm nodeConfig set NODE_TLS_REJECT_UNAUTHORIZED 0') | ||||
|         env.push({ key: 'NODE_TLS_REJECT_UNAUTHORIZED', value: '0' }) | ||||
|       } | ||||
| 
 | ||||
|       const ret = await shell.exec(cmds, { type: 'cmd' }) | ||||
|       if (env.length > 0) { | ||||
|         await shell.setSystemEnv({ list: env }) | ||||
|       } | ||||
|       event.fire('status', { key: 'plugin.node.enabled', value: true }) | ||||
|       console.info('开启【NPM】代理成功') | ||||
|       return ret | ||||
|     }, | ||||
| 
 | ||||
|     async unsetProxy () { | ||||
|       const cmds = [ | ||||
|         'npm config  delete proxy', | ||||
|         'npm config  delete https-proxy', | ||||
|         'npm config  delete NODE_EXTRA_CA_CERTS', | ||||
|         'npm config  delete strict-ssl' | ||||
|       ] | ||||
|       const ret = await shell.exec(cmds, { type: 'cmd' }) | ||||
|       event.fire('status', { key: 'plugin.node.enabled', value: false }) | ||||
|       return ret | ||||
|     } | ||||
|   } | ||||
|   return api | ||||
| } | ||||
| 
 | ||||
| module.exports = { | ||||
|   key: 'node', | ||||
|   config: nodeConfig, | ||||
|   status: { | ||||
|     enabled: false | ||||
|   }, | ||||
|   plugin: NodePlugin | ||||
| } | ||||
|  | @ -0,0 +1,53 @@ | |||
| const systemProxy = require('./system-proxy') | ||||
| const ProxyPlugin = function (context) { | ||||
|   const { config, event } = context | ||||
|   const api = { | ||||
|     async start () { | ||||
|       return api.setProxy() | ||||
|     }, | ||||
| 
 | ||||
|     async close () { | ||||
|       return api.unsetProxy() | ||||
|     }, | ||||
| 
 | ||||
|     async setProxy () { | ||||
|       const ip = '127.0.0.1' | ||||
|       const port = config.get().server.port | ||||
|       await systemProxy.setProxy(ip, port) | ||||
|       event.fire('status', { key: 'proxy.enabled', value: true }) | ||||
|       return { ip, port } | ||||
|     }, | ||||
| 
 | ||||
|     async unsetProxy () { | ||||
|       try { | ||||
|         systemProxy.unsetProxy() | ||||
|         event.fire('status', { key: 'proxy.enabled', vlaue: false }) | ||||
|         console.log('关闭系统代理成功') | ||||
|         return true | ||||
|       } catch (err) { | ||||
|         console.error('关闭系统代理失败', err) | ||||
|         return false | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   return api | ||||
| } | ||||
| module.exports = { | ||||
|   key: 'proxy', | ||||
|   config: { | ||||
|     enabled: true, | ||||
|     name: '系统代理', | ||||
|     use: 'local', | ||||
|     other: { | ||||
|       host: undefined, | ||||
|       port: undefined, | ||||
|       username: undefined, | ||||
|       password: undefined | ||||
|     } | ||||
|   }, | ||||
|   status: { | ||||
|     enabled: false, | ||||
|     proxyTarget: '' | ||||
|   }, | ||||
|   plugin: ProxyPlugin | ||||
| } | ||||
|  | @ -0,0 +1,14 @@ | |||
| const script = ` | ||||
| $signature = @' | ||||
| [DllImport("wininet.dll", SetLastError = true, CharSet=CharSet.Auto)] | ||||
| public static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int dwBufferLength); | ||||
| '@ | ||||
| 
 | ||||
| $INTERNET_OPTION_SETTINGS_CHANGED   = 39 | ||||
| $INTERNET_OPTION_REFRESH            = 37 | ||||
| $type = Add-Type -MemberDefinition $signature -Name wininet -Namespace pinvoke -PassThru | ||||
| $a = $type::InternetSetOption(0, $INTERNET_OPTION_SETTINGS_CHANGED, 0, 0) | ||||
| $b = $type::InternetSetOption(0, $INTERNET_OPTION_REFRESH, 0, 0) | ||||
| $a -and $b | ||||
| ` | ||||
| module.exports = script | ||||
|  | @ -0,0 +1,74 @@ | |||
| <# | ||||
| .Synopsis | ||||
| This function will set the proxy settings provided as input to the cmdlet. | ||||
| .Description | ||||
| This function will set the proxy server and (optinal) Automatic configuration script. | ||||
| .Parameter ProxyServer | ||||
| This parameter is set as the proxy for the system. | ||||
| Data from. This parameter is Mandatory | ||||
| .Example | ||||
| Setting proxy information | ||||
| Set-InternetProxy -proxy "proxy:7890" | ||||
| .Example | ||||
| Setting proxy information and (optinal) Automatic Configuration Script  | ||||
| Set-InternetProxy -proxy "proxy:7890" -acs "http://proxy:7892" | ||||
| #> | ||||
| 
 | ||||
| 
 | ||||
| Function Set-InternetProxy | ||||
| { | ||||
|     [CmdletBinding()] | ||||
|     Param( | ||||
|          | ||||
|         [Parameter(Mandatory=$True,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)] | ||||
|         [String[]]$Proxy, | ||||
| 
 | ||||
|         [Parameter(Mandatory=$False,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)] | ||||
|         [AllowEmptyString()] | ||||
|         [String[]]$acs | ||||
|                  | ||||
|     ) | ||||
| 
 | ||||
|     Begin | ||||
|     { | ||||
| 
 | ||||
|             $regKey="HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings" | ||||
|          | ||||
|     } | ||||
|      | ||||
|     Process | ||||
|     { | ||||
|          | ||||
|         Set-ItemProperty -path $regKey ProxyEnable -value 1 | ||||
| 
 | ||||
|         Set-ItemProperty -path $regKey ProxyServer -value $proxy | ||||
|                              | ||||
|         if($acs)  | ||||
|         {             | ||||
|              | ||||
|                  Set-ItemProperty -path $regKey AutoConfigURL -Value $acs           | ||||
|         } | ||||
| 
 | ||||
|     }  | ||||
|      | ||||
|     End | ||||
|     { | ||||
| 
 | ||||
|         Write-Output "Proxy is now enabled" | ||||
| 
 | ||||
|         Write-Output "Proxy Server : $proxy" | ||||
| 
 | ||||
|         if ($acs) | ||||
|         { | ||||
|              | ||||
|             Write-Output "Automatic Configuration Script : $acs" | ||||
| 
 | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|              | ||||
|             Write-Output "Automatic Configuration Script : Not Defined" | ||||
| 
 | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,14 @@ | |||
| $signature = @' | ||||
| [DllImport("wininet.dll", SetLastError = true, CharSet=CharSet.Auto)] | ||||
| public static extern bool InternetSetOption(IntPtr hInternet, int | ||||
| dwOption, IntPtr lpBuffer, int dwBufferLength); | ||||
| '@ | ||||
| 
 | ||||
| $interopHelper = Add-Type -MemberDefinition $signature -Name MyInteropHelper -PassThru | ||||
| $INTERNET_OPTION_SETTINGS_CHANGED = 39 | ||||
| $INTERNET_OPTION_REFRESH = 37 | ||||
| 
 | ||||
| $result1 = $interopHelper::InternetSetOption(0, $INTERNET_OPTION_SETTINGS_CHANGED, 0, 0) | ||||
| $result2 = $interopHelper::InternetSetOption(0, $INTERNET_OPTION_REFRESH, 0, 0) | ||||
| 
 | ||||
| $result1 -and $result2 | ||||
|  | @ -0,0 +1,61 @@ | |||
| const script = ` | ||||
| Function Set-InternetProxy | ||||
| { | ||||
|     [CmdletBinding()] | ||||
|     Param( | ||||
|          | ||||
|         [Parameter(Mandatory=$True,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)] | ||||
|         [String[]]$Proxy, | ||||
| 
 | ||||
|         [Parameter(Mandatory=$False,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)] | ||||
|         [AllowEmptyString()] | ||||
|         [String[]]$acs | ||||
|                  | ||||
|     ) | ||||
| 
 | ||||
|     Begin | ||||
|     { | ||||
| 
 | ||||
|             $regKey="HKCU:\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings" | ||||
|          | ||||
|     } | ||||
|      | ||||
|     Process | ||||
|     { | ||||
|          | ||||
|         Set-ItemProperty -path $regKey ProxyEnable -value 1 | ||||
| 
 | ||||
|         Set-ItemProperty -path $regKey ProxyServer -value $proxy | ||||
|                              | ||||
|         if($acs)  | ||||
|         {             | ||||
|              | ||||
|                  Set-ItemProperty -path $regKey AutoConfigURL -Value $acs           | ||||
|         } | ||||
| 
 | ||||
|     }  | ||||
|      | ||||
|     End | ||||
|     { | ||||
| 
 | ||||
|         Write-Output "Proxy is now enabled" | ||||
| 
 | ||||
|         Write-Output "Proxy Server : $proxy" | ||||
| 
 | ||||
|         if ($acs) | ||||
|         { | ||||
|              | ||||
|             Write-Output "Automatic Configuration Script : $acs" | ||||
| 
 | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|              | ||||
|             Write-Output "Automatic Configuration Script : Not Defined" | ||||
| 
 | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| ` | ||||
| module.exports = script | ||||
|  | @ -0,0 +1,191 @@ | |||
| const util = require('util') | ||||
| const os = require('os') | ||||
| const childProcess = require('child_process') | ||||
| const _exec = childProcess.exec | ||||
| const Registry = require('winreg') | ||||
| // const cmd = require('node-cmd')
 | ||||
| const exec = util.promisify(_exec) | ||||
| const refreshInternetPs = require('./refresh-internet') | ||||
| const PowerShell = require('node-powershell') | ||||
| const _lanIP = [ | ||||
|   'localhost', | ||||
|   '127.*', | ||||
|   '10.*', | ||||
|   '172.16.*', | ||||
|   '172.17.*', | ||||
|   '172.18.*', | ||||
|   '172.19.*', | ||||
|   '172.20.*', | ||||
|   '172.21.*', | ||||
|   '172.22.*', | ||||
|   '172.23.*', | ||||
|   '172.24.*', | ||||
|   '172.25.*', | ||||
|   '172.26.*', | ||||
|   '172.27.*', | ||||
|   '172.28.*', | ||||
|   '172.29.*', | ||||
|   '172.30.*', | ||||
|   '172.31.*', | ||||
|   '192.168.*', | ||||
|   '<local>' | ||||
| ] | ||||
| 
 | ||||
| class SystemProxy { | ||||
|   static async setProxy (ip, port) { | ||||
|     throw new Error('You have to implement the method setProxy!') | ||||
|   } | ||||
| 
 | ||||
|   static async unsetProxy () { | ||||
|     throw new Error('You have to implement the method unsetProxy!') | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| // TODO: Add path http_proxy and https_proxy
 | ||||
| // TODO: Support for non-gnome
 | ||||
| class LinuxSystemProxy extends SystemProxy { | ||||
|   static async setProxy (ip, port) { | ||||
|     await exec('gsettings set org.gnome.system.proxy mode manual') | ||||
|     await exec(`gsettings set org.gnome.system.proxy.http host ${ip}`) | ||||
|     await exec(`gsettings set org.gnome.system.proxy.http port ${port}`) | ||||
|   } | ||||
| 
 | ||||
|   static async unsetProxy () { | ||||
|     await exec('gsettings set org.gnome.system.proxy mode none') | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| // TODO: Support for lan connections too
 | ||||
| // TODO: move scripts to ../scripts/darwin
 | ||||
| class DarwinSystemProxy extends SystemProxy { | ||||
|   static async setProxy (ip, port) { | ||||
|     const wifiAdaptor = (await exec('sh -c "networksetup -listnetworkserviceorder | grep `route -n get 0.0.0.0 | grep \'interface\' | cut -d \':\' -f2` -B 1 | head -n 1 | cut -d \' \' -f2"')).stdout.trim() | ||||
| 
 | ||||
|     await exec(`networksetup -setwebproxy '${wifiAdaptor}' ${ip} ${port}`) | ||||
|     await exec(`networksetup -setsecurewebproxy '${wifiAdaptor}' ${ip} ${port}`) | ||||
|   } | ||||
| 
 | ||||
|   static async unsetProxy () { | ||||
|     const wifiAdaptor = (await exec('sh -c "networksetup -listnetworkserviceorder | grep `route -n get 0.0.0.0 | grep \'interface\' | cut -d \':\' -f2` -B 1 | head -n 1 | cut -d \' \' -f2"')).stdout.trim() | ||||
| 
 | ||||
|     await exec(`networksetup -setwebproxystate '${wifiAdaptor}' off`) | ||||
|     await exec(`networksetup -setsecurewebproxystate '${wifiAdaptor}' off`) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class WindowsSystemProxy extends SystemProxy { | ||||
|   static async setProxy (ip, port) { | ||||
|     const regKey = new Registry({ | ||||
|       hive: Registry.HKCU, | ||||
|       key: '\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings' | ||||
|     }) | ||||
| 
 | ||||
|     let lanIpStr = '' | ||||
|     for (const string of _lanIP) { | ||||
|       lanIpStr += string + ';' | ||||
|     } | ||||
|     // console.log('lanIps:', lanIpStr, ip, port)
 | ||||
|     await Promise.all([ | ||||
|       WindowsSystemProxy._asyncRegSet(regKey, 'MigrateProxy', Registry.REG_DWORD, 1), | ||||
|       WindowsSystemProxy._asyncRegSet(regKey, 'ProxyEnable', Registry.REG_DWORD, 1), | ||||
|       WindowsSystemProxy._asyncRegSet(regKey, 'ProxyHttp1.1', Registry.REG_DWORD, 0), | ||||
|       WindowsSystemProxy._asyncRegSet(regKey, 'ProxyServer', Registry.REG_SZ, `${ip}:${port}`), | ||||
|       WindowsSystemProxy._asyncRegSet(regKey, 'ProxyOverride', Registry.REG_SZ, lanIpStr) | ||||
|     ]) | ||||
|     await WindowsSystemProxy._resetWininetProxySettings('echo refreshing') // 要执行以下这个才能生效
 | ||||
|     await WindowsSystemProxy._resetWininetProxySettings(refreshInternetPs) | ||||
|   } | ||||
| 
 | ||||
|   static async unsetProxy () { | ||||
|     const regKey = new Registry({ | ||||
|       hive: Registry.HKCU, | ||||
|       key: '\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings' | ||||
|     }) | ||||
| 
 | ||||
|     await Promise.all([ | ||||
|       WindowsSystemProxy._asyncRegSet(regKey, 'ProxyEnable', Registry.REG_DWORD, 0), | ||||
|       WindowsSystemProxy._asyncRegSet(regKey, 'ProxyServer', Registry.REG_SZ, '') | ||||
|     ]) | ||||
|     await WindowsSystemProxy._resetWininetProxySettings(refreshInternetPs) | ||||
|   } | ||||
| 
 | ||||
|   static _asyncRegSet (regKey, name, type, value) { | ||||
|     return new Promise((resolve, reject) => { | ||||
|       regKey.set(name, type, value, e => { | ||||
|         if (e) { | ||||
|           reject(e) | ||||
|         } else { | ||||
|           resolve() | ||||
|         } | ||||
|       }) | ||||
|     }) | ||||
|   } | ||||
| 
 | ||||
|   static _resetWininetProxySettings (script) { | ||||
|     return new Promise((resolve, reject) => { | ||||
|       const ps = new PowerShell({ | ||||
|         executionPolicy: 'Bypass', | ||||
|         noProfile: true | ||||
|       }) | ||||
|       // ps.addCommand(setproxyPs)
 | ||||
|       // ps.addCommand(`Set-InternetProxy -Proxy "${ip}:${port}"`)
 | ||||
| 
 | ||||
|       ps.addCommand(script) | ||||
| 
 | ||||
|       ps.invoke() | ||||
|         .then(output => { | ||||
|           console.log(output) | ||||
|           resolve() | ||||
|         }) | ||||
|         .catch(err => { | ||||
|           console.log(err) | ||||
|           reject(err) | ||||
|         }) | ||||
| 
 | ||||
|       // const scriptPath = path.join(__dirname, '..', 'scripts', 'windows', 'wininet-reset-settings.ps1')
 | ||||
|       // const child = spawn('powershell.exe', [scriptPath])
 | ||||
|       // child.stdout.setEncoding('utf8')
 | ||||
|       // child.stdout.on('data', (data) => {
 | ||||
|       //   console.log('data', data)
 | ||||
|       //   if (data.includes('True')) {
 | ||||
|       //     resolve()
 | ||||
|       //   } else {
 | ||||
|       //     reject(data)
 | ||||
|       //   }
 | ||||
|       // })
 | ||||
|       //
 | ||||
|       // child.stderr.on('data', (err) => {
 | ||||
|       //   console.log('data', err)
 | ||||
|       //   reject(err)
 | ||||
|       // })
 | ||||
|       //
 | ||||
|       // child.stdin.end()
 | ||||
|     }) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| function getSystemProxy () { | ||||
|   switch (os.platform()) { | ||||
|     case 'darwin': | ||||
|       return DarwinSystemProxy | ||||
|     case 'linux': | ||||
|       return LinuxSystemProxy | ||||
|     case 'win32': | ||||
|     case 'win64': | ||||
|       return WindowsSystemProxy | ||||
|     case 'unknown os': | ||||
|     default: | ||||
|       throw new Error(`UNKNOWN OS TYPE ${os.platform()}`) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| module.exports = { | ||||
|   async  setProxy (ip, port) { | ||||
|     const systemProxy = getSystemProxy() | ||||
|     await systemProxy.setProxy(ip, port) | ||||
|   }, | ||||
|   async  unsetProxy () { | ||||
|     const systemProxy = getSystemProxy() | ||||
|     await systemProxy.unsetProxy() | ||||
|   } | ||||
| } | ||||
|  | @ -0,0 +1,82 @@ | |||
| const ProxyOptions = require('./options') | ||||
| const mitmproxy = require('../../lib/proxy') | ||||
| const config = require('../../config') | ||||
| const event = require('../../event') | ||||
| const status = require('../../status') | ||||
| const shell = require('../../shell') | ||||
| let server | ||||
| const serverApi = { | ||||
|   async startup () { | ||||
|     if (config.get().server.startup) { | ||||
|       return this.start(config.get().server) | ||||
|     } | ||||
|   }, | ||||
|   async shutdown () { | ||||
|     if (status.server) { | ||||
|       return this.close() | ||||
|     } | ||||
|   }, | ||||
|   async start (newConfig) { | ||||
|     if (server != null) { | ||||
|       server.close() | ||||
|     } | ||||
|     config.set(newConfig) | ||||
|     const proxyOptions = ProxyOptions(config.get()) | ||||
|     const newServer = mitmproxy.createProxy(proxyOptions, () => { | ||||
|       event.fire('status', { key: 'server.enabled', value: true }) | ||||
|       console.log(`代理服务已启动:127.0.0.1:${proxyOptions.port}`) | ||||
|     }) | ||||
|     newServer.on('close', () => { | ||||
|       if (server === newServer) { | ||||
|         server = null | ||||
|         event.fire('status', { key: 'server.enabled', value: false }) | ||||
|       } | ||||
|     }) | ||||
|     newServer.on('error', (e) => { | ||||
|       console.log('server error', e) | ||||
|       // newServer = null
 | ||||
|       event.fire('error', { key: 'server', error: e }) | ||||
|     }) | ||||
|     newServer.config = proxyOptions | ||||
|     server = newServer | ||||
|     return { port: proxyOptions.port } | ||||
|   }, | ||||
|   async close () { | ||||
|     return new Promise((resolve, reject) => { | ||||
|       if (server) { | ||||
|         server.close((err) => { | ||||
|           if (err) { | ||||
|             console.log('close error', err) | ||||
|             reject(err) | ||||
|           } else { | ||||
|             console.log('代理服务关闭') | ||||
|             resolve() | ||||
|           } | ||||
|         }) | ||||
|         // 3秒后强制关闭
 | ||||
|         setTimeout(() => { | ||||
|           console.log('强制关闭') | ||||
|           shell.killByPort(config.get().server.port) | ||||
|           server = null | ||||
|           event.fire('status', { key: 'server.enabled', value: false }) | ||||
|           resolve() | ||||
|         }, 3000) | ||||
|       } else { | ||||
|         console.log('server is null') | ||||
|         resolve() | ||||
|       } | ||||
|     }) | ||||
|   }, | ||||
|   async restart () { | ||||
|     try { | ||||
|       await serverApi.close() | ||||
|     } catch (err) { | ||||
|       console.log('stop error', err) | ||||
|     } | ||||
|     await serverApi.start() | ||||
|   }, | ||||
|   getServer () { | ||||
|     return server | ||||
|   } | ||||
| } | ||||
| module.exports = serverApi | ||||
|  | @ -1,20 +1,18 @@ | |||
| const getLogger = require('../lib/utils/logger') | ||||
| const logger = getLogger('proxy') | ||||
| const interceptors = require('../lib/interceptor') | ||||
| const dnsUtil = require('../lib/dns') | ||||
| const interceptors = require('../../lib/interceptor') | ||||
| const dnsUtil = require('../../lib/dns') | ||||
| const lodash = require('lodash') | ||||
| function matchHostname (intercepts, hostname) { | ||||
|   const interceptOpts = intercepts[hostname] | ||||
|   if (interceptOpts) { | ||||
|     return interceptOpts | ||||
|   } | ||||
|   if (!interceptOpts) { // 该域名没有配置拦截器,直接过
 | ||||
|   if (!interceptOpts) { | ||||
|     for (const target in intercepts) { | ||||
|       if (target.indexOf('*') < 0) { | ||||
|         continue | ||||
|       } | ||||
|       // 正则表达式匹配
 | ||||
|       const regexp = target.replace('.', '\\.').replace('*', '.*') | ||||
|       if (hostname.match(regexp)) { | ||||
|       if (hostname.match(target)) { | ||||
|         return intercepts[target] | ||||
|       } | ||||
|     } | ||||
|  | @ -25,19 +23,62 @@ function isMatched (url, regexp) { | |||
|   return url.match(regexp) | ||||
| } | ||||
| 
 | ||||
| function domainRegexply (target) { | ||||
|   return target.replace(/\./g, '\\.').replace(/\*/g, '.*') | ||||
| } | ||||
| 
 | ||||
| // function test () {
 | ||||
| //   const ret = domainRegexply('*.aaa.com')
 | ||||
| //   console.log(ret)
 | ||||
| //   const success = 'aa.aaa.com'.match(ret)
 | ||||
| //   console.log(success)
 | ||||
| //   const fail = 'a.aaaa.com'.match(ret)
 | ||||
| //   console.log(fail)
 | ||||
| // }
 | ||||
| // test()
 | ||||
| 
 | ||||
| module.exports = (config) => { | ||||
|   let intercepts = lodash.cloneDeep(config.server.intercepts) | ||||
|   const dnsMapping = lodash.cloneDeep(config.server.dns.mapping) | ||||
| 
 | ||||
|   if (config.plugin) { | ||||
|     lodash.each(config.plugin, (value) => { | ||||
|       const plugin = value | ||||
|       if (plugin.intercepts) { | ||||
|         lodash.merge(intercepts, plugin.intercepts) | ||||
|       } | ||||
|       if (plugin.dns) { | ||||
|         lodash.merge(dnsMapping, plugin.dns) | ||||
|       } | ||||
|     }) | ||||
|   } | ||||
| 
 | ||||
|   const regexpIntercepts = {} | ||||
|   lodash.each(intercepts, (value, domain) => { | ||||
|     if (domain.indexOf('*') >= 0) { | ||||
|       const regDomain = domainRegexply(domain) | ||||
|       regexpIntercepts[regDomain] = value | ||||
|     } else { | ||||
|       regexpIntercepts[domain] = value | ||||
|     } | ||||
|   }) | ||||
|   intercepts = regexpIntercepts | ||||
| 
 | ||||
|   const serverConfig = config.server | ||||
| 
 | ||||
|   return { | ||||
|     port: config.server.port, | ||||
|     port: serverConfig.port, | ||||
|     dnsConfig: { | ||||
|       providers: dnsUtil.initDNS(config.dns.providers), mapping: config.dns.mapping | ||||
|       providers: dnsUtil.initDNS(serverConfig.dns.providers), | ||||
|       mapping: dnsMapping | ||||
|     }, | ||||
|     sslConnectInterceptor: (req, cltSocket, head) => { | ||||
|       const hostname = req.url.split(':')[0] | ||||
|       return !!matchHostname(config.intercepts, hostname) // 配置了拦截的域名,将会被代理
 | ||||
|       return !!matchHostname(intercepts, hostname) // 配置了拦截的域名,将会被代理
 | ||||
|     }, | ||||
|     requestInterceptor: (rOptions, req, res, ssl, next) => { | ||||
|       const hostname = rOptions.hostname | ||||
|       const interceptOpts = matchHostname(config.intercepts, hostname) | ||||
|       const interceptOpts = matchHostname(intercepts, hostname) | ||||
|       if (!interceptOpts) { // 该域名没有配置拦截器,直接过
 | ||||
|         next() | ||||
|         return | ||||
|  | @ -45,20 +86,18 @@ module.exports = (config) => { | |||
| 
 | ||||
|       for (const interceptOpt of interceptOpts) { // 遍历拦截配置
 | ||||
|         let regexpList | ||||
|         if(interceptOpt.regexp!=null){ | ||||
|         if (interceptOpt.regexp != null) { | ||||
|           if (interceptOpt.regexp instanceof Array) { | ||||
|             regexpList = interceptOpt.regexp | ||||
|           } else { | ||||
|             regexpList = [interceptOpt.regexp] | ||||
|           } | ||||
|         }else{ | ||||
|         } else { | ||||
|           regexpList = [true] | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|         for (const regexp of regexpList) { // 遍历regexp配置
 | ||||
|           if(regexp!==true){ | ||||
|           if (regexp !== true) { | ||||
|             if (!isMatched(req.url, regexp)) { | ||||
|               continue | ||||
|             } | ||||
|  | @ -75,7 +114,7 @@ module.exports = (config) => { | |||
|               } | ||||
|             } catch (err) { | ||||
|               // 拦截失败
 | ||||
|               logger.error(err) | ||||
|               console.error(err) | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|  | @ -1,55 +0,0 @@ | |||
| const ProxyOptions = require('./options') | ||||
| const mitmproxy = require('../lib/proxy') | ||||
| const config = require('../config') | ||||
| const event = require('../event') | ||||
| let server | ||||
| const serverApi = { | ||||
|   async start (newConfig) { | ||||
|     if (server != null) { | ||||
|       server.close() | ||||
|     } | ||||
|     config.set(newConfig) | ||||
|     const proxyOptions = ProxyOptions(config.get()) | ||||
|     server = mitmproxy.createProxy(proxyOptions, () => { | ||||
|       event.fire('status', { key: 'server', value: true }) | ||||
|     }) | ||||
|     server.on('close', () => { | ||||
|       event.fire('status', { key: 'server', value: false }) | ||||
|     }) | ||||
|     server.on('error', (e) => { | ||||
|       event.fire('error', { key: 'server.start', error: e }) | ||||
|     }) | ||||
|     server.config = config.get() | ||||
|     return server.config | ||||
|   }, | ||||
|   async close () { | ||||
|     return new Promise((resolve, reject) => { | ||||
|       if (server) { | ||||
|         server.close((err) => { | ||||
|           if (err) { | ||||
|             console.log('close error', err) | ||||
|             reject(err) | ||||
|           } else { | ||||
|             resolve() | ||||
|           } | ||||
|         }) | ||||
|         server = null | ||||
|       } else { | ||||
|         console.log('server is null') | ||||
|         resolve() | ||||
|       } | ||||
|     }) | ||||
|   }, | ||||
|   async restart () { | ||||
|     try { | ||||
|       await serverApi.close() | ||||
|     } catch (err) { | ||||
|       console.log('stop error', err) | ||||
|     } | ||||
|     await serverApi.start() | ||||
|   }, | ||||
|   getServer () { | ||||
|     return server | ||||
|   } | ||||
| } | ||||
| module.exports = serverApi | ||||
|  | @ -1,3 +1,4 @@ | |||
| const shell = require('./shell') | ||||
| const killByPort = require('./scripts/kill-by-port') | ||||
| const setupCa = require('./scripts/setup-ca') | ||||
| const getSystemEnv = require('./scripts/get-system-env') | ||||
|  | @ -10,5 +11,8 @@ module.exports = { | |||
|   getSystemEnv, | ||||
|   setSystemEnv, | ||||
|   getNpmEnv, | ||||
|   setNpmEnv | ||||
|   setNpmEnv, | ||||
|   exec (cmds, args) { | ||||
|     shell.getSystemShell().exec(cmds, args) | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -3,9 +3,9 @@ const lodash = require('lodash') | |||
| const status = { | ||||
|   server: false, | ||||
|   proxy: { | ||||
|     system: false, | ||||
|     npm: false, | ||||
|     git: false | ||||
|   }, | ||||
|   plugin: { | ||||
| 
 | ||||
|   } | ||||
| } | ||||
| 
 | ||||
|  | @ -13,4 +13,5 @@ event.register('status', (event) => { | |||
|   lodash.set(status, event.key, event.value) | ||||
|   console.log('status changed:', event) | ||||
| }, -999) | ||||
| 
 | ||||
| module.exports = status | ||||
|  |  | |||
|  | @ -1,93 +1,26 @@ | |||
| const cmd = require('node-cmd') | ||||
| const util = require('util') | ||||
| const winExec = util.promisify(cmd.get, { multiArgs: true, context: cmd }) | ||||
| const os = require('os') | ||||
| const config = require('../../../lib/proxy/common/config') | ||||
| class SystemProxy { | ||||
|   static async setProxy (ip, port) { | ||||
|     throw new Error('You have to implement the method setProxy!') | ||||
|   } | ||||
| 
 | ||||
|   static async unsetProxy () { | ||||
|     throw new Error('You have to implement the method unsetProxy!') | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class DarwinSystemProxy extends SystemProxy { | ||||
| 
 | ||||
| } | ||||
| class LinuxSystemProxy extends SystemProxy { | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| class WindowsSystemProxy extends SystemProxy { | ||||
|   static async setProxy (ip, port) { | ||||
|     let ret = await winExec(`npm config set proxy=http://${ip}:${port}`) | ||||
|     console.log('npm http proxy set success', ret) | ||||
| 
 | ||||
|     ret = await winExec(`npm config set https-proxy=http://${ip}:${port}`) | ||||
|     console.log('npm https proxy set success', ret) | ||||
| 
 | ||||
|     // ret = await winExec(`npm config set cafile ${config.getDefaultCACertPath()}`)
 | ||||
|     // console.log('npm cafile set success', ret)
 | ||||
| 
 | ||||
|     ret = await winExec(`npm config set NODE_EXTRA_CA_CERTS ${config.getDefaultCACertPath()}`) | ||||
|     console.log('npm NODE_EXTRA_CA_CERTS set success', ret) | ||||
| 
 | ||||
|     ret = await winExec('npm config set strict-ssl false') | ||||
|     console.log('npm strict-ssl false success', ret) | ||||
|   } | ||||
| 
 | ||||
|   static async unsetProxy () { | ||||
|     await winExec('npm config  delete proxy') | ||||
|     console.log('npm https proxy unset success') | ||||
|     await winExec('npm config  delete https-proxy') | ||||
|     console.log('npm https proxy unset success') | ||||
| 
 | ||||
|     // await winExec('npm config  delete cafile')
 | ||||
|     // console.log('npm ca unset success')
 | ||||
|     await winExec('npm config  delete NODE_EXTRA_CA_CERTS') | ||||
|     console.log('npm NODE_EXTRA_CA_CERTS unset success') | ||||
| 
 | ||||
|     await winExec(' npm config delete strict-ssl') | ||||
|     console.log('npm strict-ssl true success') | ||||
|   } | ||||
| 
 | ||||
|   static _asyncRegSet (regKey, name, type, value) { | ||||
|     return new Promise((resolve, reject) => { | ||||
|       regKey.set(name, type, value, e => { | ||||
|         if (e) { | ||||
|           reject(e) | ||||
|         } else { | ||||
|           resolve() | ||||
|         } | ||||
|       }) | ||||
|     }) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| function getSystemProxy () { | ||||
|   switch (os.platform()) { | ||||
|     case 'darwin': | ||||
|       return DarwinSystemProxy | ||||
|     case 'linux': | ||||
|       return LinuxSystemProxy | ||||
|     case 'win32': | ||||
|     case 'win64': | ||||
|       return WindowsSystemProxy | ||||
|     case 'unknown os': | ||||
|     default: | ||||
|       throw new Error(`UNKNOWN OS TYPE ${os.platform()}`) | ||||
|   } | ||||
| } | ||||
| const Shell = require('../../../shell') | ||||
| 
 | ||||
| module.exports = { | ||||
|   async setProxy (ip, port) { | ||||
|     const systemProxy = getSystemProxy() | ||||
|     await systemProxy.setProxy(ip, port) | ||||
|     const cmds = [ | ||||
|       `npm config set proxy=http://${ip}:${port}`, | ||||
|       `npm config set https-proxy=http://${ip}:${port}`, | ||||
|       `npm config set NODE_EXTRA_CA_CERTS ${config.getDefaultCACertPath()}`, | ||||
|       'npm config set strict-ssl false' | ||||
|     ] | ||||
|     const ret = await Shell.exec(cmds) | ||||
|     return ret | ||||
|   }, | ||||
| 
 | ||||
|   async unsetProxy () { | ||||
|     const systemProxy = getSystemProxy() | ||||
|     await systemProxy.unsetProxy() | ||||
|     const cmds = [ | ||||
|       'npm config  delete proxy', | ||||
|       'npm config  delete https-proxy', | ||||
|       'npm config  delete NODE_EXTRA_CA_CERTS', | ||||
|       'npm config  delete strict-ssl' | ||||
|     ] | ||||
|     const ret = await Shell.exec(cmds) | ||||
|     return ret | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -6,8 +6,7 @@ const Registry = require('winreg') | |||
| // const cmd = require('node-cmd')
 | ||||
| const exec = util.promisify(_exec) | ||||
| const refreshInternetPs = require('./refresh-internet') | ||||
| const Shell = require('node-powershell') | ||||
| 
 | ||||
| const PowerShell = require('node-powershell') | ||||
| const _lanIP = [ | ||||
|   'localhost', | ||||
|   '127.*', | ||||
|  | @ -124,7 +123,7 @@ class WindowsSystemProxy extends SystemProxy { | |||
| 
 | ||||
|   static _resetWininetProxySettings (script) { | ||||
|     return new Promise((resolve, reject) => { | ||||
|       const ps = new Shell({ | ||||
|       const ps = new PowerShell({ | ||||
|         executionPolicy: 'Bypass', | ||||
|         noProfile: true | ||||
|       }) | ||||
|  |  | |||
|  | @ -1901,8 +1901,7 @@ | |||
|     "@types/json-schema": { | ||||
|       "version": "7.0.6", | ||||
|       "resolved": "https://registry.npm.taobao.org/@types/json-schema/download/@types/json-schema-7.0.6.tgz?cache=0&sync_timestamp=1598910403749&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fjson-schema%2Fdownload%2F%40types%2Fjson-schema-7.0.6.tgz", | ||||
|       "integrity": "sha1-9MfsQ+gbMZqYFRFQMXCfJph4kfA=", | ||||
|       "dev": true | ||||
|       "integrity": "sha1-9MfsQ+gbMZqYFRFQMXCfJph4kfA=" | ||||
|     }, | ||||
|     "@types/json5": { | ||||
|       "version": "0.0.29", | ||||
|  | @ -2372,16 +2371,6 @@ | |||
|           "integrity": "sha1-/q7SVZc9LndVW4PbwIhRpsY1IPo=", | ||||
|           "dev": true | ||||
|         }, | ||||
|         "ansi-styles": { | ||||
|           "version": "4.3.0", | ||||
|           "resolved": "https://registry.npm.taobao.org/ansi-styles/download/ansi-styles-4.3.0.tgz?cache=0&sync_timestamp=1601839122515&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fansi-styles%2Fdownload%2Fansi-styles-4.3.0.tgz", | ||||
|           "integrity": "sha1-7dgDYornHATIWuegkG7a00tkiTc=", | ||||
|           "dev": true, | ||||
|           "optional": true, | ||||
|           "requires": { | ||||
|             "color-convert": "^2.0.1" | ||||
|           } | ||||
|         }, | ||||
|         "cacache": { | ||||
|           "version": "13.0.1", | ||||
|           "resolved": "https://registry.npm.taobao.org/cacache/download/cacache-13.0.1.tgz", | ||||
|  | @ -2408,34 +2397,6 @@ | |||
|             "unique-filename": "^1.1.1" | ||||
|           } | ||||
|         }, | ||||
|         "chalk": { | ||||
|           "version": "4.1.0", | ||||
|           "resolved": "https://registry.npm.taobao.org/chalk/download/chalk-4.1.0.tgz", | ||||
|           "integrity": "sha1-ThSHCmGNni7dl92DRf2dncMVZGo=", | ||||
|           "dev": true, | ||||
|           "optional": true, | ||||
|           "requires": { | ||||
|             "ansi-styles": "^4.1.0", | ||||
|             "supports-color": "^7.1.0" | ||||
|           } | ||||
|         }, | ||||
|         "color-convert": { | ||||
|           "version": "2.0.1", | ||||
|           "resolved": "https://registry.npm.taobao.org/color-convert/download/color-convert-2.0.1.tgz", | ||||
|           "integrity": "sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM=", | ||||
|           "dev": true, | ||||
|           "optional": true, | ||||
|           "requires": { | ||||
|             "color-name": "~1.1.4" | ||||
|           } | ||||
|         }, | ||||
|         "color-name": { | ||||
|           "version": "1.1.4", | ||||
|           "resolved": "https://registry.npm.taobao.org/color-name/download/color-name-1.1.4.tgz", | ||||
|           "integrity": "sha1-wqCah6y95pVD3m9j+jmVyCbFNqI=", | ||||
|           "dev": true, | ||||
|           "optional": true | ||||
|         }, | ||||
|         "find-cache-dir": { | ||||
|           "version": "3.3.1", | ||||
|           "resolved": "https://registry.npm.taobao.org/find-cache-dir/download/find-cache-dir-3.3.1.tgz", | ||||
|  | @ -2457,25 +2418,6 @@ | |||
|             "path-exists": "^4.0.0" | ||||
|           } | ||||
|         }, | ||||
|         "has-flag": { | ||||
|           "version": "4.0.0", | ||||
|           "resolved": "https://registry.npm.taobao.org/has-flag/download/has-flag-4.0.0.tgz", | ||||
|           "integrity": "sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s=", | ||||
|           "dev": true, | ||||
|           "optional": true | ||||
|         }, | ||||
|         "loader-utils": { | ||||
|           "version": "2.0.0", | ||||
|           "resolved": "https://registry.npm.taobao.org/loader-utils/download/loader-utils-2.0.0.tgz", | ||||
|           "integrity": "sha1-5MrOW4FtQloWa18JfhDNErNgZLA=", | ||||
|           "dev": true, | ||||
|           "optional": true, | ||||
|           "requires": { | ||||
|             "big.js": "^5.2.2", | ||||
|             "emojis-list": "^3.0.0", | ||||
|             "json5": "^2.1.2" | ||||
|           } | ||||
|         }, | ||||
|         "locate-path": { | ||||
|           "version": "5.0.0", | ||||
|           "resolved": "https://registry.npm.taobao.org/locate-path/download/locate-path-5.0.0.tgz", | ||||
|  | @ -2540,16 +2482,6 @@ | |||
|             "minipass": "^3.1.1" | ||||
|           } | ||||
|         }, | ||||
|         "supports-color": { | ||||
|           "version": "7.2.0", | ||||
|           "resolved": "https://registry.npm.taobao.org/supports-color/download/supports-color-7.2.0.tgz?cache=0&sync_timestamp=1598611709087&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsupports-color%2Fdownload%2Fsupports-color-7.2.0.tgz", | ||||
|           "integrity": "sha1-G33NyzK4E4gBs+R4umpRyqiWSNo=", | ||||
|           "dev": true, | ||||
|           "optional": true, | ||||
|           "requires": { | ||||
|             "has-flag": "^4.0.0" | ||||
|           } | ||||
|         }, | ||||
|         "terser-webpack-plugin": { | ||||
|           "version": "2.3.8", | ||||
|           "resolved": "https://registry.npm.taobao.org/terser-webpack-plugin/download/terser-webpack-plugin-2.3.8.tgz?cache=0&sync_timestamp=1602701885709&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fterser-webpack-plugin%2Fdownload%2Fterser-webpack-plugin-2.3.8.tgz", | ||||
|  | @ -2566,18 +2498,6 @@ | |||
|             "terser": "^4.6.12", | ||||
|             "webpack-sources": "^1.4.3" | ||||
|           } | ||||
|         }, | ||||
|         "vue-loader-v16": { | ||||
|           "version": "npm:vue-loader@16.0.0-beta.9", | ||||
|           "resolved": "https://registry.npm.taobao.org/vue-loader/download/vue-loader-16.0.0-beta.9.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue-loader%2Fdownload%2Fvue-loader-16.0.0-beta.9.tgz", | ||||
|           "integrity": "sha1-UlEsthwpaCfJnA1UOYvvhL5ESPw=", | ||||
|           "dev": true, | ||||
|           "optional": true, | ||||
|           "requires": { | ||||
|             "chalk": "^4.1.0", | ||||
|             "hash-sum": "^2.0.0", | ||||
|             "loader-utils": "^2.0.0" | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|  | @ -2936,7 +2856,6 @@ | |||
|       "version": "6.12.6", | ||||
|       "resolved": "https://registry.npm.taobao.org/ajv/download/ajv-6.12.6.tgz?cache=0&sync_timestamp=1602353715225&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fajv%2Fdownload%2Fajv-6.12.6.tgz", | ||||
|       "integrity": "sha1-uvWmLoArB9l3A0WG+MO69a3ybfQ=", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "fast-deep-equal": "^3.1.1", | ||||
|         "fast-json-stable-stringify": "^2.0.0", | ||||
|  | @ -2953,8 +2872,7 @@ | |||
|     "ajv-keywords": { | ||||
|       "version": "3.5.2", | ||||
|       "resolved": "https://registry.npm.taobao.org/ajv-keywords/download/ajv-keywords-3.5.2.tgz?cache=0&sync_timestamp=1595907068314&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fajv-keywords%2Fdownload%2Fajv-keywords-3.5.2.tgz", | ||||
|       "integrity": "sha1-MfKdpatuANHC0yms97WSlhTVAU0=", | ||||
|       "dev": true | ||||
|       "integrity": "sha1-MfKdpatuANHC0yms97WSlhTVAU0=" | ||||
|     }, | ||||
|     "alphanum-sort": { | ||||
|       "version": "1.0.2", | ||||
|  | @ -3101,7 +3019,6 @@ | |||
|       "version": "3.1.1", | ||||
|       "resolved": "https://registry.npm.taobao.org/anymatch/download/anymatch-3.1.1.tgz", | ||||
|       "integrity": "sha1-xV7PAhheJGklk5kxDBc84xIzsUI=", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "normalize-path": "^3.0.0", | ||||
|         "picomatch": "^2.0.4" | ||||
|  | @ -4396,14 +4313,12 @@ | |||
|     "big.js": { | ||||
|       "version": "5.2.2", | ||||
|       "resolved": "https://registry.npm.taobao.org/big.js/download/big.js-5.2.2.tgz", | ||||
|       "integrity": "sha1-ZfCvOC9Xi83HQr2cKB6cstd2gyg=", | ||||
|       "dev": true | ||||
|       "integrity": "sha1-ZfCvOC9Xi83HQr2cKB6cstd2gyg=" | ||||
|     }, | ||||
|     "binary-extensions": { | ||||
|       "version": "2.1.0", | ||||
|       "resolved": "https://registry.npm.taobao.org/binary-extensions/download/binary-extensions-2.1.0.tgz", | ||||
|       "integrity": "sha1-MPpAyef+B9vIlWeM0ocCTeokHdk=", | ||||
|       "dev": true | ||||
|       "integrity": "sha1-MPpAyef+B9vIlWeM0ocCTeokHdk=" | ||||
|     }, | ||||
|     "bindings": { | ||||
|       "version": "1.5.0", | ||||
|  | @ -5229,7 +5144,6 @@ | |||
|       "version": "3.4.3", | ||||
|       "resolved": "https://registry.npm.taobao.org/chokidar/download/chokidar-3.4.3.tgz?cache=0&sync_timestamp=1602585381749&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fchokidar%2Fdownload%2Fchokidar-3.4.3.tgz", | ||||
|       "integrity": "sha1-wd84IxRI5FykrFiObHlXO6alfVs=", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "anymatch": "~3.1.1", | ||||
|         "braces": "~3.0.2", | ||||
|  | @ -5245,7 +5159,6 @@ | |||
|           "version": "3.0.2", | ||||
|           "resolved": "https://registry.npm.taobao.org/braces/download/braces-3.0.2.tgz", | ||||
|           "integrity": "sha1-NFThpGLujVmeI23zNs2epPiv4Qc=", | ||||
|           "dev": true, | ||||
|           "requires": { | ||||
|             "fill-range": "^7.0.1" | ||||
|           } | ||||
|  | @ -5254,7 +5167,6 @@ | |||
|           "version": "7.0.1", | ||||
|           "resolved": "https://registry.npm.taobao.org/fill-range/download/fill-range-7.0.1.tgz", | ||||
|           "integrity": "sha1-GRmmp8df44ssfHflGYU12prN2kA=", | ||||
|           "dev": true, | ||||
|           "requires": { | ||||
|             "to-regex-range": "^5.0.1" | ||||
|           } | ||||
|  | @ -5262,14 +5174,12 @@ | |||
|         "is-number": { | ||||
|           "version": "7.0.0", | ||||
|           "resolved": "https://registry.npm.taobao.org/is-number/download/is-number-7.0.0.tgz", | ||||
|           "integrity": "sha1-dTU0W4lnNNX4DE0GxQlVUnoU8Ss=", | ||||
|           "dev": true | ||||
|           "integrity": "sha1-dTU0W4lnNNX4DE0GxQlVUnoU8Ss=" | ||||
|         }, | ||||
|         "to-regex-range": { | ||||
|           "version": "5.0.1", | ||||
|           "resolved": "https://registry.npm.taobao.org/to-regex-range/download/to-regex-range-5.0.1.tgz", | ||||
|           "integrity": "sha1-FkjESq58jZiKMmAY7XL1tN0DkuQ=", | ||||
|           "dev": true, | ||||
|           "requires": { | ||||
|             "is-number": "^7.0.0" | ||||
|           } | ||||
|  | @ -7362,8 +7272,7 @@ | |||
|     "emojis-list": { | ||||
|       "version": "3.0.0", | ||||
|       "resolved": "https://registry.npm.taobao.org/emojis-list/download/emojis-list-3.0.0.tgz", | ||||
|       "integrity": "sha1-VXBmIEatKeLpFucariYKvf9Pang=", | ||||
|       "dev": true | ||||
|       "integrity": "sha1-VXBmIEatKeLpFucariYKvf9Pang=" | ||||
|     }, | ||||
|     "encodeurl": { | ||||
|       "version": "1.0.2", | ||||
|  | @ -8318,8 +8227,7 @@ | |||
|     "fast-deep-equal": { | ||||
|       "version": "3.1.3", | ||||
|       "resolved": "https://registry.npm.taobao.org/fast-deep-equal/download/fast-deep-equal-3.1.3.tgz", | ||||
|       "integrity": "sha1-On1WtVnWy8PrUSMlJE5hmmXGxSU=", | ||||
|       "dev": true | ||||
|       "integrity": "sha1-On1WtVnWy8PrUSMlJE5hmmXGxSU=" | ||||
|     }, | ||||
|     "fast-glob": { | ||||
|       "version": "2.2.7", | ||||
|  | @ -8361,8 +8269,7 @@ | |||
|     "fast-json-stable-stringify": { | ||||
|       "version": "2.1.0", | ||||
|       "resolved": "https://registry.npm.taobao.org/fast-json-stable-stringify/download/fast-json-stable-stringify-2.1.0.tgz?cache=0&sync_timestamp=1576340291001&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffast-json-stable-stringify%2Fdownload%2Ffast-json-stable-stringify-2.1.0.tgz", | ||||
|       "integrity": "sha1-h0v2nG9ATCtdmcSBNBOZ/VWJJjM=", | ||||
|       "dev": true | ||||
|       "integrity": "sha1-h0v2nG9ATCtdmcSBNBOZ/VWJJjM=" | ||||
|     }, | ||||
|     "fast-levenshtein": { | ||||
|       "version": "2.0.6", | ||||
|  | @ -8780,7 +8687,6 @@ | |||
|       "version": "2.1.3", | ||||
|       "resolved": "https://registry.npm.taobao.org/fsevents/download/fsevents-2.1.3.tgz", | ||||
|       "integrity": "sha1-+3OHA66NL5/pAMM4Nt3r7ouX8j4=", | ||||
|       "dev": true, | ||||
|       "optional": true | ||||
|     }, | ||||
|     "function-bind": { | ||||
|  | @ -8848,7 +8754,6 @@ | |||
|       "version": "5.1.1", | ||||
|       "resolved": "https://registry.npm.taobao.org/glob-parent/download/glob-parent-5.1.1.tgz", | ||||
|       "integrity": "sha1-tsHvQXxOVmPqSY8cRa+saRa7wik=", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "is-glob": "^4.0.1" | ||||
|       } | ||||
|  | @ -9855,7 +9760,6 @@ | |||
|       "version": "2.1.0", | ||||
|       "resolved": "https://registry.npm.taobao.org/is-binary-path/download/is-binary-path-2.1.0.tgz", | ||||
|       "integrity": "sha1-6h9/O4DwZCNug0cPhsCcJU+0Wwk=", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "binary-extensions": "^2.0.0" | ||||
|       } | ||||
|  | @ -9964,8 +9868,7 @@ | |||
|     "is-extglob": { | ||||
|       "version": "2.1.1", | ||||
|       "resolved": "https://registry.npm.taobao.org/is-extglob/download/is-extglob-2.1.1.tgz", | ||||
|       "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", | ||||
|       "dev": true | ||||
|       "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" | ||||
|     }, | ||||
|     "is-finite": { | ||||
|       "version": "1.1.0", | ||||
|  | @ -9993,7 +9896,6 @@ | |||
|       "version": "4.0.1", | ||||
|       "resolved": "https://registry.npm.taobao.org/is-glob/download/is-glob-4.0.1.tgz", | ||||
|       "integrity": "sha1-dWfb6fL14kZ7x3q4PEopSCQHpdw=", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "is-extglob": "^2.1.1" | ||||
|       } | ||||
|  | @ -10369,8 +10271,7 @@ | |||
|     "json-schema-traverse": { | ||||
|       "version": "0.4.1", | ||||
|       "resolved": "https://registry.npm.taobao.org/json-schema-traverse/download/json-schema-traverse-0.4.1.tgz?cache=0&sync_timestamp=1599333856086&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjson-schema-traverse%2Fdownload%2Fjson-schema-traverse-0.4.1.tgz", | ||||
|       "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=", | ||||
|       "dev": true | ||||
|       "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=" | ||||
|     }, | ||||
|     "json-stable-stringify-without-jsonify": { | ||||
|       "version": "1.0.1", | ||||
|  | @ -10510,6 +10411,11 @@ | |||
|         "graceful-fs": "^4.1.9" | ||||
|       } | ||||
|     }, | ||||
|     "klona": { | ||||
|       "version": "2.0.4", | ||||
|       "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.4.tgz", | ||||
|       "integrity": "sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA==" | ||||
|     }, | ||||
|     "latest-version": { | ||||
|       "version": "5.1.0", | ||||
|       "resolved": "https://registry.npm.taobao.org/latest-version/download/latest-version-5.1.0.tgz", | ||||
|  | @ -11305,8 +11211,7 @@ | |||
|     "neo-async": { | ||||
|       "version": "2.6.2", | ||||
|       "resolved": "https://registry.npm.taobao.org/neo-async/download/neo-async-2.6.2.tgz", | ||||
|       "integrity": "sha1-tKr7k+OustgXTKU88WOrfXMIMF8=", | ||||
|       "dev": true | ||||
|       "integrity": "sha1-tKr7k+OustgXTKU88WOrfXMIMF8=" | ||||
|     }, | ||||
|     "nice-try": { | ||||
|       "version": "1.0.5", | ||||
|  | @ -11465,8 +11370,7 @@ | |||
|     "normalize-path": { | ||||
|       "version": "3.0.0", | ||||
|       "resolved": "https://registry.npm.taobao.org/normalize-path/download/normalize-path-3.0.0.tgz", | ||||
|       "integrity": "sha1-Dc1p/yOhybEf0JeDFmRKA4ghamU=", | ||||
|       "dev": true | ||||
|       "integrity": "sha1-Dc1p/yOhybEf0JeDFmRKA4ghamU=" | ||||
|     }, | ||||
|     "normalize-range": { | ||||
|       "version": "0.1.2", | ||||
|  | @ -12223,8 +12127,7 @@ | |||
|     "picomatch": { | ||||
|       "version": "2.2.2", | ||||
|       "resolved": "https://registry.npm.taobao.org/picomatch/download/picomatch-2.2.2.tgz?cache=0&sync_timestamp=1584790434095&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpicomatch%2Fdownload%2Fpicomatch-2.2.2.tgz", | ||||
|       "integrity": "sha1-IfMz6ba46v8CRo9RRupAbTRfTa0=", | ||||
|       "dev": true | ||||
|       "integrity": "sha1-IfMz6ba46v8CRo9RRupAbTRfTa0=" | ||||
|     }, | ||||
|     "pify": { | ||||
|       "version": "4.0.1", | ||||
|  | @ -13054,8 +12957,7 @@ | |||
|     "punycode": { | ||||
|       "version": "2.1.1", | ||||
|       "resolved": "https://registry.npm.taobao.org/punycode/download/punycode-2.1.1.tgz", | ||||
|       "integrity": "sha1-tYsBCsQMIsVldhbI0sLALHv0eew=", | ||||
|       "dev": true | ||||
|       "integrity": "sha1-tYsBCsQMIsVldhbI0sLALHv0eew=" | ||||
|     }, | ||||
|     "pupa": { | ||||
|       "version": "2.0.1", | ||||
|  | @ -13300,7 +13202,6 @@ | |||
|       "version": "3.5.0", | ||||
|       "resolved": "https://registry.npm.taobao.org/readdirp/download/readdirp-3.5.0.tgz?cache=0&sync_timestamp=1602584331621&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Freaddirp%2Fdownload%2Freaddirp-3.5.0.tgz", | ||||
|       "integrity": "sha1-m6dMAZsV02UnjS6Ru4xI17TULJ4=", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "picomatch": "^2.2.1" | ||||
|       } | ||||
|  | @ -13761,6 +13662,53 @@ | |||
|         "truncate-utf8-bytes": "^1.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "sass": { | ||||
|       "version": "1.27.1", | ||||
|       "resolved": "https://registry.npmjs.org/sass/-/sass-1.27.1.tgz", | ||||
|       "integrity": "sha512-Co5i3s4kN0AgXe8ZFfIl4pfjHjPgotT81O68m3buwdj7v3oHjYiWNqp0oXTKXnEqyKU30KAYC5u8uUF4x+BKfw==", | ||||
|       "requires": { | ||||
|         "chokidar": ">=2.0.0 <4.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "sass-loader": { | ||||
|       "version": "10.0.4", | ||||
|       "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-10.0.4.tgz", | ||||
|       "integrity": "sha512-zhdZ8qvZM4iL5XjLVEjJLvKWvC+MB+hHgzL2x/Nf7UHpUNmPYsJvypW79bW39g4LZ603dH/dRSsRYzJJIljtdA==", | ||||
|       "requires": { | ||||
|         "klona": "^2.0.4", | ||||
|         "loader-utils": "^2.0.0", | ||||
|         "neo-async": "^2.6.2", | ||||
|         "schema-utils": "^3.0.0", | ||||
|         "semver": "^7.3.2" | ||||
|       }, | ||||
|       "dependencies": { | ||||
|         "loader-utils": { | ||||
|           "version": "2.0.0", | ||||
|           "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", | ||||
|           "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", | ||||
|           "requires": { | ||||
|             "big.js": "^5.2.2", | ||||
|             "emojis-list": "^3.0.0", | ||||
|             "json5": "^2.1.2" | ||||
|           } | ||||
|         }, | ||||
|         "schema-utils": { | ||||
|           "version": "3.0.0", | ||||
|           "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", | ||||
|           "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", | ||||
|           "requires": { | ||||
|             "@types/json-schema": "^7.0.6", | ||||
|             "ajv": "^6.12.5", | ||||
|             "ajv-keywords": "^3.5.2" | ||||
|           } | ||||
|         }, | ||||
|         "semver": { | ||||
|           "version": "7.3.2", | ||||
|           "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", | ||||
|           "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==" | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "sax": { | ||||
|       "version": "1.2.4", | ||||
|       "resolved": "https://registry.npm.taobao.org/sax/download/sax-1.2.4.tgz", | ||||
|  | @ -15725,7 +15673,6 @@ | |||
|       "version": "4.4.0", | ||||
|       "resolved": "https://registry.npm.taobao.org/uri-js/download/uri-js-4.4.0.tgz", | ||||
|       "integrity": "sha1-qnFCYd55PoqCNHp7zJznTobyhgI=", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "punycode": "^2.1.0" | ||||
|       } | ||||
|  | @ -16414,11 +16361,97 @@ | |||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "vue-loader-v16": { | ||||
|       "version": "npm:vue-loader@16.0.0-beta.9", | ||||
|       "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.0.0-beta.9.tgz", | ||||
|       "integrity": "sha512-mu9pg6554GbXDSO8LlxkQM6qUJzUkb/A0FJc9LgRqnU9MCnhzEXwCt1Zx5NObvFpzs2mH2dH/uUCDwL8Qaz9sA==", | ||||
|       "dev": true, | ||||
|       "optional": true, | ||||
|       "requires": { | ||||
|         "chalk": "^4.1.0", | ||||
|         "hash-sum": "^2.0.0", | ||||
|         "loader-utils": "^2.0.0" | ||||
|       }, | ||||
|       "dependencies": { | ||||
|         "ansi-styles": { | ||||
|           "version": "4.3.0", | ||||
|           "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", | ||||
|           "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", | ||||
|           "dev": true, | ||||
|           "optional": true, | ||||
|           "requires": { | ||||
|             "color-convert": "^2.0.1" | ||||
|           } | ||||
|         }, | ||||
|         "chalk": { | ||||
|           "version": "4.1.0", | ||||
|           "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", | ||||
|           "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", | ||||
|           "dev": true, | ||||
|           "optional": true, | ||||
|           "requires": { | ||||
|             "ansi-styles": "^4.1.0", | ||||
|             "supports-color": "^7.1.0" | ||||
|           } | ||||
|         }, | ||||
|         "color-convert": { | ||||
|           "version": "2.0.1", | ||||
|           "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", | ||||
|           "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", | ||||
|           "dev": true, | ||||
|           "optional": true, | ||||
|           "requires": { | ||||
|             "color-name": "~1.1.4" | ||||
|           } | ||||
|         }, | ||||
|         "color-name": { | ||||
|           "version": "1.1.4", | ||||
|           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", | ||||
|           "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", | ||||
|           "dev": true, | ||||
|           "optional": true | ||||
|         }, | ||||
|         "has-flag": { | ||||
|           "version": "4.0.0", | ||||
|           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", | ||||
|           "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", | ||||
|           "dev": true, | ||||
|           "optional": true | ||||
|         }, | ||||
|         "loader-utils": { | ||||
|           "version": "2.0.0", | ||||
|           "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", | ||||
|           "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", | ||||
|           "dev": true, | ||||
|           "optional": true, | ||||
|           "requires": { | ||||
|             "big.js": "^5.2.2", | ||||
|             "emojis-list": "^3.0.0", | ||||
|             "json5": "^2.1.2" | ||||
|           } | ||||
|         }, | ||||
|         "supports-color": { | ||||
|           "version": "7.2.0", | ||||
|           "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", | ||||
|           "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", | ||||
|           "dev": true, | ||||
|           "optional": true, | ||||
|           "requires": { | ||||
|             "has-flag": "^4.0.0" | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "vue-ref": { | ||||
|       "version": "2.0.0", | ||||
|       "resolved": "https://registry.npm.taobao.org/vue-ref/download/vue-ref-2.0.0.tgz", | ||||
|       "integrity": "sha1-SDCE1zKr7RHaeWd4qCZqOvDqGpw=" | ||||
|     }, | ||||
|     "vue-router": { | ||||
|       "version": "3.4.8", | ||||
|       "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.4.8.tgz", | ||||
|       "integrity": "sha512-3BsR84AqarcmweXjItxw3jwQsiYNssYg090yi4rlzTnCJxmHtkyCvhNz9Z7qRSOkmiV485KkUCReTp5AjNY4wg==" | ||||
|     }, | ||||
|     "vue-style-loader": { | ||||
|       "version": "4.1.2", | ||||
|       "resolved": "https://registry.npm.taobao.org/vue-style-loader/download/vue-style-loader-4.1.2.tgz", | ||||
|  |  | |||
|  | @ -22,8 +22,11 @@ | |||
|     "es-abstract": "^1.17.7", | ||||
|     "json5": "^2.1.3", | ||||
|     "lodash": "^4.17.20", | ||||
|     "sass": "^1.27.1", | ||||
|     "sass-loader": "^10.0.4", | ||||
|     "vue": "^2.6.11", | ||||
|     "vue-json-editor": "^1.4.2" | ||||
|     "vue-json-editor": "^1.4.2", | ||||
|     "vue-router": "^3.4.8" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "@vue/cli-plugin-babel": "~4.5.0", | ||||
|  |  | |||
|  | @ -58,7 +58,7 @@ function setTray (app) { | |||
| function createWindow () { | ||||
|   // Create the browser window.
 | ||||
|   win = new BrowserWindow({ | ||||
|     width: 800, | ||||
|     width: 900, | ||||
|     height: 700, | ||||
|     webPreferences: { | ||||
|       enableRemoteModule: true, | ||||
|  |  | |||
|  | @ -132,6 +132,7 @@ export default { | |||
| 
 | ||||
|     // 合并用户配置
 | ||||
|     localApi.config.reload() | ||||
|     DevSidecar.api.startup() | ||||
|   }, | ||||
|   devSidecar: DevSidecar | ||||
| } | ||||
|  |  | |||
|  | @ -1,16 +1,37 @@ | |||
| import Vue from 'vue' | ||||
| import App from './view/components/App.vue' | ||||
| import App from './view/App.vue' | ||||
| import antd from 'ant-design-vue' | ||||
| import 'ant-design-vue/dist/antd.css' | ||||
| import view from './view' | ||||
| import { apiInit } from './view/api' | ||||
| import VueRouter from 'vue-router' | ||||
| import routes from './view/router' | ||||
| import DsContainer from './view/components/container' | ||||
| Vue.config.productionTip = false | ||||
| Vue.use(antd) | ||||
| Vue.use(VueRouter) | ||||
| Vue.component(DsContainer) | ||||
| // 3. 创建 router 实例,然后传 `routes` 配置
 | ||||
| // 你还可以传别的配置参数, 不过先这么简单着吧。
 | ||||
| const router = new VueRouter({ | ||||
|   routes // (缩写) 相当于 routes: routes
 | ||||
| }) | ||||
| 
 | ||||
| apiInit().then(() => { | ||||
| apiInit().then((api) => { | ||||
|   const app = new Vue({ | ||||
|     router, | ||||
|     render: h => h(App) | ||||
|   }).$mount('#app') | ||||
| 
 | ||||
|   view.register(app) | ||||
| }) | ||||
| 
 | ||||
| // fix vue-router NavigationDuplicated
 | ||||
| const VueRouterPush = VueRouter.prototype.push | ||||
| VueRouter.prototype.push = function push (location) { | ||||
|   return VueRouterPush.call(this, location).catch(err => err) | ||||
| } | ||||
| const VueRouterReplace = VueRouter.prototype.replace | ||||
| VueRouter.prototype.replace = function replace (location) { | ||||
|   return VueRouterReplace.call(this, location).catch(err => err) | ||||
| } | ||||
|  |  | |||
|  | @ -0,0 +1,122 @@ | |||
| <template> | ||||
|   <div class="ds_layout"> | ||||
|     <a-layout> | ||||
|       <a-layout-sider theme="light"> | ||||
|         <div class="logo" > | ||||
|           <img height="60px" src="/logo/logo-lang.svg"> | ||||
|         </div> | ||||
|         <div class="aside"> | ||||
|           <a-menu | ||||
|             mode="inline" | ||||
|             :defaultSelectedKeys="[$route.fullPath]" | ||||
|           > | ||||
|             <template v-for="(item) of menus"> | ||||
|               <a-sub-menu v-if="item.children && item.children.length>0"   :key="item.path" @titleClick="titleClick(item)"> | ||||
|                 <span slot="title"><a-icon  :type="item.icon?item.icon:'file'" /><span>{{item.title}}</span></span> | ||||
|                   <a-menu-item v-for="(sub) of item.children" :key="sub.path" @click="menuClick(sub)" > | ||||
|                     {{ sub.title }} | ||||
|                   </a-menu-item> | ||||
|               </a-sub-menu> | ||||
|               <a-menu-item v-else :key="item.path" @click="menuClick(item)"> | ||||
|                 <a-icon  :type="item.icon?item.icon:'file'"/> | ||||
|                 <span class="nav-text">{{ item.title }}</span> | ||||
|               </a-menu-item> | ||||
|             </template> | ||||
| 
 | ||||
|           </a-menu> | ||||
| 
 | ||||
|         </div> | ||||
| 
 | ||||
|       </a-layout-sider> | ||||
|       <a-layout> | ||||
| <!--        <a-layout-header>Header</a-layout-header>--> | ||||
|         <a-layout-content> | ||||
|           <router-view></router-view> | ||||
|         </a-layout-content> | ||||
|         <a-layout-footer> | ||||
|           <div class="footer"> | ||||
|             ©2020 docmirror.cn | ||||
|           </div> | ||||
|         </a-layout-footer> | ||||
|       </a-layout> | ||||
|     </a-layout> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| export default { | ||||
|   name: 'App', | ||||
|   components: { | ||||
|   }, | ||||
|   data () { | ||||
|     return { | ||||
|       menus: [ | ||||
|         { title: '首页', path: '/index', icon: 'home' }, | ||||
|         { title: '加速服务', path: '/server' }, | ||||
|         { title: '系统代理', path: '/proxy' }, | ||||
|         { | ||||
|           title: '应用', | ||||
|           path: '/app', | ||||
|           children: [ | ||||
|             { title: 'NPM加速', path: '/app/node' } | ||||
|           ] | ||||
|         } | ||||
|       ] | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|   }, | ||||
|   created () { | ||||
|   }, | ||||
|   methods: { | ||||
|     handleClick (e) { | ||||
|       console.log('click', e) | ||||
|     }, | ||||
|     titleClick (e) { | ||||
|       console.log('titleClick', e) | ||||
|     }, | ||||
|     menuClick (item) { | ||||
|       console.log('menu click', item) | ||||
|       this.$router.push(item.path) | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
| 
 | ||||
| <style lang="scss"> | ||||
| body{ | ||||
|   height: 100%; | ||||
| } | ||||
| .ds_layout { | ||||
|   font-family: Avenir, Helvetica, Arial, sans-serif; | ||||
|   -webkit-font-smoothing: antialiased; | ||||
|   -moz-osx-font-smoothing: grayscale; | ||||
|   color: #2c3e50; | ||||
|   height: 100%; | ||||
|   .ant-layout-has-sider{ | ||||
|     border:1px solid #eee; | ||||
|   } | ||||
|   .ant-layout-sider-children{ | ||||
|     border-right:1px solid #eee; | ||||
|   } | ||||
|   .ant-layout{ | ||||
|     height:100% | ||||
|   } | ||||
|   .logo{ | ||||
|     padding:5px; | ||||
|     border-bottom: #eee solid 1px; | ||||
|     height:60px; | ||||
|     img{ | ||||
|       height:100% | ||||
|     } | ||||
|   } | ||||
|   .ant-layout-footer{ | ||||
|     padding:10px; | ||||
|     text-align: center; | ||||
|     border-top:#d6d4d4 solid 1px; | ||||
|   } | ||||
|   .ant-menu-inline, .ant-menu-vertical, .ant-menu-vertical-left{ | ||||
|     border:0; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
|  | @ -26,6 +26,7 @@ export function apiInit () { | |||
|       for (const item of list) { | ||||
|         bindApi(item) | ||||
|       } | ||||
|       console.log('api inited:', apiObj) | ||||
|       return apiObj | ||||
|     }) | ||||
|   } | ||||
|  |  | |||
|  | @ -1,203 +0,0 @@ | |||
| <template> | ||||
|   <div id="app"> | ||||
|     <template> | ||||
|       <div style="margin:auto"> | ||||
|         <div style="text-align: center"><img height="80px" src="/logo/logo-lang.svg"></div> | ||||
|         <a-card title="给开发者的辅助工具" style="width: 500px;margin:auto"> | ||||
|           <div style="display: flex; align-items:center;justify-content:space-around;flex-direction: row"> | ||||
|             <div style="text-align: center"> | ||||
|               <div class="big_button" > | ||||
|                 <a-button shape="circle"  :type="startup.type()" :loading="startup.loading" @click="startup.doClick"  > | ||||
|                   <img v-if="!startup.loading && !status.server" width="50" src="/logo/logo-simple.svg"> | ||||
|                  <img v-if="!startup.loading && status.server" width="50" src="/logo/logo-fff.svg"> | ||||
|                 </a-button> | ||||
|                 <div style="margin-top: 10px">{{status.server?'已开启':'已关闭'}}</div> | ||||
|               </div> | ||||
|             </div> | ||||
|             <div :span="12"> | ||||
|               <a-form  style="margin-top:20px" :label-col="{ span: 12 }" :wrapper-col="{ span: 12 }" > | ||||
|                 <a-form-item label="代理服务"> | ||||
|                   <a-switch :loading="server.loading" v-model="status.server"  default-checked   v-on:click="server.doClick"> | ||||
|                     <a-icon slot="checkedChildren" type="check" /> | ||||
|                     <a-icon slot="unCheckedChildren" type="close" /> | ||||
|                   </a-switch> | ||||
|                 </a-form-item> | ||||
| 
 | ||||
|                 <a-form-item v-for=" (item, key) in proxy" :key="key"  :label="_lang(key,langSetting.proxy) "> | ||||
|                   <a-switch :loading="item.loading" v-model="status.proxy[key]"  default-checked   v-on:click="item.doClick"> | ||||
|                     <a-icon slot="checkedChildren" type="check" /> | ||||
|                     <a-icon slot="unCheckedChildren" type="close" /> | ||||
|                   </a-switch> | ||||
|                 </a-form-item> | ||||
| 
 | ||||
|               </a-form> | ||||
| 
 | ||||
|             </div> | ||||
|           </div> | ||||
| 
 | ||||
|            <span  slot="extra" > | ||||
|                 <a-button style="margin-right:10px" @click="openSetupCa" >安装根证书</a-button> | ||||
|                 <a-button v-if="config" @click="openSettings" icon="setting" ></a-button> | ||||
|            </span> | ||||
|         </a-card> | ||||
| 
 | ||||
|         <setup-ca title="安装证书" :visible.sync="setupCa.visible"></setup-ca> | ||||
|         <settings  v-if="config" title="设置" :config="config" :visible.sync="settings.visible"  @change="onConfigChanged"></settings> | ||||
|       </div> | ||||
|     </template> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import api from '../api' | ||||
| import status from '../status' | ||||
| import lodash from 'lodash' | ||||
| import Settings from './settings' | ||||
| import setupCa from './setup-ca' | ||||
| export default { | ||||
|   name: 'App', | ||||
|   components: { | ||||
|     Settings, setupCa | ||||
|   }, | ||||
|   data () { | ||||
|     return { | ||||
|       langSetting: { | ||||
|         proxy: { | ||||
|           system: '系统代理', | ||||
|           npm: 'npm代理', | ||||
|           yarn: 'yarn代理' | ||||
|         } | ||||
|       }, | ||||
|       status: status, | ||||
|       startup: { | ||||
|         loading: false, | ||||
|         type: () => { | ||||
|           return this.status.server ? 'primary' : 'default' | ||||
|         }, | ||||
|         doClick: () => { | ||||
|           if (this.status.server) { | ||||
|             this.apiCall(this.startup, api.shutdown) | ||||
|           } else { | ||||
|             this.apiCall(this.startup, api.startup) | ||||
|           } | ||||
|         } | ||||
|       }, | ||||
|       server: { | ||||
|         key: '代理服务', | ||||
|         loading: false, | ||||
|         doClick: (checked) => { | ||||
|           this.onServerClick(checked) | ||||
|         } | ||||
|       }, | ||||
|       proxy: undefined, | ||||
|       config: undefined, | ||||
|       settings: { | ||||
|         visible: false | ||||
|       }, | ||||
|       setupCa: { | ||||
|         visible: false | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     _intercepts () { | ||||
|       return this.config.intercepts | ||||
|     } | ||||
|   }, | ||||
|   created () { | ||||
|     this.proxy = this.createProxyBtns() | ||||
|     this.reloadConfig().then(() => { | ||||
|       this.start(true) | ||||
|     }) | ||||
|   }, | ||||
|   methods: { | ||||
|     reloadConfig () { | ||||
|       return api.config.reload().then(ret => { | ||||
|         this.config = ret | ||||
|         return ret | ||||
|       }) | ||||
|     }, | ||||
|     _lang (key, parent) { | ||||
|       const label = parent ? lodash.get(parent, key) : lodash.get(this.langSetting, key) | ||||
|       if (label) { | ||||
|         return label | ||||
|       } | ||||
|       return key | ||||
|     }, | ||||
|     createProxyBtns () { | ||||
|       const btns = {} | ||||
|       for (const type in api.proxy) { | ||||
|         btns[type] = { | ||||
|           loading: false, | ||||
|           key: type, | ||||
|           doClick: (checked) => { | ||||
|             this.onSwitchClick(this.proxy[type], api.proxy[type].open, api.proxy[type].close, checked) | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|       return btns | ||||
|     }, | ||||
|     async apiCall (btn, api, param) { | ||||
|       btn.loading = true | ||||
|       try { | ||||
|         const ret = await api(param) | ||||
|         return ret | ||||
|       } catch (err) { | ||||
|         console.log('api invoke error:', err) | ||||
|       } finally { | ||||
|         btn.loading = false | ||||
|       } | ||||
|     }, | ||||
| 
 | ||||
|     onSwitchClick (btn, openApi, closeApi, checked) { | ||||
|       if (checked) { | ||||
|         return this.apiCall(btn, openApi) | ||||
|       } else { | ||||
|         return this.apiCall(btn, closeApi) | ||||
|       } | ||||
|     }, | ||||
|     onServerClick (checked) { | ||||
|       return this.onSwitchClick(this.server, api.server.start, api.server.close, checked) | ||||
|     }, | ||||
|     start (checked) { | ||||
|       this.apiCall(this.startup, api.startup) | ||||
|     }, | ||||
|     openSettings () { | ||||
|       this.settings.visible = true | ||||
|     }, | ||||
|     onConfigChanged (newConfig) { | ||||
|       console.log('config changed', newConfig) | ||||
|       this.reloadConfig().then(() => { | ||||
|         if (this.status.server) { | ||||
|           return api.server.restart() | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     openSetupCa () { | ||||
|       this.setupCa.visible = true | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
| 
 | ||||
| <style> | ||||
| #app { | ||||
|   font-family: Avenir, Helvetica, Arial, sans-serif; | ||||
|   -webkit-font-smoothing: antialiased; | ||||
|   -moz-osx-font-smoothing: grayscale; | ||||
|   color: #2c3e50; | ||||
|   padding-top:60px; | ||||
| } | ||||
| 
 | ||||
| .big_button >button{ | ||||
|   width:100px; | ||||
|   height:100px; | ||||
|   border-radius: 100px; | ||||
| } | ||||
| .big_button >button i{ | ||||
|   size:40px | ||||
| } | ||||
| div.ant-form-item{ | ||||
|   margin-bottom: 10px; | ||||
| } | ||||
| </style> | ||||
|  | @ -0,0 +1,53 @@ | |||
| <template> | ||||
|   <div class="ds-container"> | ||||
|     <div class="body-wrapper"> | ||||
|       <div v-if="$slots.header" class="container-header"><slot name="header"></slot></div> | ||||
|       <div class="container-body"> <slot></slot></div> | ||||
|       <div class="container-footer"> <slot name="footer"></slot></div> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| export default { | ||||
|   name: 'ds-container' | ||||
| } | ||||
| </script> | ||||
| 
 | ||||
| <style lang="scss"> | ||||
| .ds-container{ | ||||
|   height:100%; | ||||
|   background: #fff; | ||||
|   display: flex; | ||||
|   position: relative; | ||||
| 
 | ||||
|   .body-wrapper{ | ||||
|     position: absolute; | ||||
|     top: 0px; | ||||
|     right: 0px; | ||||
|     bottom: 0px; | ||||
|     left: 0px; | ||||
|     display: flex; | ||||
|     flex-direction: column; | ||||
|     overflow: hidden; | ||||
|   } | ||||
| 
 | ||||
|   .container-header{ | ||||
|     padding:15px; | ||||
|     border-bottom: 1px solid #EEE; | ||||
|     background: #FFF; | ||||
|     height:60px; | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     justify-content:  space-between; | ||||
|   } | ||||
|   .container-body{ | ||||
|     flex: 1; | ||||
|     height: 0; | ||||
|     overflow: auto; | ||||
|     position: relative; | ||||
|     padding:15px; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| </style> | ||||
|  | @ -12,7 +12,7 @@ function register (app) { | |||
|   api.on('error.core', (event, message) => { | ||||
|     console.error('view on error', message) | ||||
|     const key = message.key | ||||
|     if (key === 'server.start') { | ||||
|     if (key === 'server') { | ||||
|       handleServerStartError(message.error, app) | ||||
|     } | ||||
|   }) | ||||
|  |  | |||
|  | @ -0,0 +1,3 @@ | |||
| <template> | ||||
|   <div>node</div> | ||||
| </template> | ||||
|  | @ -0,0 +1,195 @@ | |||
| <template> | ||||
|   <ds-container> | ||||
|     <template slot="header"> | ||||
|       给开发者的辅助工具 | ||||
|       <span> | ||||
|           <a-button style="margin-right:10px" @click="openSetupCa">安装根证书</a-button> | ||||
|       </span> | ||||
|     </template> | ||||
| 
 | ||||
|     <div style="display: flex; align-items:center;justify-content:space-around;flex-direction: row"> | ||||
|       <div style="text-align: center"> | ||||
|         <div class="big_button"> | ||||
|           <a-button shape="circle" :type="startup.type()" :loading="startup.loading" @click="startup.doClick"> | ||||
|             <img v-if="!startup.loading && !status.server" width="50" src="/logo/logo-simple.svg"> | ||||
|             <img v-if="!startup.loading && status.server" width="50" src="/logo/logo-fff.svg"> | ||||
|           </a-button> | ||||
|           <div style="margin-top: 10px">{{ status.server ? '已开启' : '已关闭' }}</div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div :span="12"> | ||||
|         <a-form style="margin-top:20px" :label-col="{ span: 12 }" :wrapper-col="{ span: 12 }"> | ||||
| 
 | ||||
|           <a-form-item v-for=" (item, key) in switchBtns" :key="key" :label="item.label"> | ||||
|             <a-switch :loading="item.loading" v-model="item.status[key].enabled" default-checked v-on:click="item.doClick"> | ||||
|               <a-icon slot="checkedChildren" type="check"/> | ||||
|               <a-icon slot="unCheckedChildren" type="close"/> | ||||
|             </a-switch> | ||||
|           </a-form-item> | ||||
| 
 | ||||
|         </a-form> | ||||
| 
 | ||||
|       </div> | ||||
|     </div> | ||||
|     <setup-ca title="安装证书" :visible.sync="setupCa.visible"></setup-ca> | ||||
|   </ds-container> | ||||
| 
 | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import api from '../api' | ||||
| import status from '../status' | ||||
| import lodash from 'lodash' | ||||
| import setupCa from '../components/setup-ca' | ||||
| import DsContainer from '../components/container' | ||||
| 
 | ||||
| export default { | ||||
|   name: 'Index', | ||||
|   components: { | ||||
|     DsContainer, | ||||
|     setupCa | ||||
|   }, | ||||
|   data () { | ||||
|     return { | ||||
|       status: { | ||||
|         proxy: {}, | ||||
|         plugin: { | ||||
|           node: {} | ||||
|         } | ||||
|       }, | ||||
|       startup: { | ||||
|         loading: false, | ||||
|         type: () => { | ||||
|           return this.status.server ? 'primary' : 'default' | ||||
|         }, | ||||
|         doClick: () => { | ||||
|           if (this.status.server) { | ||||
|             this.apiCall(this.startup, api.shutdown) | ||||
|           } else { | ||||
|             this.apiCall(this.startup, api.startup) | ||||
|           } | ||||
|         } | ||||
|       }, | ||||
|       server: { | ||||
|         key: '代理服务', | ||||
|         loading: false, | ||||
|         doClick: (checked) => { | ||||
|           this.onServerClick(checked) | ||||
|         } | ||||
|       }, | ||||
|       switchBtns: undefined, | ||||
|       config: undefined, | ||||
|       setupCa: { | ||||
|         visible: false | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   created () { | ||||
|     console.log('index created') | ||||
|     this.reloadConfig().then(() => { | ||||
|       // this.start(true) | ||||
|       return api.status.get().then(ret => { | ||||
|         console.log('status', ret) | ||||
|         lodash.merge(status, ret) | ||||
|         this.$set(this, 'status', status) | ||||
|       }) | ||||
|     }).then(() => { | ||||
|       this.switchBtns = this.createSwitchBtns() | ||||
|     }) | ||||
|   }, | ||||
|   mounted () { | ||||
|     console.log('index mounted') | ||||
|   }, | ||||
|   methods: { | ||||
|     reloadConfig () { | ||||
|       return api.config.reload().then(ret => { | ||||
|         this.config = ret | ||||
|         return ret | ||||
|       }) | ||||
|     }, | ||||
|     createSwitchBtns () { | ||||
|       console.log('api,', api) | ||||
|       const btns = {} | ||||
|       btns.server = this.createSwitchBtn('server', '代理服务', api.server, status) | ||||
|       btns.proxy = this.createSwitchBtn('proxy', '系统代理', api.proxy, status) | ||||
|       lodash.forEach(this.status.plugin, (item, key) => { | ||||
|         btns[key] = this.createSwitchBtn(key, this.config.plugin[key].name, api.plugin[key], status.plugin) | ||||
|       }) | ||||
|       return btns | ||||
|     }, | ||||
|     createSwitchBtn (key, label, apiTarget, statusParent) { | ||||
|       return { | ||||
|         loading: false, | ||||
|         key: key, | ||||
|         label: label, | ||||
|         status: statusParent, | ||||
|         doClick: (checked) => { | ||||
|           this.onSwitchClick(this.switchBtns[key], apiTarget.start, apiTarget.close, checked) | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     async apiCall (btn, api, param) { | ||||
|       btn.loading = true | ||||
|       try { | ||||
|         const ret = await api(param) | ||||
|         return ret | ||||
|       } catch (err) { | ||||
|         console.log('api invoke error:', err) | ||||
|       } finally { | ||||
|         btn.loading = false | ||||
|       } | ||||
|     }, | ||||
| 
 | ||||
|     onSwitchClick (btn, openApi, closeApi, checked) { | ||||
|       if (checked) { | ||||
|         return this.apiCall(btn, openApi) | ||||
|       } else { | ||||
|         return this.apiCall(btn, closeApi) | ||||
|       } | ||||
|     }, | ||||
|     onServerClick (checked) { | ||||
|       return this.onSwitchClick(this.server, api.server.start, api.server.close, checked) | ||||
|     }, | ||||
|     start (checked) { | ||||
|       this.apiCall(this.startup, api.startup) | ||||
|     }, | ||||
|     openSettings () { | ||||
|       this.settings.visible = true | ||||
|     }, | ||||
|     onConfigChanged (newConfig) { | ||||
|       console.log('config changed', newConfig) | ||||
|       this.reloadConfig().then(() => { | ||||
|         if (this.status.server) { | ||||
|           return api.server.restart() | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     openSetupCa () { | ||||
|       this.setupCa.visible = true | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
| <style> | ||||
| .page_index { | ||||
|   font-family: Avenir, Helvetica, Arial, sans-serif; | ||||
|   -webkit-font-smoothing: antialiased; | ||||
|   -moz-osx-font-smoothing: grayscale; | ||||
|   color: #2c3e50; | ||||
|   padding-top: 60px; | ||||
| } | ||||
| 
 | ||||
| .big_button > button { | ||||
|   width: 100px; | ||||
|   height: 100px; | ||||
|   border-radius: 100px; | ||||
| } | ||||
| 
 | ||||
| .big_button > button i { | ||||
|   size: 40px | ||||
| } | ||||
| 
 | ||||
| div.ant-form-item { | ||||
|   margin-bottom: 10px; | ||||
| } | ||||
| </style> | ||||
|  | @ -0,0 +1,3 @@ | |||
| <template> | ||||
|   <div>proxy</div> | ||||
| </template> | ||||
|  | @ -0,0 +1,3 @@ | |||
| <template> | ||||
|   <div>server</div> | ||||
| </template> | ||||
|  | @ -0,0 +1,15 @@ | |||
| import Index from '../pages/index' | ||||
| import Server from '../pages/server' | ||||
| import Proxy from '../pages/proxy' | ||||
| import Node from '../pages/app/node' | ||||
| 
 | ||||
| const routes = [ | ||||
|   { path: '/', redirect: '/index' }, | ||||
|   { path: '/index', component: Index }, | ||||
|   { path: '/server', component: Server }, | ||||
|   { path: '/proxy', component: Proxy }, | ||||
|   { path: '/app/node', component: Node } | ||||
| 
 | ||||
| ] | ||||
| 
 | ||||
| export default routes | ||||
		Loading…
	
		Reference in New Issue
	
	 xiaojunnuo
						xiaojunnuo