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