refactor: 插件化
parent
2be957968e
commit
3f81235e86
|
@ -32,6 +32,9 @@ const configApi = {
|
||||||
getDefault () {
|
getDefault () {
|
||||||
return lodash.cloneDeep(defConfig)
|
return lodash.cloneDeep(defConfig)
|
||||||
},
|
},
|
||||||
|
addDefault (key, defValue) {
|
||||||
|
lodash.set(defConfig, key, defValue)
|
||||||
|
},
|
||||||
resetDefault () {
|
resetDefault () {
|
||||||
configTarget = lodash.cloneDeep(defConfig)
|
configTarget = lodash.cloneDeep(defConfig)
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,145 +1,118 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
server: {
|
server: {
|
||||||
port: 1181
|
enabled: true,
|
||||||
},
|
port: 1181,
|
||||||
intercepts: {
|
intercepts: {
|
||||||
'github.com': [
|
'github.com': [
|
||||||
{
|
{
|
||||||
// "release archive 下载链接替换",
|
// "release archive 下载链接替换",
|
||||||
regexp: [
|
regexp: [
|
||||||
'/.*/.*/releases/download/',
|
'/.*/.*/releases/download/',
|
||||||
'/.*/.*/archive/'
|
'/.*/.*/archive/'
|
||||||
],
|
],
|
||||||
redirect: 'download.fastgit.org'
|
redirect: 'download.fastgit.org'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
regexp: [
|
regexp: [
|
||||||
'/.*/.*/raw/',
|
'/.*/.*/raw/',
|
||||||
'/.*/.*/blame/'
|
'/.*/.*/blame/'
|
||||||
],
|
],
|
||||||
redirect: 'hub.fastgit.org'
|
redirect: 'hub.fastgit.org'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
// 'codeload.github.com': [
|
// 'codeload.github.com': [
|
||||||
// {
|
// {
|
||||||
// regexp: '.*',
|
// regexp: '.*',
|
||||||
// redirect:"download.fastgit.org"
|
// redirect:"download.fastgit.org"
|
||||||
// }
|
// }
|
||||||
// ],
|
// ],
|
||||||
'raw.githubusercontent.com': [{ proxy: 'raw.fastgit.org' }],
|
'raw.githubusercontent.com': [{ proxy: 'raw.fastgit.org' }],
|
||||||
'github.githubassets.com': [
|
'github.githubassets.com': [
|
||||||
{
|
{
|
||||||
proxy: 'assets.fastgit.org'
|
proxy: 'assets.fastgit.org'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
'customer-stories-feed.github.com': [
|
'customer-stories-feed.github.com': [
|
||||||
{
|
{
|
||||||
proxy: 'customer-stories-feed.fastgit.org'
|
proxy: 'customer-stories-feed.fastgit.org'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
// google cdn
|
// google cdn
|
||||||
'ajax.googleapis.com': [
|
'ajax.googleapis.com': [
|
||||||
{
|
{
|
||||||
proxy: 'ajax.loli.net',
|
proxy: 'ajax.loli.net',
|
||||||
backup: ['ajax.proxy.ustclug.org'],
|
backup: ['ajax.proxy.ustclug.org'],
|
||||||
case: 'ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js'
|
case: 'ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
'fonts.googleapis.com': [
|
'fonts.googleapis.com': [
|
||||||
{
|
{
|
||||||
proxy: 'fonts.loli.net',
|
proxy: 'fonts.loli.net',
|
||||||
backup: ['fonts.proxy.ustclug.org'],
|
backup: ['fonts.proxy.ustclug.org'],
|
||||||
case: 'https://fonts.googleapis.com/css?family=Oswald'
|
case: 'https://fonts.googleapis.com/css?family=Oswald'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
'themes.googleapis.com': [
|
'themes.googleapis.com': [
|
||||||
{
|
{
|
||||||
proxy: 'themes.loli.net',
|
proxy: 'themes.loli.net',
|
||||||
backup: ['themes.proxy.ustclug.org']
|
backup: ['themes.proxy.ustclug.org']
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
'themes.googleusercontent.com': [
|
'themes.googleusercontent.com': [
|
||||||
{ proxy: 'google-themes.proxy.ustclug.org' }
|
{ proxy: 'google-themes.proxy.ustclug.org' }
|
||||||
],
|
],
|
||||||
'www.google.com': [
|
'www.google.com': [
|
||||||
{
|
{
|
||||||
regexp: '/recaptcha/.*',
|
regexp: '/recaptcha/.*',
|
||||||
proxy: 'www.recaptcha.net'
|
proxy: 'www.recaptcha.net'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
'fonts.gstatic.com': [
|
'fonts.gstatic.com': [
|
||||||
{
|
{
|
||||||
proxy: 'fonts-gstatic.proxy.ustclug.org',
|
proxy: 'fonts-gstatic.proxy.ustclug.org',
|
||||||
backup: ['gstatic.loli.net']
|
backup: ['gstatic.loli.net']
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
'clients*.google.com': [{ abort: true }],
|
'clients*.google.com': [{ abort: true }],
|
||||||
'www.googleapis.com': [{ abort: true }],
|
'www.googleapis.com': [{ abort: true }],
|
||||||
'lh*.googleusercontent.com': [{ abort: true }],
|
'lh*.googleusercontent.com': [{ abort: true }],
|
||||||
// mapbox-node-binary.s3.amazonaws.com/sqlite3/v5.0.0/napi-v3-win32-x64.tar.gz
|
// mapbox-node-binary.s3.amazonaws.com/sqlite3/v5.0.0/napi-v3-win32-x64.tar.gz
|
||||||
'*.s3.amazonaws.com': [
|
'*.s3.amazonaws.com': [
|
||||||
{
|
{
|
||||||
regexp: '/sqlite3/.*',
|
regexp: '/sqlite3/.*',
|
||||||
redirect: 'npm.taobao.org/mirrors'
|
redirect: 'npm.taobao.org/mirrors'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
'registry-1.docker.io': [{ proxy: 'docker.mirrors.ustc.edu.cn' }],
|
'registry-1.docker.io': [{ proxy: 'docker.mirrors.ustc.edu.cn' }],
|
||||||
'packages.elastic.co': [{ proxy: 'elastic.proxy.ustclug.org' }],
|
'packages.elastic.co': [{ proxy: 'elastic.proxy.ustclug.org' }],
|
||||||
'ppa.launchpad.net': [{ proxy: 'launchpad.proxy.ustclug.org' }],
|
'ppa.launchpad.net': [{ proxy: 'launchpad.proxy.ustclug.org' }],
|
||||||
'archive.cloudera.com': [{ regexp: '/cdh5/.*', proxy: 'cloudera.proxy.ustclug.org' }],
|
'archive.cloudera.com': [{ regexp: '/cdh5/.*', proxy: 'cloudera.proxy.ustclug.org' }],
|
||||||
'downloads.lede-project.org': [{ proxy: 'lede.proxy.ustclug.org' }],
|
'downloads.lede-project.org': [{ proxy: 'lede.proxy.ustclug.org' }],
|
||||||
'downloads.openwrt.org': [{ proxy: 'openwrt.proxy.ustclug.org' }],
|
'downloads.openwrt.org': [{ proxy: 'openwrt.proxy.ustclug.org' }],
|
||||||
'secure.gravatar.com': [{ proxy: 'gravatar.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
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
mapping: {
|
dns: {
|
||||||
// "解决push的时候需要输入密码的问题",
|
providers: {
|
||||||
'api.github.com': 'usa',
|
aliyun: {
|
||||||
'gist.github.com': 'usa'
|
type: 'https',
|
||||||
// "avatars*.githubusercontent.com": "usa"
|
server: 'dns.alidns.com/dns-query',
|
||||||
}
|
cacheSize: 1000
|
||||||
},
|
},
|
||||||
variables: {
|
usa: {
|
||||||
npm: {
|
type: 'https',
|
||||||
SASS_BINARY_SITE: 'https://npm.taobao.org/mirrors/node-sass/',
|
server: 'cloudflare-dns.com/dns-query',
|
||||||
PHANTOMJS_CDNURL: 'https://npm.taobao.org/mirrors/phantomjs/',
|
cacheSize: 1000
|
||||||
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
|
|
||||||
},
|
},
|
||||||
variables: {
|
mapping: {
|
||||||
npm: true
|
// "解决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 status = require('./status')
|
||||||
const config = require('./config')
|
const config = require('./config')
|
||||||
const event = require('./event')
|
const event = require('./event')
|
||||||
const shell = require('./shell')
|
const shell = require('./shell')
|
||||||
async function proxyStartup ({ ip, port }) {
|
const modules = require('./modules')
|
||||||
for (const key in proxy) {
|
const proxyConfig = require('./lib/proxy/common/config')
|
||||||
if (config.get().setting.startup.proxy[key]) {
|
const lodash = require('lodash')
|
||||||
await proxy[key].open({ ip, port })
|
const context = {
|
||||||
}
|
config,
|
||||||
}
|
shell,
|
||||||
|
status,
|
||||||
|
event,
|
||||||
|
rootCaFile: proxyConfig.getDefaultCACertPath()
|
||||||
}
|
}
|
||||||
async function proxyShutdown () {
|
|
||||||
for (const key in proxy) {
|
function setupPlugin (key, plugin, context, config) {
|
||||||
if (status.proxy[key] === false) {
|
const pluginConfig = plugin.config
|
||||||
continue
|
const PluginClass = plugin.plugin
|
||||||
}
|
const pluginStatus = plugin.status
|
||||||
await proxy[key].close()
|
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 = {
|
module.exports = {
|
||||||
status,
|
status,
|
||||||
api: {
|
api: {
|
||||||
server,
|
|
||||||
proxy,
|
|
||||||
config,
|
|
||||||
startup: async (newConfig) => {
|
startup: async (newConfig) => {
|
||||||
if (newConfig) {
|
if (newConfig) {
|
||||||
config.set(newConfig)
|
config.set(newConfig)
|
||||||
}
|
}
|
||||||
try {
|
const conf = config.get()
|
||||||
const startup = config.get().setting.startup
|
if (conf.server.enabled) {
|
||||||
if (startup.server) {
|
try {
|
||||||
server.start(newConfig)
|
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 () => {
|
shutdown: async () => {
|
||||||
try {
|
try {
|
||||||
await proxyShutdown()
|
const plugins = []
|
||||||
return new Promise(resolve => {
|
for (const key in plugin) {
|
||||||
server.close()
|
if (status.plugin[key].enabled && plugin[key].close) {
|
||||||
resolve()
|
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) {
|
} catch (error) {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
status: {
|
||||||
|
get () {
|
||||||
|
return status
|
||||||
|
}
|
||||||
|
},
|
||||||
|
config,
|
||||||
event,
|
event,
|
||||||
shell
|
shell,
|
||||||
|
server,
|
||||||
|
proxy,
|
||||||
|
plugin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ module.exports = function createRequestHandler (requestInterceptor, responseInte
|
||||||
function onFree () {
|
function onFree () {
|
||||||
const url = `${rOptions.protocol}//${rOptions.hostname}:${rOptions.port}${rOptions.path}`
|
const url = `${rOptions.protocol}//${rOptions.hostname}:${rOptions.port}${rOptions.path}`
|
||||||
const start = new Date().getTime()
|
const start = new Date().getTime()
|
||||||
console.log('代理请求:', url)
|
console.log('代理请求:', url, rOptions.method)
|
||||||
|
|
||||||
proxyReq = (rOptions.protocol === 'https:' ? https : http).request(rOptions, (proxyRes) => {
|
proxyReq = (rOptions.protocol === 'https:' ? https : http).request(rOptions, (proxyRes) => {
|
||||||
const end = new Date().getTime()
|
const end = new Date().getTime()
|
||||||
|
@ -73,7 +73,7 @@ module.exports = function createRequestHandler (requestInterceptor, responseInte
|
||||||
})
|
})
|
||||||
|
|
||||||
proxyReq.on('timeout', () => {
|
proxyReq.on('timeout', () => {
|
||||||
console.error('代理请求超时', rOptions.hostname, rOptions.path)
|
console.error('代理请求超时', rOptions.protocol, rOptions.hostname, rOptions.path)
|
||||||
reject(new Error(`${rOptions.host}:${rOptions.port}, 代理请求超时`))
|
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 interceptors = require('../../lib/interceptor')
|
||||||
const logger = getLogger('proxy')
|
const dnsUtil = require('../../lib/dns')
|
||||||
const interceptors = require('../lib/interceptor')
|
const lodash = require('lodash')
|
||||||
const dnsUtil = require('../lib/dns')
|
|
||||||
function matchHostname (intercepts, hostname) {
|
function matchHostname (intercepts, hostname) {
|
||||||
const interceptOpts = intercepts[hostname]
|
const interceptOpts = intercepts[hostname]
|
||||||
if (interceptOpts) {
|
if (interceptOpts) {
|
||||||
return interceptOpts
|
return interceptOpts
|
||||||
}
|
}
|
||||||
if (!interceptOpts) { // 该域名没有配置拦截器,直接过
|
if (!interceptOpts) {
|
||||||
for (const target in intercepts) {
|
for (const target in intercepts) {
|
||||||
if (target.indexOf('*') < 0) {
|
if (target.indexOf('*') < 0) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// 正则表达式匹配
|
// 正则表达式匹配
|
||||||
const regexp = target.replace('.', '\\.').replace('*', '.*')
|
if (hostname.match(target)) {
|
||||||
if (hostname.match(regexp)) {
|
|
||||||
return intercepts[target]
|
return intercepts[target]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,19 +23,62 @@ function isMatched (url, regexp) {
|
||||||
return url.match(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) => {
|
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 {
|
return {
|
||||||
port: config.server.port,
|
port: serverConfig.port,
|
||||||
dnsConfig: {
|
dnsConfig: {
|
||||||
providers: dnsUtil.initDNS(config.dns.providers), mapping: config.dns.mapping
|
providers: dnsUtil.initDNS(serverConfig.dns.providers),
|
||||||
|
mapping: dnsMapping
|
||||||
},
|
},
|
||||||
sslConnectInterceptor: (req, cltSocket, head) => {
|
sslConnectInterceptor: (req, cltSocket, head) => {
|
||||||
const hostname = req.url.split(':')[0]
|
const hostname = req.url.split(':')[0]
|
||||||
return !!matchHostname(config.intercepts, hostname) // 配置了拦截的域名,将会被代理
|
return !!matchHostname(intercepts, hostname) // 配置了拦截的域名,将会被代理
|
||||||
},
|
},
|
||||||
requestInterceptor: (rOptions, req, res, ssl, next) => {
|
requestInterceptor: (rOptions, req, res, ssl, next) => {
|
||||||
const hostname = rOptions.hostname
|
const hostname = rOptions.hostname
|
||||||
const interceptOpts = matchHostname(config.intercepts, hostname)
|
const interceptOpts = matchHostname(intercepts, hostname)
|
||||||
if (!interceptOpts) { // 该域名没有配置拦截器,直接过
|
if (!interceptOpts) { // 该域名没有配置拦截器,直接过
|
||||||
next()
|
next()
|
||||||
return
|
return
|
||||||
|
@ -45,20 +86,18 @@ module.exports = (config) => {
|
||||||
|
|
||||||
for (const interceptOpt of interceptOpts) { // 遍历拦截配置
|
for (const interceptOpt of interceptOpts) { // 遍历拦截配置
|
||||||
let regexpList
|
let regexpList
|
||||||
if(interceptOpt.regexp!=null){
|
if (interceptOpt.regexp != null) {
|
||||||
if (interceptOpt.regexp instanceof Array) {
|
if (interceptOpt.regexp instanceof Array) {
|
||||||
regexpList = interceptOpt.regexp
|
regexpList = interceptOpt.regexp
|
||||||
} else {
|
} else {
|
||||||
regexpList = [interceptOpt.regexp]
|
regexpList = [interceptOpt.regexp]
|
||||||
}
|
}
|
||||||
}else{
|
} else {
|
||||||
regexpList = [true]
|
regexpList = [true]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for (const regexp of regexpList) { // 遍历regexp配置
|
for (const regexp of regexpList) { // 遍历regexp配置
|
||||||
if(regexp!==true){
|
if (regexp !== true) {
|
||||||
if (!isMatched(req.url, regexp)) {
|
if (!isMatched(req.url, regexp)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -75,7 +114,7 @@ module.exports = (config) => {
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} 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 killByPort = require('./scripts/kill-by-port')
|
||||||
const setupCa = require('./scripts/setup-ca')
|
const setupCa = require('./scripts/setup-ca')
|
||||||
const getSystemEnv = require('./scripts/get-system-env')
|
const getSystemEnv = require('./scripts/get-system-env')
|
||||||
|
@ -10,5 +11,8 @@ module.exports = {
|
||||||
getSystemEnv,
|
getSystemEnv,
|
||||||
setSystemEnv,
|
setSystemEnv,
|
||||||
getNpmEnv,
|
getNpmEnv,
|
||||||
setNpmEnv
|
setNpmEnv,
|
||||||
|
exec (cmds, args) {
|
||||||
|
shell.getSystemShell().exec(cmds, args)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,9 @@ const lodash = require('lodash')
|
||||||
const status = {
|
const status = {
|
||||||
server: false,
|
server: false,
|
||||||
proxy: {
|
proxy: {
|
||||||
system: false,
|
},
|
||||||
npm: false,
|
plugin: {
|
||||||
git: false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,4 +13,5 @@ event.register('status', (event) => {
|
||||||
lodash.set(status, event.key, event.value)
|
lodash.set(status, event.key, event.value)
|
||||||
console.log('status changed:', event)
|
console.log('status changed:', event)
|
||||||
}, -999)
|
}, -999)
|
||||||
|
|
||||||
module.exports = status
|
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')
|
const config = require('../../../lib/proxy/common/config')
|
||||||
class SystemProxy {
|
const Shell = require('../../../shell')
|
||||||
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()}`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
async setProxy (ip, port) {
|
async setProxy (ip, port) {
|
||||||
const systemProxy = getSystemProxy()
|
const cmds = [
|
||||||
await systemProxy.setProxy(ip, port)
|
`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 () {
|
async unsetProxy () {
|
||||||
const systemProxy = getSystemProxy()
|
const cmds = [
|
||||||
await systemProxy.unsetProxy()
|
'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 cmd = require('node-cmd')
|
||||||
const exec = util.promisify(_exec)
|
const exec = util.promisify(_exec)
|
||||||
const refreshInternetPs = require('./refresh-internet')
|
const refreshInternetPs = require('./refresh-internet')
|
||||||
const Shell = require('node-powershell')
|
const PowerShell = require('node-powershell')
|
||||||
|
|
||||||
const _lanIP = [
|
const _lanIP = [
|
||||||
'localhost',
|
'localhost',
|
||||||
'127.*',
|
'127.*',
|
||||||
|
@ -124,7 +123,7 @@ class WindowsSystemProxy extends SystemProxy {
|
||||||
|
|
||||||
static _resetWininetProxySettings (script) {
|
static _resetWininetProxySettings (script) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const ps = new Shell({
|
const ps = new PowerShell({
|
||||||
executionPolicy: 'Bypass',
|
executionPolicy: 'Bypass',
|
||||||
noProfile: true
|
noProfile: true
|
||||||
})
|
})
|
||||||
|
|
|
@ -1901,8 +1901,7 @@
|
||||||
"@types/json-schema": {
|
"@types/json-schema": {
|
||||||
"version": "7.0.6",
|
"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",
|
"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=",
|
"integrity": "sha1-9MfsQ+gbMZqYFRFQMXCfJph4kfA="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"@types/json5": {
|
"@types/json5": {
|
||||||
"version": "0.0.29",
|
"version": "0.0.29",
|
||||||
|
@ -2372,16 +2371,6 @@
|
||||||
"integrity": "sha1-/q7SVZc9LndVW4PbwIhRpsY1IPo=",
|
"integrity": "sha1-/q7SVZc9LndVW4PbwIhRpsY1IPo=",
|
||||||
"dev": true
|
"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": {
|
"cacache": {
|
||||||
"version": "13.0.1",
|
"version": "13.0.1",
|
||||||
"resolved": "https://registry.npm.taobao.org/cacache/download/cacache-13.0.1.tgz",
|
"resolved": "https://registry.npm.taobao.org/cacache/download/cacache-13.0.1.tgz",
|
||||||
|
@ -2408,34 +2397,6 @@
|
||||||
"unique-filename": "^1.1.1"
|
"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": {
|
"find-cache-dir": {
|
||||||
"version": "3.3.1",
|
"version": "3.3.1",
|
||||||
"resolved": "https://registry.npm.taobao.org/find-cache-dir/download/find-cache-dir-3.3.1.tgz",
|
"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"
|
"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": {
|
"locate-path": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npm.taobao.org/locate-path/download/locate-path-5.0.0.tgz",
|
"resolved": "https://registry.npm.taobao.org/locate-path/download/locate-path-5.0.0.tgz",
|
||||||
|
@ -2540,16 +2482,6 @@
|
||||||
"minipass": "^3.1.1"
|
"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": {
|
"terser-webpack-plugin": {
|
||||||
"version": "2.3.8",
|
"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",
|
"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",
|
"terser": "^4.6.12",
|
||||||
"webpack-sources": "^1.4.3"
|
"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",
|
"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",
|
"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=",
|
"integrity": "sha1-uvWmLoArB9l3A0WG+MO69a3ybfQ=",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"fast-deep-equal": "^3.1.1",
|
"fast-deep-equal": "^3.1.1",
|
||||||
"fast-json-stable-stringify": "^2.0.0",
|
"fast-json-stable-stringify": "^2.0.0",
|
||||||
|
@ -2953,8 +2872,7 @@
|
||||||
"ajv-keywords": {
|
"ajv-keywords": {
|
||||||
"version": "3.5.2",
|
"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",
|
"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=",
|
"integrity": "sha1-MfKdpatuANHC0yms97WSlhTVAU0="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"alphanum-sort": {
|
"alphanum-sort": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
|
@ -3101,7 +3019,6 @@
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npm.taobao.org/anymatch/download/anymatch-3.1.1.tgz",
|
"resolved": "https://registry.npm.taobao.org/anymatch/download/anymatch-3.1.1.tgz",
|
||||||
"integrity": "sha1-xV7PAhheJGklk5kxDBc84xIzsUI=",
|
"integrity": "sha1-xV7PAhheJGklk5kxDBc84xIzsUI=",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"normalize-path": "^3.0.0",
|
"normalize-path": "^3.0.0",
|
||||||
"picomatch": "^2.0.4"
|
"picomatch": "^2.0.4"
|
||||||
|
@ -4396,14 +4313,12 @@
|
||||||
"big.js": {
|
"big.js": {
|
||||||
"version": "5.2.2",
|
"version": "5.2.2",
|
||||||
"resolved": "https://registry.npm.taobao.org/big.js/download/big.js-5.2.2.tgz",
|
"resolved": "https://registry.npm.taobao.org/big.js/download/big.js-5.2.2.tgz",
|
||||||
"integrity": "sha1-ZfCvOC9Xi83HQr2cKB6cstd2gyg=",
|
"integrity": "sha1-ZfCvOC9Xi83HQr2cKB6cstd2gyg="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"binary-extensions": {
|
"binary-extensions": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npm.taobao.org/binary-extensions/download/binary-extensions-2.1.0.tgz",
|
"resolved": "https://registry.npm.taobao.org/binary-extensions/download/binary-extensions-2.1.0.tgz",
|
||||||
"integrity": "sha1-MPpAyef+B9vIlWeM0ocCTeokHdk=",
|
"integrity": "sha1-MPpAyef+B9vIlWeM0ocCTeokHdk="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"bindings": {
|
"bindings": {
|
||||||
"version": "1.5.0",
|
"version": "1.5.0",
|
||||||
|
@ -5229,7 +5144,6 @@
|
||||||
"version": "3.4.3",
|
"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",
|
"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=",
|
"integrity": "sha1-wd84IxRI5FykrFiObHlXO6alfVs=",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"anymatch": "~3.1.1",
|
"anymatch": "~3.1.1",
|
||||||
"braces": "~3.0.2",
|
"braces": "~3.0.2",
|
||||||
|
@ -5245,7 +5159,6 @@
|
||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
"resolved": "https://registry.npm.taobao.org/braces/download/braces-3.0.2.tgz",
|
"resolved": "https://registry.npm.taobao.org/braces/download/braces-3.0.2.tgz",
|
||||||
"integrity": "sha1-NFThpGLujVmeI23zNs2epPiv4Qc=",
|
"integrity": "sha1-NFThpGLujVmeI23zNs2epPiv4Qc=",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"fill-range": "^7.0.1"
|
"fill-range": "^7.0.1"
|
||||||
}
|
}
|
||||||
|
@ -5254,7 +5167,6 @@
|
||||||
"version": "7.0.1",
|
"version": "7.0.1",
|
||||||
"resolved": "https://registry.npm.taobao.org/fill-range/download/fill-range-7.0.1.tgz",
|
"resolved": "https://registry.npm.taobao.org/fill-range/download/fill-range-7.0.1.tgz",
|
||||||
"integrity": "sha1-GRmmp8df44ssfHflGYU12prN2kA=",
|
"integrity": "sha1-GRmmp8df44ssfHflGYU12prN2kA=",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"to-regex-range": "^5.0.1"
|
"to-regex-range": "^5.0.1"
|
||||||
}
|
}
|
||||||
|
@ -5262,14 +5174,12 @@
|
||||||
"is-number": {
|
"is-number": {
|
||||||
"version": "7.0.0",
|
"version": "7.0.0",
|
||||||
"resolved": "https://registry.npm.taobao.org/is-number/download/is-number-7.0.0.tgz",
|
"resolved": "https://registry.npm.taobao.org/is-number/download/is-number-7.0.0.tgz",
|
||||||
"integrity": "sha1-dTU0W4lnNNX4DE0GxQlVUnoU8Ss=",
|
"integrity": "sha1-dTU0W4lnNNX4DE0GxQlVUnoU8Ss="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"to-regex-range": {
|
"to-regex-range": {
|
||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npm.taobao.org/to-regex-range/download/to-regex-range-5.0.1.tgz",
|
"resolved": "https://registry.npm.taobao.org/to-regex-range/download/to-regex-range-5.0.1.tgz",
|
||||||
"integrity": "sha1-FkjESq58jZiKMmAY7XL1tN0DkuQ=",
|
"integrity": "sha1-FkjESq58jZiKMmAY7XL1tN0DkuQ=",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"is-number": "^7.0.0"
|
"is-number": "^7.0.0"
|
||||||
}
|
}
|
||||||
|
@ -7362,8 +7272,7 @@
|
||||||
"emojis-list": {
|
"emojis-list": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npm.taobao.org/emojis-list/download/emojis-list-3.0.0.tgz",
|
"resolved": "https://registry.npm.taobao.org/emojis-list/download/emojis-list-3.0.0.tgz",
|
||||||
"integrity": "sha1-VXBmIEatKeLpFucariYKvf9Pang=",
|
"integrity": "sha1-VXBmIEatKeLpFucariYKvf9Pang="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"encodeurl": {
|
"encodeurl": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
|
@ -8318,8 +8227,7 @@
|
||||||
"fast-deep-equal": {
|
"fast-deep-equal": {
|
||||||
"version": "3.1.3",
|
"version": "3.1.3",
|
||||||
"resolved": "https://registry.npm.taobao.org/fast-deep-equal/download/fast-deep-equal-3.1.3.tgz",
|
"resolved": "https://registry.npm.taobao.org/fast-deep-equal/download/fast-deep-equal-3.1.3.tgz",
|
||||||
"integrity": "sha1-On1WtVnWy8PrUSMlJE5hmmXGxSU=",
|
"integrity": "sha1-On1WtVnWy8PrUSMlJE5hmmXGxSU="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"fast-glob": {
|
"fast-glob": {
|
||||||
"version": "2.2.7",
|
"version": "2.2.7",
|
||||||
|
@ -8361,8 +8269,7 @@
|
||||||
"fast-json-stable-stringify": {
|
"fast-json-stable-stringify": {
|
||||||
"version": "2.1.0",
|
"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",
|
"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=",
|
"integrity": "sha1-h0v2nG9ATCtdmcSBNBOZ/VWJJjM="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"fast-levenshtein": {
|
"fast-levenshtein": {
|
||||||
"version": "2.0.6",
|
"version": "2.0.6",
|
||||||
|
@ -8780,7 +8687,6 @@
|
||||||
"version": "2.1.3",
|
"version": "2.1.3",
|
||||||
"resolved": "https://registry.npm.taobao.org/fsevents/download/fsevents-2.1.3.tgz",
|
"resolved": "https://registry.npm.taobao.org/fsevents/download/fsevents-2.1.3.tgz",
|
||||||
"integrity": "sha1-+3OHA66NL5/pAMM4Nt3r7ouX8j4=",
|
"integrity": "sha1-+3OHA66NL5/pAMM4Nt3r7ouX8j4=",
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"function-bind": {
|
"function-bind": {
|
||||||
|
@ -8848,7 +8754,6 @@
|
||||||
"version": "5.1.1",
|
"version": "5.1.1",
|
||||||
"resolved": "https://registry.npm.taobao.org/glob-parent/download/glob-parent-5.1.1.tgz",
|
"resolved": "https://registry.npm.taobao.org/glob-parent/download/glob-parent-5.1.1.tgz",
|
||||||
"integrity": "sha1-tsHvQXxOVmPqSY8cRa+saRa7wik=",
|
"integrity": "sha1-tsHvQXxOVmPqSY8cRa+saRa7wik=",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"is-glob": "^4.0.1"
|
"is-glob": "^4.0.1"
|
||||||
}
|
}
|
||||||
|
@ -9855,7 +9760,6 @@
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npm.taobao.org/is-binary-path/download/is-binary-path-2.1.0.tgz",
|
"resolved": "https://registry.npm.taobao.org/is-binary-path/download/is-binary-path-2.1.0.tgz",
|
||||||
"integrity": "sha1-6h9/O4DwZCNug0cPhsCcJU+0Wwk=",
|
"integrity": "sha1-6h9/O4DwZCNug0cPhsCcJU+0Wwk=",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"binary-extensions": "^2.0.0"
|
"binary-extensions": "^2.0.0"
|
||||||
}
|
}
|
||||||
|
@ -9964,8 +9868,7 @@
|
||||||
"is-extglob": {
|
"is-extglob": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npm.taobao.org/is-extglob/download/is-extglob-2.1.1.tgz",
|
"resolved": "https://registry.npm.taobao.org/is-extglob/download/is-extglob-2.1.1.tgz",
|
||||||
"integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
|
"integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"is-finite": {
|
"is-finite": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
|
@ -9993,7 +9896,6 @@
|
||||||
"version": "4.0.1",
|
"version": "4.0.1",
|
||||||
"resolved": "https://registry.npm.taobao.org/is-glob/download/is-glob-4.0.1.tgz",
|
"resolved": "https://registry.npm.taobao.org/is-glob/download/is-glob-4.0.1.tgz",
|
||||||
"integrity": "sha1-dWfb6fL14kZ7x3q4PEopSCQHpdw=",
|
"integrity": "sha1-dWfb6fL14kZ7x3q4PEopSCQHpdw=",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"is-extglob": "^2.1.1"
|
"is-extglob": "^2.1.1"
|
||||||
}
|
}
|
||||||
|
@ -10369,8 +10271,7 @@
|
||||||
"json-schema-traverse": {
|
"json-schema-traverse": {
|
||||||
"version": "0.4.1",
|
"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",
|
"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=",
|
"integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"json-stable-stringify-without-jsonify": {
|
"json-stable-stringify-without-jsonify": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
|
@ -10510,6 +10411,11 @@
|
||||||
"graceful-fs": "^4.1.9"
|
"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": {
|
"latest-version": {
|
||||||
"version": "5.1.0",
|
"version": "5.1.0",
|
||||||
"resolved": "https://registry.npm.taobao.org/latest-version/download/latest-version-5.1.0.tgz",
|
"resolved": "https://registry.npm.taobao.org/latest-version/download/latest-version-5.1.0.tgz",
|
||||||
|
@ -11305,8 +11211,7 @@
|
||||||
"neo-async": {
|
"neo-async": {
|
||||||
"version": "2.6.2",
|
"version": "2.6.2",
|
||||||
"resolved": "https://registry.npm.taobao.org/neo-async/download/neo-async-2.6.2.tgz",
|
"resolved": "https://registry.npm.taobao.org/neo-async/download/neo-async-2.6.2.tgz",
|
||||||
"integrity": "sha1-tKr7k+OustgXTKU88WOrfXMIMF8=",
|
"integrity": "sha1-tKr7k+OustgXTKU88WOrfXMIMF8="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"nice-try": {
|
"nice-try": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
|
@ -11465,8 +11370,7 @@
|
||||||
"normalize-path": {
|
"normalize-path": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npm.taobao.org/normalize-path/download/normalize-path-3.0.0.tgz",
|
"resolved": "https://registry.npm.taobao.org/normalize-path/download/normalize-path-3.0.0.tgz",
|
||||||
"integrity": "sha1-Dc1p/yOhybEf0JeDFmRKA4ghamU=",
|
"integrity": "sha1-Dc1p/yOhybEf0JeDFmRKA4ghamU="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"normalize-range": {
|
"normalize-range": {
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
|
@ -12223,8 +12127,7 @@
|
||||||
"picomatch": {
|
"picomatch": {
|
||||||
"version": "2.2.2",
|
"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",
|
"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=",
|
"integrity": "sha1-IfMz6ba46v8CRo9RRupAbTRfTa0="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"pify": {
|
"pify": {
|
||||||
"version": "4.0.1",
|
"version": "4.0.1",
|
||||||
|
@ -13054,8 +12957,7 @@
|
||||||
"punycode": {
|
"punycode": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npm.taobao.org/punycode/download/punycode-2.1.1.tgz",
|
"resolved": "https://registry.npm.taobao.org/punycode/download/punycode-2.1.1.tgz",
|
||||||
"integrity": "sha1-tYsBCsQMIsVldhbI0sLALHv0eew=",
|
"integrity": "sha1-tYsBCsQMIsVldhbI0sLALHv0eew="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"pupa": {
|
"pupa": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
|
@ -13300,7 +13202,6 @@
|
||||||
"version": "3.5.0",
|
"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",
|
"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=",
|
"integrity": "sha1-m6dMAZsV02UnjS6Ru4xI17TULJ4=",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"picomatch": "^2.2.1"
|
"picomatch": "^2.2.1"
|
||||||
}
|
}
|
||||||
|
@ -13761,6 +13662,53 @@
|
||||||
"truncate-utf8-bytes": "^1.0.0"
|
"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": {
|
"sax": {
|
||||||
"version": "1.2.4",
|
"version": "1.2.4",
|
||||||
"resolved": "https://registry.npm.taobao.org/sax/download/sax-1.2.4.tgz",
|
"resolved": "https://registry.npm.taobao.org/sax/download/sax-1.2.4.tgz",
|
||||||
|
@ -15725,7 +15673,6 @@
|
||||||
"version": "4.4.0",
|
"version": "4.4.0",
|
||||||
"resolved": "https://registry.npm.taobao.org/uri-js/download/uri-js-4.4.0.tgz",
|
"resolved": "https://registry.npm.taobao.org/uri-js/download/uri-js-4.4.0.tgz",
|
||||||
"integrity": "sha1-qnFCYd55PoqCNHp7zJznTobyhgI=",
|
"integrity": "sha1-qnFCYd55PoqCNHp7zJznTobyhgI=",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"punycode": "^2.1.0"
|
"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": {
|
"vue-ref": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npm.taobao.org/vue-ref/download/vue-ref-2.0.0.tgz",
|
"resolved": "https://registry.npm.taobao.org/vue-ref/download/vue-ref-2.0.0.tgz",
|
||||||
"integrity": "sha1-SDCE1zKr7RHaeWd4qCZqOvDqGpw="
|
"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": {
|
"vue-style-loader": {
|
||||||
"version": "4.1.2",
|
"version": "4.1.2",
|
||||||
"resolved": "https://registry.npm.taobao.org/vue-style-loader/download/vue-style-loader-4.1.2.tgz",
|
"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",
|
"es-abstract": "^1.17.7",
|
||||||
"json5": "^2.1.3",
|
"json5": "^2.1.3",
|
||||||
"lodash": "^4.17.20",
|
"lodash": "^4.17.20",
|
||||||
|
"sass": "^1.27.1",
|
||||||
|
"sass-loader": "^10.0.4",
|
||||||
"vue": "^2.6.11",
|
"vue": "^2.6.11",
|
||||||
"vue-json-editor": "^1.4.2"
|
"vue-json-editor": "^1.4.2",
|
||||||
|
"vue-router": "^3.4.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vue/cli-plugin-babel": "~4.5.0",
|
"@vue/cli-plugin-babel": "~4.5.0",
|
||||||
|
|
|
@ -58,7 +58,7 @@ function setTray (app) {
|
||||||
function createWindow () {
|
function createWindow () {
|
||||||
// Create the browser window.
|
// Create the browser window.
|
||||||
win = new BrowserWindow({
|
win = new BrowserWindow({
|
||||||
width: 800,
|
width: 900,
|
||||||
height: 700,
|
height: 700,
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
enableRemoteModule: true,
|
enableRemoteModule: true,
|
||||||
|
|
|
@ -132,6 +132,7 @@ export default {
|
||||||
|
|
||||||
// 合并用户配置
|
// 合并用户配置
|
||||||
localApi.config.reload()
|
localApi.config.reload()
|
||||||
|
DevSidecar.api.startup()
|
||||||
},
|
},
|
||||||
devSidecar: DevSidecar
|
devSidecar: DevSidecar
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,37 @@
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import App from './view/components/App.vue'
|
import App from './view/App.vue'
|
||||||
import antd from 'ant-design-vue'
|
import antd from 'ant-design-vue'
|
||||||
import 'ant-design-vue/dist/antd.css'
|
import 'ant-design-vue/dist/antd.css'
|
||||||
import view from './view'
|
import view from './view'
|
||||||
import { apiInit } from './view/api'
|
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.config.productionTip = false
|
||||||
Vue.use(antd)
|
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({
|
const app = new Vue({
|
||||||
|
router,
|
||||||
render: h => h(App)
|
render: h => h(App)
|
||||||
}).$mount('#app')
|
}).$mount('#app')
|
||||||
|
|
||||||
view.register(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) {
|
for (const item of list) {
|
||||||
bindApi(item)
|
bindApi(item)
|
||||||
}
|
}
|
||||||
|
console.log('api inited:', apiObj)
|
||||||
return 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) => {
|
api.on('error.core', (event, message) => {
|
||||||
console.error('view on error', message)
|
console.error('view on error', message)
|
||||||
const key = message.key
|
const key = message.key
|
||||||
if (key === 'server.start') {
|
if (key === 'server') {
|
||||||
handleServerStartError(message.error, app)
|
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