refactor: 自动更新
parent
161411f9c6
commit
f0552d5cce
44
README.md
44
README.md
|
@ -9,13 +9,22 @@
|
|||
### 1、 github的release、source、zip下载加速
|
||||
可解决npm install 时某些安装包下载不下来的问题
|
||||
|
||||
### 2、 解决git push某些情况下需要临时输入账号密码的问题
|
||||
通过将api.github.com域名解析到美国服务器
|
||||
### 2、 dns优选
|
||||
根据网络状况智能解析域名ip地址,获取最佳网络速度
|
||||
比如:
|
||||
1. 解决git push 偶尔失败需要输入账号密码的问题
|
||||
2. 解决github头像加载不出来的问题
|
||||
3. 解决gist.github.com访问不到的问题
|
||||
|
||||
### 3、 github的源代码查看(raw/blame查看)
|
||||
通过跳转到国内加速链接上
|
||||
|
||||
### 4、 Stack Overflow 加速
|
||||
将ajax.google.com代理到加速代理上 ,recaptcha 加速
|
||||
|
||||
将ajax.google.com代理到加速CDN上
|
||||
recaptcha 图片验证码加速
|
||||
|
||||
|
||||
### 5、 google cdn 加速
|
||||
通过代理到加速链接上
|
||||
|
||||
|
@ -90,10 +99,16 @@ sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keyc
|
|||
1. yarn 设置淘宝镜像registry
|
||||
2. npm设置官方registry。
|
||||
3. 项目install使用yarn,发布包publish用npm,互不影响
|
||||
|
||||
4. 某些库用cnpm也下载不下来的话,可以试试打开dev-sidecar的npm加速
|
||||
### 其他加速
|
||||
1. git clone 加速 [fgit-go](https://github.com/FastGitORG/fgit-go)
|
||||
2. github.com代理网站(不能登录) [hub.fastgit.org](https://hub.fastgit.org/)
|
||||
1. git clone 加速
|
||||
> 使用方式用实际的名称替换{}的内容,即可加速clone
|
||||
> https://hub.fastgit.org/{username}/{reponame}.git
|
||||
> clone 出来的 remote "origin" 为fastgit的地址,需要手动改回来
|
||||
> 你也可以直接使用他们的clone加速工具 [fgit-go](https://github.com/FastGitORG/fgit-go)
|
||||
2. github.com的镜像网站(注意:不能登录)
|
||||
>1. [hub.fastgit.org](https://hub.fastgit.org/)
|
||||
>2. [github.com.cnpmjs.org](https://github.com.cnpmjs.org/) 这个很容易超限
|
||||
|
||||
|
||||
## api
|
||||
|
@ -128,21 +143,28 @@ const intercepts = {
|
|||
}
|
||||
```
|
||||
|
||||
### DNS配置
|
||||
### DNS优选
|
||||
某些域名(比如api.github.com)会被解析到新加坡的ip上,新加坡的服务器在上午挺好,到了晚上就卡死,基本不可用。
|
||||
所以将这些域名解析到美国服务器上就可以正常访问
|
||||
|
||||
另外,配置了dns mapping的域名,将会从dns获取到的ip列表中选择相对快一点的服务器进行访问
|
||||
|
||||
```js
|
||||
dns: {
|
||||
mapping: {
|
||||
// "解决push的时候需要输入密码的问题",
|
||||
'api.github.com': 'usa', //配置该域名,使用USA的域名解析服务器
|
||||
'gist.github.com': 'usa'
|
||||
// "avatars*.githubusercontent.com": "usa"
|
||||
//
|
||||
'api.github.com': 'usa', // "解决push的时候需要输入密码的问题",
|
||||
'gist.github.com': 'usa' // 解决gist无法访问的问题
|
||||
"*.githubusercontent.com": "usa" // 解决github头像经常下载不到的问题
|
||||
}
|
||||
},
|
||||
```
|
||||
注意:暂时只支持IPv4的解析
|
||||
#### 开启前vs 开启后
|
||||

|
||||

|
||||
|
||||
|
||||
|
||||
## 感谢
|
||||
本项目使用lerna包管理工具
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
Binary file not shown.
After Width: | Height: | Size: 4.5 KiB |
|
@ -1,31 +1,21 @@
|
|||
{
|
||||
"name": "@docmirror/dev-sidecar",
|
||||
"version": "1.0.1",
|
||||
"description": "",
|
||||
"description": "给开发者的加速代理工具",
|
||||
"main": "src/index.js",
|
||||
"depedencies": {},
|
||||
"keywords": [],
|
||||
"keywords": ["dev-sidecar","github加速","google加速","代理"],
|
||||
"author": "docmirror.cn",
|
||||
"license": "MPL-2.0",
|
||||
"private": false,
|
||||
"scripts": {
|
||||
"start": "node ./start",
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"lint": "vue-cli-service lint"
|
||||
"start": "node ./start"
|
||||
},
|
||||
"dependencies": {
|
||||
"agentkeepalive": "^2.1.1",
|
||||
"babel-core": "^6.8.0",
|
||||
"babel-plugin-transform-async-to-generator": "^6.7.4",
|
||||
"babel-polyfill": "^6.8.0",
|
||||
"babel-preset-es2015": "^6.6.0",
|
||||
"babel-register": "^6.8.0",
|
||||
"charset": "^1.0.0",
|
||||
"child_process": "^1.0.2",
|
||||
"colors": "^1.1.2",
|
||||
"commander": "^2.9.0",
|
||||
"core-js": "^3.6.5",
|
||||
"debug": "^4.1.1",
|
||||
"dns-over-http": "^0.2.0",
|
||||
"dns-over-tls": "^0.0.8",
|
||||
|
@ -38,22 +28,17 @@
|
|||
"mkdirp": "^0.5.1",
|
||||
"node-cmd": "^3.0.0",
|
||||
"node-forge": "^0.8.2",
|
||||
"node-mitmproxy": "^3.1.1",
|
||||
"node-powershell": "^4.0.0",
|
||||
"require-context": "^1.1.0",
|
||||
"ssl-root-cas": "^1.3.1",
|
||||
"through2": "^2.0.1",
|
||||
"tunnel-agent": "^0.4.3",
|
||||
"util": "^0.12.3",
|
||||
"validator": "^13.1.17",
|
||||
"vue": "^2.6.11",
|
||||
"winreg": "^1.2.4",
|
||||
"@docmirror/mitmproxy": "1.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "~4.5.0",
|
||||
"@vue/cli-plugin-eslint": "~4.5.0",
|
||||
"@vue/cli-service": "~4.5.0",
|
||||
"@vue/eslint-config-standard": "^5.1.2",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"eslint": "^6.7.2",
|
||||
|
@ -61,8 +46,7 @@
|
|||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"eslint-plugin-standard": "^4.0.0",
|
||||
"eslint-plugin-vue": "^6.2.2",
|
||||
"vue-template-compiler": "^2.6.11"
|
||||
"eslint-plugin-vue": "^6.2.2"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"root": true,
|
||||
|
|
|
@ -23,7 +23,7 @@ module.exports = {
|
|||
'raw.githubusercontent.com': {
|
||||
'.*': { proxy: 'raw.fastgit.org' }
|
||||
},
|
||||
'github.githubassets.com': {
|
||||
'github11.githubassets.com': {
|
||||
'.*': { proxy: 'assets.fastgit.org', test: 'https://github.githubassets.com/favicons/favicon.svg' }
|
||||
},
|
||||
'customer-stories-feed.github.com': {
|
||||
|
@ -100,10 +100,11 @@ module.exports = {
|
|||
}
|
||||
},
|
||||
mapping: {
|
||||
'*.github.com': 'usa',
|
||||
'*.githubusercontent.com': 'usa',
|
||||
'*.githubassets.com': 'usa',
|
||||
// "解决push的时候需要输入密码的问题",
|
||||
'api.github.com': 'usa',
|
||||
'gist.github.com': 'usa'
|
||||
// "avatars*.githubusercontent.com": "usa"
|
||||
'github.com': 'usa'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -8,9 +8,6 @@
|
|||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
</head>
|
||||
<body style="height:100%">
|
||||
<noscript>
|
||||
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
<div id="app" style="height:100%">
|
||||
<div style="display: flex;align-items: center;justify-content: center;height:100%;width:100%"><img src="loading-spin.svg"></div>
|
||||
</div>
|
||||
|
|
|
@ -75,6 +75,7 @@ function createWindow () {
|
|||
win = new BrowserWindow({
|
||||
width: 900,
|
||||
height: 700,
|
||||
title: 'Dev-Sidecar',
|
||||
webPreferences: {
|
||||
enableRemoteModule: true,
|
||||
// preload: path.join(__dirname, 'preload.js'),
|
||||
|
@ -167,7 +168,17 @@ if (!isFirstInstance) {
|
|||
}
|
||||
createWindow()
|
||||
bridge.init(win)
|
||||
updateHandle(win, 'http://localhost/dev-sidecar/')
|
||||
|
||||
let updateUrl = 'https://dev-sidecar.docmirror.cn/update/'
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
Object.defineProperty(app, 'isPackaged', {
|
||||
get () {
|
||||
return true
|
||||
}
|
||||
})
|
||||
updateUrl = 'http://localhost/dev-sidecar/'
|
||||
}
|
||||
updateHandle(win, updateUrl)
|
||||
try {
|
||||
// 最小化到托盘
|
||||
tray = setTray(app)
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
import lodash from 'lodash'
|
||||
import DevSidecar from '@docmirror/dev-sidecar'
|
||||
import { ipcMain } from 'electron'
|
||||
import { ipcMain, Menu } from 'electron'
|
||||
import fs from 'fs'
|
||||
import JSON5 from 'json5'
|
||||
import path from 'path'
|
||||
const mitmproxyPath = path.join(__dirname, 'mitmproxy.js')
|
||||
const localApi = {
|
||||
/**
|
||||
* 返回所有api列表,供vue来ipc调用
|
||||
* @returns {[]}
|
||||
*/
|
||||
getApiList () {
|
||||
const core = lodash.cloneDeep(DevSidecar.api)
|
||||
const local = lodash.cloneDeep(localApi)
|
||||
|
@ -15,13 +19,40 @@ const localApi = {
|
|||
// console.log('api list:', list)
|
||||
return list
|
||||
},
|
||||
/**
|
||||
* 软件设置
|
||||
*/
|
||||
setting: {
|
||||
load () {
|
||||
const settingPath = _getSettingPath()
|
||||
const file = fs.readFileSync(settingPath)
|
||||
const settings = JSON5.parse(file.toString())
|
||||
return settings || {}
|
||||
},
|
||||
save (settings = {}) {
|
||||
const settingPath = _getSettingPath()
|
||||
fs.writeFileSync(settingPath, JSON5.stringify(settings, null, 2))
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 启动所有
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
startup () {
|
||||
return DevSidecar.api.startup({ mitmproxyPath })
|
||||
},
|
||||
server: {
|
||||
/**
|
||||
* 启动代理服务
|
||||
* @returns {Promise<{port: *}>}
|
||||
*/
|
||||
start () {
|
||||
return DevSidecar.api.server.start({ mitmproxyPath })
|
||||
},
|
||||
/**
|
||||
* 重启代理服务
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
restart () {
|
||||
return DevSidecar.api.server.restart({ mitmproxyPath })
|
||||
}
|
||||
|
@ -35,15 +66,13 @@ const localApi = {
|
|||
// 对比默认config的异同
|
||||
const defConfig = DevSidecar.api.config.getDefault()
|
||||
const saveConfig = doMerge(defConfig, newConfig)
|
||||
|
||||
// _merge(defConfig, newConfig, saveConfig, 'intercepts')
|
||||
// _merge(defConfig, newConfig, saveConfig, 'dns.mapping')
|
||||
// _merge(defConfig, newConfig, saveConfig, 'setting.startup.server', true)
|
||||
// _merge(defConfig, newConfig, saveConfig, 'setting.startup.proxy')
|
||||
|
||||
fs.writeFileSync(_getConfigPath(), JSON5.stringify(saveConfig, null, 2))
|
||||
return saveConfig
|
||||
},
|
||||
/**
|
||||
* 读取后合并配置
|
||||
* @returns {*}
|
||||
*/
|
||||
reload () {
|
||||
const path = _getConfigPath()
|
||||
if (!fs.existsSync(path)) {
|
||||
|
@ -53,7 +82,7 @@ const localApi = {
|
|||
const userConfig = JSON5.parse(file.toString())
|
||||
DevSidecar.api.config.set(userConfig)
|
||||
const config = DevSidecar.api.config.get()
|
||||
return config
|
||||
return config || {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -69,6 +98,13 @@ function _deepFindFunction (list, parent, parentKey) {
|
|||
}
|
||||
}
|
||||
|
||||
function _getSettingPath () {
|
||||
const dir = './config/'
|
||||
if (!fs.existsSync(dir)) {
|
||||
fs.mkdirSync(dir)
|
||||
}
|
||||
return dir + 'setting.json5'
|
||||
}
|
||||
function _getConfigPath () {
|
||||
const dir = './config/'
|
||||
if (!fs.existsSync(dir)) {
|
||||
|
@ -147,6 +183,7 @@ export default {
|
|||
|
||||
// 合并用户配置
|
||||
localApi.config.reload()
|
||||
// 启动所有
|
||||
localApi.startup()
|
||||
},
|
||||
devSidecar: DevSidecar
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { ipcMain } from 'electron'
|
||||
import { ipcMain, dialog } from 'electron'
|
||||
import { autoUpdater } from 'electron-updater'
|
||||
|
||||
import path from 'path'
|
||||
// win是所有窗口的引用
|
||||
// const path = require('path') // 引入path模块
|
||||
// const fs = require('fs-extra')
|
||||
|
@ -14,61 +14,77 @@ function updateHandle (win, updateUrl) {
|
|||
// fs.emptyDir(updatePendingPath)
|
||||
// // 更新前,删除本地安装包 ↑
|
||||
const message = {
|
||||
error: 'update error',
|
||||
checking: 'updating...',
|
||||
updateAva: 'fetch new version and downloading...',
|
||||
updateNotAva: 'do not to update'
|
||||
error: '更新失败',
|
||||
checking: '检查更新中',
|
||||
updateAva: '发现新版本',
|
||||
updateNotAva: '当前为最新版本,无需更新'
|
||||
}
|
||||
// 本地开发环境,改变app-update.yml地址
|
||||
// if (process.env.NODE_ENV === 'development' && !isMac) {
|
||||
// autoUpdater.updateConfigPath = path.join(__dirname, 'win-unpacked/resources/app-update.yml')
|
||||
// }
|
||||
if (process.env.NODE_ENV === 'development' && !isMac) {
|
||||
autoUpdater.updateConfigPath = path.join(__dirname, 'win-unpacked/resources/app-update.yml')
|
||||
}
|
||||
autoUpdater.autoDownload = false
|
||||
|
||||
// 设置服务器更新地址
|
||||
autoUpdater.setFeedURL({
|
||||
provider: 'generic',
|
||||
url: updateUrl
|
||||
})
|
||||
autoUpdater.on('error', function (err) {
|
||||
console.log('autoUpdater error', err)
|
||||
sendUpdateMessage(message.error)
|
||||
autoUpdater.on('error', function (error) {
|
||||
console.log('autoUpdater error', error)
|
||||
sendUpdateMessage({ key: 'error', value: error, error: error })
|
||||
// dialog.showErrorBox('Error: ', error == null ? 'unknown' : (error.stack || error).toString())
|
||||
})
|
||||
autoUpdater.on('checking-for-update', function () {
|
||||
console.log('autoUpdater checking-for-update')
|
||||
sendUpdateMessage(message.checking)
|
||||
sendUpdateMessage({ key: 'checking', value: message.checking })
|
||||
})
|
||||
// 准备更新,打开进度条读取页面,关闭其他页面
|
||||
autoUpdater.on('update-available', function (info) {
|
||||
console.log('autoUpdater update-available')
|
||||
sendUpdateMessage(message.updateAva)
|
||||
sendUpdateMessage({ key: 'available', value: info })
|
||||
})
|
||||
autoUpdater.on('update-not-available', function (info) {
|
||||
console.log('autoUpdater update-not-available')
|
||||
sendUpdateMessage(message.updateNotAva)
|
||||
sendUpdateMessage({ key: 'notAvailable', value: message.updateNotAva })
|
||||
})
|
||||
// 更新下载进度
|
||||
autoUpdater.on('download-progress', function (progressObj) {
|
||||
console.log('autoUpdater download-progress')
|
||||
win.webContents.send('download-progress', parseInt(progressObj.percent))
|
||||
win.webContents.send('update', { key: 'progress', value: parseInt(progressObj.percent) })
|
||||
})
|
||||
// 更新完成,重启应用
|
||||
autoUpdater.on('update-downloaded', function (event, releaseNotes, releaseName, releaseDate, updateUrl, quitAndUpdate) {
|
||||
ipcMain.on('isUpdateNow', (e, arg) => {
|
||||
// some code here to handle event
|
||||
autoUpdater.quitAndInstall()
|
||||
autoUpdater.on('update-downloaded', function (info) {
|
||||
console.log('download complete', info.version)
|
||||
win.webContents.send('update', {
|
||||
key: 'downloaded',
|
||||
value: {
|
||||
version: info.version,
|
||||
releaseData: info.releaseDate
|
||||
}
|
||||
})
|
||||
win.webContents.send('isUpdateNow')
|
||||
})
|
||||
ipcMain.on('checkForUpdate', () => {
|
||||
// 执行自动更新检查
|
||||
console.log('autoUpdater checkForUpdates')
|
||||
autoUpdater.checkForUpdates()
|
||||
|
||||
ipcMain.on('update', (e, arg) => {
|
||||
if (arg.key === 'doUpdateNow') {
|
||||
// some code here to handle event
|
||||
autoUpdater.quitAndInstall(true, true)
|
||||
} else if (arg.key === 'checkForUpdate') {
|
||||
// 执行自动更新检查
|
||||
console.log('autoUpdater checkForUpdates')
|
||||
autoUpdater.checkForUpdates()
|
||||
} else if (arg.key === 'downloadUpdate') {
|
||||
// 下载新版本
|
||||
console.log('autoUpdater downloadUpdate')
|
||||
autoUpdater.downloadUpdate()
|
||||
}
|
||||
})
|
||||
// 通过main进程发送事件给renderer进程,提示更新信息
|
||||
function sendUpdateMessage (text) {
|
||||
function sendUpdateMessage (message) {
|
||||
console.log('autoUpdater sendUpdateMessage')
|
||||
win.webContents.send('message', text)
|
||||
win.webContents.send('update', message)
|
||||
}
|
||||
|
||||
console.log('auto update inited')
|
||||
return autoUpdater
|
||||
}
|
||||
export default updateHandle
|
||||
|
|
|
@ -3,7 +3,6 @@ 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'
|
||||
|
@ -17,16 +16,17 @@ Vue.component(DsContainer)
|
|||
const router = new VueRouter({
|
||||
routes // (缩写) 相当于 routes: routes
|
||||
})
|
||||
|
||||
apiInit().then((api) => {
|
||||
Vue.prototype.$global = {}
|
||||
view.initApi().then(async (api) => {
|
||||
Vue.prototype.$api = api
|
||||
|
||||
// 初始化status
|
||||
await view.initPre(api)
|
||||
const app = new Vue({
|
||||
router,
|
||||
render: h => h(App)
|
||||
}).$mount('#app')
|
||||
|
||||
view.init(app)
|
||||
view.initModules(app)
|
||||
})
|
||||
|
||||
// fix vue-router NavigationDuplicated
|
||||
|
|
|
@ -1,27 +1,32 @@
|
|||
import lodash from 'lodash'
|
||||
import { ipcRenderer } from 'electron'
|
||||
const doInvoke = (api, args) => {
|
||||
const invoke = (api, args) => {
|
||||
return ipcRenderer.invoke('apiInvoke', [api, args]).catch(err => {
|
||||
console.error('api invoke error:', err)
|
||||
})
|
||||
}
|
||||
const send = (channel, message) => {
|
||||
console.log('do send,', channel, message)
|
||||
return ipcRenderer.send(channel, message)
|
||||
}
|
||||
|
||||
const bindApi = (api, param1) => {
|
||||
lodash.set(apiObj, api, (param2) => {
|
||||
return doInvoke(api, param2 || param1)
|
||||
return invoke(api, param2 || param1)
|
||||
})
|
||||
}
|
||||
const apiObj = {
|
||||
on (channel, callback) {
|
||||
ipcRenderer.on(channel, callback)
|
||||
},
|
||||
doInvoke
|
||||
invoke,
|
||||
send
|
||||
}
|
||||
let inited = false
|
||||
|
||||
export function apiInit () {
|
||||
if (!inited) {
|
||||
return doInvoke('getApiList').then(list => {
|
||||
return invoke('getApiList').then(list => {
|
||||
inited = true
|
||||
for (const item of list) {
|
||||
bindApi(item)
|
||||
|
@ -30,7 +35,6 @@ export function apiInit () {
|
|||
return apiObj
|
||||
})
|
||||
}
|
||||
ipcRenderer.send('checkForUpdate')
|
||||
|
||||
return new Promise(resolve => {
|
||||
resolve(apiObj)
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
import './status'
|
||||
import register from './event'
|
||||
import api, { apiInit } from './api'
|
||||
import modules from './modules'
|
||||
import status from './status'
|
||||
export default {
|
||||
init (app) {
|
||||
register(app)
|
||||
initApi: apiInit,
|
||||
async initPre (api) {
|
||||
await status.install(api)
|
||||
},
|
||||
initModules (app) {
|
||||
modules.install(app, api)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import DsContainer from '../components/container'
|
||||
import status from '../status'
|
||||
import lodash from 'lodash'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
DsContainer
|
||||
|
@ -8,7 +8,7 @@ export default {
|
|||
data () {
|
||||
return {
|
||||
config: undefined,
|
||||
status: status,
|
||||
status: {},
|
||||
labelCol: { span: 4 },
|
||||
wrapperCol: { span: 20 },
|
||||
applyLoading: false
|
||||
|
@ -20,8 +20,15 @@ export default {
|
|||
mounted () {
|
||||
},
|
||||
methods: {
|
||||
getKey () {
|
||||
if (this.key) {
|
||||
return this.key
|
||||
}
|
||||
throw new Error('请设置key')
|
||||
},
|
||||
init () {
|
||||
this.$api.config.reload().then(ret => {
|
||||
this.status = this.$status
|
||||
return this.$api.config.reload().then(ret => {
|
||||
this.config = ret
|
||||
if (this.ready) {
|
||||
return this.ready(this.config)
|
||||
|
@ -40,11 +47,21 @@ export default {
|
|||
async applyBefore () {
|
||||
|
||||
},
|
||||
reloadDefault (key) {
|
||||
this.$api.config.resetDefault(key).then(ret => {
|
||||
this.config = ret
|
||||
}).then(() => {
|
||||
this.apply()
|
||||
resetDefault () {
|
||||
const key = this.getKey()
|
||||
this.$confirm({
|
||||
title: '提示',
|
||||
content: '确定要恢复默认设置吗?',
|
||||
cancelText: '取消',
|
||||
okText: '确定',
|
||||
onOk: async () => {
|
||||
this.config = await this.$api.config.resetDefault(key)
|
||||
if (this.ready) {
|
||||
await this.ready(this.config)
|
||||
}
|
||||
await this.apply()
|
||||
},
|
||||
onCancel () {}
|
||||
})
|
||||
},
|
||||
saveConfig () {
|
||||
|
|
|
@ -1,19 +1,9 @@
|
|||
import api from './api'
|
||||
import status from './status'
|
||||
import lodash from 'lodash'
|
||||
function register (app) {
|
||||
api.on('status', (event, message) => {
|
||||
console.log('view on status', event, message)
|
||||
const value = message.value
|
||||
const key = message.key
|
||||
lodash.set(status, key, value)
|
||||
})
|
||||
|
||||
function install (app, api) {
|
||||
api.on('error.core', (event, message) => {
|
||||
console.error('view on error', message)
|
||||
const key = message.key
|
||||
if (key === 'server') {
|
||||
handleServerStartError(message, message.error, app)
|
||||
handleServerStartError(message, message.error, app, api)
|
||||
}
|
||||
})
|
||||
api.on('error', (event, message) => {
|
||||
|
@ -21,7 +11,7 @@ function register (app) {
|
|||
})
|
||||
}
|
||||
|
||||
function handleServerStartError (message, err, app) {
|
||||
function handleServerStartError (message, err, app, api) {
|
||||
if (message.value === 'EADDRINUSE') {
|
||||
app.$confirm({
|
||||
title: '端口被占用,代理服务启动失败',
|
||||
|
@ -42,4 +32,6 @@ function handleServerStartError (message, err, app) {
|
|||
}
|
||||
}
|
||||
|
||||
export default register
|
||||
export default {
|
||||
install
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
import update from './update'
|
||||
import error from './error'
|
||||
|
||||
export default {
|
||||
install (app, api) {
|
||||
error.install(app, api)
|
||||
update.install(app, api)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
let updateParams = { }
|
||||
function install (app, api) {
|
||||
api.on('update', (event, message) => {
|
||||
console.log('on message', event, message)
|
||||
handleUpdateMessage(message, app)
|
||||
})
|
||||
|
||||
api.update = {
|
||||
checkForUpdate (params) {
|
||||
updateParams = params || { fromUser: false, autoDownload: true, progress: 0 }
|
||||
api.send('update', { key: 'checkForUpdate' })
|
||||
},
|
||||
downloadUpdate () {
|
||||
api.send('update', { key: 'downloadUpdate' })
|
||||
},
|
||||
doUpdateNow () {
|
||||
api.send('update', { key: 'doUpdateNow' })
|
||||
}
|
||||
}
|
||||
|
||||
function handleUpdateMessage (message) {
|
||||
const type = message.key
|
||||
if (type === 'available') {
|
||||
foundNewVersion(message.value)
|
||||
} else if (type === 'notAvailable') {
|
||||
noNewVersion()
|
||||
} else if (type === 'downloaded') {
|
||||
// 更新包已下载完成,让用户确认是否更新
|
||||
newUpdateIsReady(message.value)
|
||||
} else if (type === 'progress') {
|
||||
progressUpdate(message.value)
|
||||
} else if (type === 'error') {
|
||||
const error = message.error
|
||||
app.$message.error('Error: ' + (error == null ? '未知错误' : (error.stack || error).toString()))
|
||||
}
|
||||
}
|
||||
|
||||
function noNewVersion (value) {
|
||||
updateParams.newVersion = false
|
||||
if (updateParams.fromUser) {
|
||||
app.$message.info('当前已经是最新版本')
|
||||
}
|
||||
}
|
||||
|
||||
function progressUpdate (value) {
|
||||
updateParams.progress = value
|
||||
}
|
||||
function foundNewVersion (value) {
|
||||
updateParams.newVersion = true
|
||||
|
||||
if (updateParams.autoDownload !== false) {
|
||||
api.update.downloadUpdate()
|
||||
return
|
||||
}
|
||||
app.$confirm({
|
||||
title: '发现新版本',
|
||||
content: `是否要更新到v${value.version}?`,
|
||||
cancelText: '暂不升级',
|
||||
okText: '升级',
|
||||
// content: h => <div><h4>{value.version}更新内容:</h4><div>{value.releaseNotes}</div></div>,
|
||||
onOk () {
|
||||
console.log('OK')
|
||||
api.update.downloadUpdate()
|
||||
},
|
||||
onCancel () {
|
||||
console.log('Cancel')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function newUpdateIsReady (value) {
|
||||
app.$confirm({
|
||||
title: '新版本已准备好',
|
||||
content: `是否立即升级安装v${value.version}?`,
|
||||
cancelText: '暂不升级',
|
||||
okText: '立即升级',
|
||||
// content: h => <div><h4>{value.version}更新内容:</h4><div>{value.releaseNotes}</div></div>,
|
||||
onOk () {
|
||||
console.log('OK')
|
||||
api.update.doUpdateNow()
|
||||
},
|
||||
onCancel () {
|
||||
console.log('Cancel')
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
install
|
||||
}
|
|
@ -4,10 +4,13 @@
|
|||
给开发者的辅助工具
|
||||
<span>
|
||||
<a-button style="margin-right:10px" @click="openSetupCa">安装根证书</a-button>
|
||||
<a-badge :count="update.newVersion?1:0" dot>
|
||||
<a-button style="margin-right:10px" @click="doCheckUpdate">检查更新</a-button>
|
||||
</a-badge>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<div style="display: flex; align-items:center;justify-content:space-around;flex-direction: row">
|
||||
<div v-if="status" 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">
|
||||
|
@ -38,8 +41,6 @@
|
|||
</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'
|
||||
|
@ -52,7 +53,7 @@ export default {
|
|||
},
|
||||
data () {
|
||||
return {
|
||||
status: status,
|
||||
status: undefined,
|
||||
startup: {
|
||||
loading: false,
|
||||
type: () => {
|
||||
|
@ -60,9 +61,9 @@ export default {
|
|||
},
|
||||
doClick: () => {
|
||||
if (this.status.server.enabled) {
|
||||
this.apiCall(this.startup, api.shutdown)
|
||||
this.apiCall(this.startup, this.$api.shutdown)
|
||||
} else {
|
||||
this.apiCall(this.startup, api.startup)
|
||||
this.apiCall(this.startup, this.$api.startup)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -77,39 +78,48 @@ export default {
|
|||
config: undefined,
|
||||
setupCa: {
|
||||
visible: false
|
||||
}
|
||||
},
|
||||
update: {}
|
||||
}
|
||||
},
|
||||
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()
|
||||
})
|
||||
async created () {
|
||||
console.log('index created', this.status, this.$status)
|
||||
await this.reloadConfig()
|
||||
const status = await this.$api.status.get()
|
||||
console.log('status', status)
|
||||
this.$set(this, 'status', status)
|
||||
this.switchBtns = this.createSwitchBtns()
|
||||
console.log('switchBtns', this.switchBtns)
|
||||
if (this.$global.update == null) {
|
||||
this.$global.update = {
|
||||
fromUser: false,
|
||||
autoDownload: true,
|
||||
progress: 0,
|
||||
newVersion: false
|
||||
}
|
||||
this.update = this.$global.update
|
||||
this.doCheckUpdate(false)
|
||||
}
|
||||
this.update = this.$global.update
|
||||
},
|
||||
mounted () {
|
||||
console.log('index mounted')
|
||||
},
|
||||
methods: {
|
||||
reloadConfig () {
|
||||
return api.config.reload().then(ret => {
|
||||
return this.$api.config.reload().then(ret => {
|
||||
this.config = ret
|
||||
return ret
|
||||
})
|
||||
},
|
||||
createSwitchBtns () {
|
||||
console.log('api,', api)
|
||||
console.log('api,', this.$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)
|
||||
const status = this.status
|
||||
btns.server = this.createSwitchBtn('server', '代理服务', this.$api.server, status)
|
||||
btns.proxy = this.createSwitchBtn('proxy', '系统代理', this.$api.proxy, status)
|
||||
lodash.forEach(status.plugin, (item, key) => {
|
||||
btns[key] = this.createSwitchBtn(key, this.config.plugin[key].name, this.$api.plugin[key], status.plugin)
|
||||
})
|
||||
return btns
|
||||
},
|
||||
|
@ -145,10 +155,10 @@ export default {
|
|||
}
|
||||
},
|
||||
onServerClick (checked) {
|
||||
return this.onSwitchClick(this.server, api.server.start, api.server.close, checked)
|
||||
return this.onSwitchClick(this.server, this.$api.server.start, this.$api.server.close, checked)
|
||||
},
|
||||
start (checked) {
|
||||
this.apiCall(this.startup, api.startup)
|
||||
this.apiCall(this.startup, this.$api.startup)
|
||||
},
|
||||
openSettings () {
|
||||
this.settings.visible = true
|
||||
|
@ -157,12 +167,16 @@ export default {
|
|||
console.log('config changed', newConfig)
|
||||
this.reloadConfig().then(() => {
|
||||
if (this.status.server) {
|
||||
return api.server.restart()
|
||||
return this.$api.server.restart()
|
||||
}
|
||||
})
|
||||
},
|
||||
openSetupCa () {
|
||||
this.setupCa.visible = true
|
||||
},
|
||||
doCheckUpdate (fromUser = true) {
|
||||
this.update.fromUser = fromUser
|
||||
this.$api.update.checkForUpdate(this.update)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@
|
|||
</div>
|
||||
<template slot="footer">
|
||||
<div class="footer-bar">
|
||||
<a-button class="md-mr-10" icon="sync" @click="reloadDefault('server')">恢复默认</a-button>
|
||||
<a-button class="md-mr-10" icon="sync" @click="resetDefault()">恢复默认</a-button>
|
||||
<a-button :loading="applyLoading" icon="check" type="primary" @click="apply()">应用</a-button>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -75,6 +75,7 @@ export default {
|
|||
mixins: [Plugin],
|
||||
data () {
|
||||
return {
|
||||
key: 'plugin.node',
|
||||
npmVariables: undefined,
|
||||
registry: false
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
</div>
|
||||
<template slot="footer">
|
||||
<div class="footer-bar">
|
||||
<a-button class="md-mr-10" icon="sync" @click="reloadDefault('server')">恢复默认</a-button>
|
||||
<a-button class="md-mr-10" icon="sync" @click="resetDefault()">恢复默认</a-button>
|
||||
<a-button :loading="applyLoading" icon="check" type="primary" @click="apply()">应用</a-button>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -36,7 +36,7 @@ export default {
|
|||
mixins: [Plugin],
|
||||
data () {
|
||||
return {
|
||||
|
||||
key: 'proxy'
|
||||
}
|
||||
},
|
||||
created () {
|
||||
|
|
|
@ -69,7 +69,7 @@
|
|||
</div>
|
||||
<template slot="footer">
|
||||
<div class="footer-bar">
|
||||
<a-button class="md-mr-10" icon="sync" @click="reloadDefault('server')">恢复默认</a-button>
|
||||
<a-button class="md-mr-10" icon="sync" @click="resetDefault()">恢复默认</a-button>
|
||||
<a-button :loading="applyLoading" icon="check" type="primary" @click="apply()">应用</a-button>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -88,6 +88,7 @@ export default {
|
|||
mixins: [Plugin],
|
||||
data () {
|
||||
return {
|
||||
key: 'server',
|
||||
labelCol: { span: 4 },
|
||||
wrapperCol: { span: 20 },
|
||||
dnsMappings: []
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import lodash from 'lodash'
|
||||
import Vue from 'vue'
|
||||
const status = {
|
||||
server: {
|
||||
enabled: false
|
||||
|
@ -9,4 +11,19 @@ const status = {
|
|||
node: {}
|
||||
}
|
||||
}
|
||||
export default status
|
||||
async function install (api) {
|
||||
api.on('status', (event, message) => {
|
||||
console.log('view on status', event, message)
|
||||
const value = message.value
|
||||
const key = message.key
|
||||
lodash.set(status, key, value)
|
||||
})
|
||||
const basicStatus = await api.status.get()
|
||||
lodash.merge(status, basicStatus)
|
||||
Vue.prototype.$status = status
|
||||
return status
|
||||
}
|
||||
export default {
|
||||
install,
|
||||
status
|
||||
}
|
||||
|
|
|
@ -3,56 +3,38 @@
|
|||
"version": "1.0.1",
|
||||
"description": "",
|
||||
"main": "src/index.js",
|
||||
"depedencies": {},
|
||||
"keywords": [],
|
||||
"keywords": [
|
||||
"dev-sidecar"
|
||||
],
|
||||
"author": "docmirror.cn",
|
||||
"license": "MPL-2.0",
|
||||
"private": false,
|
||||
"scripts": {
|
||||
"start": "node start.js",
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"agentkeepalive": "^2.1.1",
|
||||
"babel-core": "^6.8.0",
|
||||
"babel-plugin-transform-async-to-generator": "^6.7.4",
|
||||
"babel-polyfill": "^6.8.0",
|
||||
"babel-preset-es2015": "^6.6.0",
|
||||
"babel-register": "^6.8.0",
|
||||
"charset": "^1.0.0",
|
||||
"child_process": "^1.0.2",
|
||||
"colors": "^1.1.2",
|
||||
"commander": "^2.9.0",
|
||||
"core-js": "^3.6.5",
|
||||
"debug": "^4.1.1",
|
||||
"dns-over-http": "^0.2.0",
|
||||
"dns-over-tls": "^0.0.8",
|
||||
"iconv-lite": "^0.4.13",
|
||||
"is-browser": "^2.1.0",
|
||||
"jschardet": "^1.4.1",
|
||||
"json5": "^2.1.3",
|
||||
"lodash": "^4.7.0",
|
||||
"log4js": "^6.3.0",
|
||||
"lru-cache": "^6.0.0",
|
||||
"mkdirp": "^0.5.1",
|
||||
"node-cmd": "^3.0.0",
|
||||
"node-forge": "^0.8.2",
|
||||
"node-mitmproxy": "^3.1.1",
|
||||
"node-powershell": "^4.0.0",
|
||||
"require-context": "^1.1.0",
|
||||
"ssl-root-cas": "^1.3.1",
|
||||
"through2": "^2.0.1",
|
||||
"tunnel-agent": "^0.4.3",
|
||||
"util": "^0.12.3",
|
||||
"validator": "^13.1.17",
|
||||
"vue": "^2.6.11",
|
||||
"winreg": "^1.2.4"
|
||||
"validator": "^13.1.17"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "~4.5.0",
|
||||
"@vue/cli-plugin-eslint": "~4.5.0",
|
||||
"@vue/cli-service": "~4.5.0",
|
||||
"@vue/eslint-config-standard": "^5.1.2",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"eslint": "^6.7.2",
|
||||
|
@ -60,8 +42,7 @@
|
|||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"eslint-plugin-standard": "^4.0.0",
|
||||
"eslint-plugin-vue": "^6.2.2",
|
||||
"vue-template-compiler": "^2.6.11"
|
||||
"eslint-plugin-vue": "^6.2.2"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"root": true,
|
||||
|
|
|
@ -63,15 +63,12 @@ function connect (req, cltSocket, head, hostname, port, dnsConfig) {
|
|||
proxySocket.on('timeout', () => {
|
||||
const end = new Date().getTime()
|
||||
console.log('代理socket timeout:', hostname, port, (end - start) + 'ms')
|
||||
proxySocket.destroy()
|
||||
cltSocket.destroy()
|
||||
})
|
||||
proxySocket.on('error', (e) => {
|
||||
// 连接失败,可能被GFW拦截,或者服务端拥挤
|
||||
const end = new Date().getTime()
|
||||
console.error('代理连接失败:', e.message, hostname, port, (end - start) + 'ms')
|
||||
cltSocket.destroy()
|
||||
|
||||
if (isDnsIntercept) {
|
||||
const { dns, ip, hostname } = isDnsIntercept
|
||||
dns.count(hostname, ip, true)
|
||||
|
|
|
@ -39,14 +39,14 @@ module.exports = function createRequestHandler (requestInterceptor, responseInte
|
|||
|
||||
const proxyRequestPromise = async () => {
|
||||
rOptions.host = rOptions.hostname || rOptions.host || 'localhost'
|
||||
if (dnsConfig) {
|
||||
const dns = DnsUtil.hasDnsLookup(dnsConfig, rOptions.host)
|
||||
if (dns) {
|
||||
const ip = await dns.lookup(rOptions.host)
|
||||
console.log('使用自定义dns:', rOptions.host, ip, dns.dnsServer)
|
||||
rOptions.host = ip
|
||||
}
|
||||
}
|
||||
// if (dnsConfig) {
|
||||
// const dns = DnsUtil.hasDnsLookup(dnsConfig, rOptions.host)
|
||||
// if (dns) {
|
||||
// const ip = await dns.lookup(rOptions.host)
|
||||
// console.log('使用自定义dns:', rOptions.host, ip, dns.dnsServer)
|
||||
// rOptions.host = ip
|
||||
// }
|
||||
// }
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
// use the binded socket for NTLM
|
||||
|
@ -64,6 +64,22 @@ module.exports = function createRequestHandler (requestInterceptor, responseInte
|
|||
const url = `${rOptions.protocol}//${rOptions.hostname}:${rOptions.port}${rOptions.path}`
|
||||
const start = new Date().getTime()
|
||||
console.log('代理请求:', url, rOptions.method)
|
||||
let isDnsIntercept
|
||||
if (dnsConfig) {
|
||||
const dns = DnsUtil.hasDnsLookup(dnsConfig, rOptions.hostname)
|
||||
if (dns) {
|
||||
rOptions.lookup = (hostname, options, callback) => {
|
||||
dns.lookup(hostname).then(ip => {
|
||||
isDnsIntercept = { dns, hostname, ip }
|
||||
if (ip !== hostname) {
|
||||
callback(null, ip, 4)
|
||||
} else {
|
||||
rOptions.lookup(hostname, options, callback)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proxyReq = (rOptions.protocol === 'https:' ? https : http).request(rOptions, (proxyRes) => {
|
||||
const end = new Date().getTime()
|
||||
|
@ -75,12 +91,22 @@ module.exports = function createRequestHandler (requestInterceptor, responseInte
|
|||
|
||||
proxyReq.on('timeout', () => {
|
||||
const end = new Date().getTime()
|
||||
if (isDnsIntercept) {
|
||||
const { dns, ip, hostname } = isDnsIntercept
|
||||
dns.count(hostname, ip, true)
|
||||
console.error('记录ip失败次数,用于优选ip:', hostname, ip)
|
||||
}
|
||||
console.error('代理请求超时', rOptions.protocol, rOptions.hostname, rOptions.path, (end - start) + 'ms')
|
||||
reject(new Error(`${rOptions.host}:${rOptions.port}, 代理请求超时`))
|
||||
})
|
||||
|
||||
proxyReq.on('error', (e, req, res) => {
|
||||
const end = new Date().getTime()
|
||||
if (isDnsIntercept) {
|
||||
const { dns, ip, hostname } = isDnsIntercept
|
||||
dns.count(hostname, ip, true)
|
||||
console.error('记录ip失败次数,用于优选ip:', hostname, ip)
|
||||
}
|
||||
console.error('代理请求错误', e.errno, rOptions.hostname, rOptions.path, (end - start) + 'ms')
|
||||
reject(e)
|
||||
})
|
||||
|
@ -92,7 +118,7 @@ module.exports = function createRequestHandler (requestInterceptor, responseInte
|
|||
|
||||
req.on('aborted', function () {
|
||||
console.error('请求被取消', rOptions.hostname, rOptions.path)
|
||||
proxyReq.destroy()
|
||||
proxyReq.abort()
|
||||
reject(new Error('请求被取消'))
|
||||
})
|
||||
req.on('error', function (e, req, res) {
|
||||
|
|
|
@ -3541,6 +3541,16 @@ dashdash@^1.12.0:
|
|||
dependencies:
|
||||
assert-plus "^1.0.0"
|
||||
|
||||
date-format@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/date-format/-/date-format-2.1.0.tgz#31d5b5ea211cf5fd764cd38baf9d033df7e125cf"
|
||||
integrity sha512-bYQuGLeFxhkxNOF3rcMtiZxvCBAquGzZm6oWA1oZ0g2THUzivaRhv8uOhdr19LmoobSOLoIAxeUK2RdbM8IFTA==
|
||||
|
||||
date-format@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/date-format/-/date-format-3.0.0.tgz#eb8780365c7d2b1511078fb491e6479780f3ad95"
|
||||
integrity sha512-eyTcpKOcamdhWJXj56DpQMo1ylSQpcGtGKXcU0Tb97+K56/CF5amAqqqNj0+KvA0iw2ynxtHWFsPDSClCxe48w==
|
||||
|
||||
de-indent@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npm.taobao.org/de-indent/download/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d"
|
||||
|
@ -4644,7 +4654,7 @@ flat-cache@^2.0.1:
|
|||
rimraf "2.6.3"
|
||||
write "1.0.3"
|
||||
|
||||
flatted@^2.0.0:
|
||||
flatted@^2.0.0, flatted@^2.0.1:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.npm.taobao.org/flatted/download/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138"
|
||||
integrity sha1-RXWyHivO50NKqb5mL0t7X5wrUTg=
|
||||
|
@ -4720,6 +4730,15 @@ fs-extra@^7.0.1:
|
|||
jsonfile "^4.0.0"
|
||||
universalify "^0.1.0"
|
||||
|
||||
fs-extra@^8.1.0:
|
||||
version "8.1.0"
|
||||
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0"
|
||||
integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==
|
||||
dependencies:
|
||||
graceful-fs "^4.2.0"
|
||||
jsonfile "^4.0.0"
|
||||
universalify "^0.1.0"
|
||||
|
||||
fs-minipass@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.npm.taobao.org/fs-minipass/download/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb"
|
||||
|
@ -4901,7 +4920,7 @@ globby@^9.2.0:
|
|||
pify "^4.0.1"
|
||||
slash "^2.0.0"
|
||||
|
||||
graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.2:
|
||||
graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2:
|
||||
version "4.2.4"
|
||||
resolved "https://registry.npm.taobao.org/graceful-fs/download/graceful-fs-4.2.4.tgz?cache=0&sync_timestamp=1589682809142&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fgraceful-fs%2Fdownload%2Fgraceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb"
|
||||
integrity sha1-Ila94U02MpWMRl68ltxGfKB6Kfs=
|
||||
|
@ -6055,6 +6074,17 @@ log-symbols@^2.2.0:
|
|||
dependencies:
|
||||
chalk "^2.0.1"
|
||||
|
||||
log4js@^6.3.0:
|
||||
version "6.3.0"
|
||||
resolved "https://registry.yarnpkg.com/log4js/-/log4js-6.3.0.tgz#10dfafbb434351a3e30277a00b9879446f715bcb"
|
||||
integrity sha512-Mc8jNuSFImQUIateBFwdOQcmC6Q5maU0VVvdC2R6XMb66/VnT+7WS4D/0EeNMZu1YODmJe5NIn2XftCzEocUgw==
|
||||
dependencies:
|
||||
date-format "^3.0.0"
|
||||
debug "^4.1.1"
|
||||
flatted "^2.0.1"
|
||||
rfdc "^1.1.4"
|
||||
streamroller "^2.2.4"
|
||||
|
||||
loglevel@^1.6.8:
|
||||
version "1.7.0"
|
||||
resolved "https://registry.npm.taobao.org/loglevel/download/loglevel-1.7.0.tgz#728166855a740d59d38db01cf46f042caa041bb0"
|
||||
|
@ -8002,6 +8032,11 @@ retry@^0.12.0:
|
|||
resolved "https://registry.npm.taobao.org/retry/download/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b"
|
||||
integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=
|
||||
|
||||
rfdc@^1.1.4:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.1.4.tgz#ba72cc1367a0ccd9cf81a870b3b58bd3ad07f8c2"
|
||||
integrity sha512-5C9HXdzK8EAqN7JDif30jqsBzavB7wLpaubisuQIGHWf2gUXSpzy6ArX/+Da8RjFpagWsCn+pIgxTMAmKw9Zug==
|
||||
|
||||
rgb-regex@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.npm.taobao.org/rgb-regex/download/rgb-regex-1.0.1.tgz#c0e0d6882df0e23be254a475e8edd41915feaeb1"
|
||||
|
@ -8541,6 +8576,15 @@ stream-shift@^1.0.0:
|
|||
resolved "https://registry.npm.taobao.org/stream-shift/download/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d"
|
||||
integrity sha1-1wiCgVWasneEJCebCHfaPDktWj0=
|
||||
|
||||
streamroller@^2.2.4:
|
||||
version "2.2.4"
|
||||
resolved "https://registry.yarnpkg.com/streamroller/-/streamroller-2.2.4.tgz#c198ced42db94086a6193608187ce80a5f2b0e53"
|
||||
integrity sha512-OG79qm3AujAM9ImoqgWEY1xG4HX+Lw+yY6qZj9R1K2mhF5bEmQ849wvrb+4vt4jLMLzwXttJlQbOdPOQVRv7DQ==
|
||||
dependencies:
|
||||
date-format "^2.1.0"
|
||||
debug "^4.1.1"
|
||||
fs-extra "^8.1.0"
|
||||
|
||||
strict-uri-encode@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.npm.taobao.org/strict-uri-encode/download/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713"
|
||||
|
|
Loading…
Reference in New Issue