Merge pull request #274 from wangliang181230/feature/sysproxy/excludeIpList

1)系统代理排除列表可配置化;2)启/禁用远程配置功能增强;3)添加重载远程配置功能;4)修复3个BUG;5)几处功能优化;6)配置调整;7)文档调整。
pull/276/head
Greper 2024-03-15 09:34:38 +08:00 committed by GitHub
commit 3594c68f7b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
32 changed files with 796 additions and 7390 deletions

4
.gitignore vendored
View File

@ -6,4 +6,6 @@ gen
node_modules/
*.lock
*.log
pnpm-lock.yaml
pnpm-lock.yaml
package-lock.json
*.lnk

101
README.md
View File

@ -5,7 +5,6 @@
通过本地代理的方式将https请求代理到一些国内的加速通道上
<a href='https://github.com/docmirror/dev-sidecar'><img alt="GitHub stars" src="https://img.shields.io/github/stars/docmirror/dev-sidecar?logo=github"></a>
<a href='https://gitee.com/docmirror/dev-sidecar'><img src='./doc/gitee.png' alt='star'/></a>
>
> Gitee上的同步项目已被封禁此项目将不再更新与维护 【狗头保命】
@ -26,7 +25,6 @@
> 注意由于electron无法监听windows的关机事件开着ds情况下直接重启电脑会导致无法上网你可以手动启动ds即可恢复网络你也可以将ds设置为开机自启。
>
> 关于此问题的更多讨论请前往:
> https://gitee.com/docmirror/dev-sidecar/issues/I49OUL
> https://github.com/docmirror/dev-sidecar/issues/109
>
@ -40,17 +38,17 @@
## 一、 特性
### 1、 dns优选解决***污染问题)
### 1.1、 dns优选解决***污染问题)
* 根据网络状况智能解析最佳域名ip地址获取最佳网络速度
* 解决一些网站和库无法访问或访问速度慢的问题
* 建议遇到打开比较慢的国外网站可以优先尝试将该域名添加到dns设置中注意被***封杀的无效)
### 2、 请求拦截
### 1.2、 请求拦截
* 拦截打不开的网站,代理到加速镜像站点上去。
* 可配置多个镜像站作为备份
* 具备测速机制,当访问失败或超时之后,自动切换到备用站点,使得目标服务高可用
### 3、 github加速
### 1.3、 github加速
* github 直连加速 (通过修改sni实现感谢 [fastGithub](https://github.com/dotnetcore/FastGithub) 提供的思路)
* release、source、zip下载加速
* clone 加速
@ -67,11 +65,11 @@
> 由于此脚本在ds中是打包在本地的更新会不及时你可以直接通过浏览器安装油猴插件使用此脚本从而获得最新更新ds本地的可以通过`加速服务->基本设置->启用脚本`进行关闭)。
### 4、 Stack Overflow 加速
### 1.4、 Stack Overflow 加速
* 将ajax.google.com代理到加速CDN上
* recaptcha 图片验证码加速
### 5、 npm加速
### 1.5、 npm加速
* 支持开启npm代理
* 官方与淘宝npm registry一键切换,
* 某些npm install的时候并且使用cnpm也无法安装时可以尝试开启npm代理再试
@ -87,11 +85,10 @@
## 二、快速开始
支持windows、Mac、Linux(Ubuntu)
### DevSidecar桌面应用
### 2.1、DevSidecar桌面应用
#### 1 下载安装包
#### 1下载安装包
* release下载
[Gitee Release](https://gitee.com/docmirror/dev-sidecar/releases)
[Github Release](https://github.com/docmirror/dev-sidecar/releases)
> Windows: 请选择DevSidecar-x.x.x.exe
@ -104,13 +101,13 @@
> 注意:由于没有买应用证书,所以应用在下载安装时会有“未知发行者”等安全提示,选择保留即可。
#### 2 安装后打开
#### 2安装后打开
> 注意mac版安装需要在“系统偏好设置->安全性与隐私->通用”中解锁并允许应用安装
![](./doc/index.png)
#### 3 安装根证书
#### 3安装根证书
第一次打开会提示安装证书,根据提示操作即可
@ -122,12 +119,12 @@
> 火狐浏览器需要[手动安装证书](#3浏览器打开提示证书不受信任)
#### 4 开始加速吧
#### 4开始加速吧
去试试打开github
### 开启前 vs 开启后
### 2.2、开启前 vs 开启后
| | 开启前 | 开启后 |
| ---- | ---- | ---- |
@ -138,14 +135,14 @@
## 三、模式说明
### 安全模式
### 3.1、安全模式
* 此模式关闭拦截、关闭增强、开启dns优选、开启测速
* 最安全,无需安装证书,可以在浏览器地址栏左侧查看域名证书
* 功能也最弱只有特性1相当于查询github的国外ip手动改hosts一个意思。
* github的可访问性不稳定取决于IP测速如果有绿色ip存在`有可能` 可以直连访问。
![](./doc/speed.png)
### 默认模式
### 3.2、默认模式
* 此模式开启拦截、关闭增强、开启dns优选、开启测速
* 需要安装证书通过修改sni直连访问github
* 功能上包含特性1/2/3/4。
@ -156,7 +153,8 @@
* 建议遇到打开比较慢的国外网站可以尝试将该域名添加到dns设置中注意被***封杀的无效)
### 其他加速
1. git clone 加速
#### 1git clone 加速
方式1快捷复制
> 开启脚本支持然后在复制clone链接下方即可复制到加速链接
@ -167,14 +165,14 @@
> 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/) 这个很容易超限
#### 2github.com的镜像网站(注意:不能登录)
> 1. [hub.fastgit.org](https://hub.fastgit.org/)
> 2. [github.com.cnpmjs.org](https://github.com.cnpmjs.org/) 这个很容易超限
## 五、api
### 拦截配置
### 5.1、拦截配置
没有配置域名的不会拦截,其他根据配置进行拦截处理
```js
const intercepts = {
@ -210,32 +208,32 @@ const intercepts = {
}
```
### DNS优选配置
### 5.2、DNS优选配置
某些域名解析出来的ip会无法访问比如api.github.com会被解析到新加坡的ip上新加坡的服务器在上午挺好到了晚上就卡死基本不可用
通过从dns上获取ip列表切换不同的ip进行尝试最终会挑选到一个最快的ip
```js
dns: {
mapping: {
//
'api.github.com': 'usa', // "解决push的时候需要输入密码的问题",
'gist.github.com': 'usa' // 解决gist无法访问的问题
"*.githubusercontent.com": "usa" // 解决github头像经常下载不到的问题
'*.githubusercontent.com': 'usa' // 解决github头像经常下载不到的问题
}
},
}
```
注意暂时只支持IPv4的解析
## 六、问题排查
### 1、dev-sidecar的前两个开关没有处于打开状态
### 6.1、dev-sidecar的前两个开关没有处于打开状态
1. 尝试将开关按钮手动打开
2. 请尝试右键dev-sidecar图标点退出。再重新打开
3. 如果还不行,请将日志发送给作者
如果是mac系统可能是下面的原因
#### 1.1 Mac系统使用时首页的系统代理开关无法打开
#### 1Mac系统使用时首页的系统代理开关无法打开
出现这个问题可能是没有开启系统代理命令的执行权限
```
networksetup -setwebproxy 'WiFi' 127.0.0.1 1181
@ -248,7 +246,7 @@ networksetup -setwebproxy 'WiFi' 127.0.0.1 1181
>系统偏好设置—>安全性与隐私—> 通用—> 高级—> 访问系统范围的偏好设置需要输入管理员密码(取消勾选)
### 2、没有加速效果
### 6.2、没有加速效果
>本应用仅支持https加速请务必确认你访问的网站地址是https开头的
@ -268,23 +266,23 @@ networksetup -setwebproxy 'WiFi' 127.0.0.1 1181
正常情况下ds在“系统代理”开关打开时会自动设置系统代理。
### 3、浏览器打开提示证书不受信任
### 6.3、浏览器打开提示证书不受信任
![](./doc/crt-error.png)
一般是证书安装位置不对,重新安装证书后,重启浏览器
#### 3.1 windows: 请确认证书已正确安装在“信任的根证书颁发机构”下
#### 1windows: 请确认证书已正确安装在“信任的根证书颁发机构”下
#### 3.2 mac: 请确认证书已经被安装并已经设置信任。
#### 2mac: 请确认证书已经被安装并已经设置信任。
#### 3.3 火狐浏览器:火狐浏览器不走系统的根证书,需要在选项中添加根证书
#### 3火狐浏览器:火狐浏览器不走系统的根证书,需要在选项中添加根证书
> 1、火狐浏览器->选项->隐私与安全->证书->查看证书
> 2、证书颁发机构->导入
> 3、选择证书文件`C:\Users(用户)\Administrator(你的账号)\.dev-sidecar\dev-sidecar.ca.crt`Mac或linux为`~/.dev-sidecar`目录)
> 4、勾选信任由此证书颁发机构来标识网站确定即可
### 4. 打开github显示连接超时
### 6.4、打开github显示连接超时
```html
DevSidecar Warning:
Error: www.github.com:443, 代理请求超时
@ -293,18 +291,18 @@ Error: www.github.com:443, 代理请求超时
2、如果是安全模式则是因为不稳定导致的等一会再刷新试试
3、如果是增强模式则是由于访问人数过多正常现象
### 5、查看日志是否有报错
### 6.5、查看日志是否有报错
如果还是不行,请在下方加作者好友,将服务日志发送给作者进行分析
日志打开方式:加速服务->右边日志按钮->打开日志文件夹
![](./doc/log.png)
### 6、某些原本可以打开的网站打不开了
### 6.6、某些原本可以打开的网站打不开了
1、可以尝试关闭pac
2、可以将域名加入白名单
### 7、应用意外关闭导致没有网络了
### 6.7、应用意外关闭导致没有网络了
应用开启后会自动修改系统代理设置,正常退出会自动关闭系统代理
当应用意外关闭时,可能会因为没有将系统代理恢复,从而导致完全无法上网。
@ -314,7 +312,7 @@ Error: www.github.com:443, 代理请求超时
3、如果你是因为开着ds的情况下重启电脑导致无法上网你可以设置ds为开机自启
### 8、卸载应用后上不了网git请求不了
### 6.8、卸载应用后上不了网git请求不了
如果你在卸载应用前没有正常退出app就有可能无法上网。请按如下步骤操作恢复您的网络
1、关闭系统代理设置参见[手动关闭系统代理设置](./doc/recover.md)
@ -329,12 +327,33 @@ npm config delete proxy
npm config delete https-proxy
```
## 七、在其他程序使用
* [java程序使用](./doc/other.md#Java程序使用)
## 八、贡献代码
### 开发调试模式启动
### 8.1、准备环境
#### 1安装 `nodejs`
推荐安装 nodejs 16.x版本其他版本未做测试
#### 2安装 `lerna``phantomjs`
运行如下命令即可安装所需依赖:
> 注lerna指定为6.x版本更高版本会导致打包失败不兼容导致
```shell
npm install cnpm -g --registry=https://registry.npm.taobao.org
cnpm install lerna@6 -g
cnpm install phantomjs -g
```
### 8.2、开发调试模式启动
运行如下命令即可开发模式启动
```shell
@ -342,7 +361,7 @@ git clone https://github.com/docmirror/dev-sidecar
cd dev-sidecar
npm install lerna -g
# 注意不要使用 `npm install` 来安装依赖,因为 `lerna bootstrap` 会自动安装依赖
lerna bootstrap
cd packages/gui
@ -352,13 +371,13 @@ npm run electron
```
> 如果electron依赖包下载不动可以开启ds的npm加速
### 打包成可执行文件
### 8.3、打包成可执行文件
```shell
# 先执行上面的步骤,然后运行如下命令打包成可执行文件
npm run electron:build
```
### 提交pr
### 8.4、提交pr
如果你想将你的修改贡献出来请提交pr

View File

@ -46,7 +46,6 @@ DevSidecar在第一次启动时会在本地随机生成一份根证书当有
> 对于应用来源风险:
> 请勿从未知网站下载DevSidecar应用认准官方版本发布地址
> [Gitee Release](https://gitee.com/docmirror/dev-sidecar/releases)
> [Github Release](https://github.com/docmirror/dev-sidecar/releases)
>
> 或者从源码自行编译安装

File diff suppressed because it is too large Load Diff

View File

@ -6,80 +6,32 @@ const JSON5 = require('json5').default
const request = require('request')
const path = require('path')
const log = require('./utils/util.log')
const mergeApi = require('./merge.js')
let configTarget = lodash.cloneDeep(defConfig)
function get () {
return configTarget
}
function _deleteDisabledItem (target) {
lodash.forEach(target, (item, key) => {
if (item == null) {
delete target[key]
}
if (lodash.isObject(item)) {
_deleteDisabledItem(item)
}
})
}
const getDefaultConfigBasePath = function () {
return get().server.setting.userBasePath
}
function _getRemoteSavePath () {
function _getRemoteSavePath (prefix = '', version = '') {
const dir = getDefaultConfigBasePath()
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir)
}
return path.join(dir, 'remote_config.json5')
return path.join(dir, prefix + 'remote_config.json' + version)
}
function _getConfigPath () {
const dir = getDefaultConfigBasePath()
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir)
}
return dir + '/config.json5'
return dir + '/config.json'
}
function doMerge (defObj, newObj) {
if (newObj == null) {
return defObj
}
const defObj2 = { ...defObj }
const newObj2 = {}
for (const key in newObj) {
const newValue = newObj[key]
const defValue = defObj[key]
if (newValue != null && defValue == null) {
newObj2[key] = newValue
continue
}
if (lodash.isEqual(newValue, defValue)) {
delete defObj2[key]
continue
}
if (lodash.isArray(newValue)) {
delete defObj2[key]
newObj2[key] = newValue
continue
}
if (lodash.isObject(newValue)) {
newObj2[key] = doMerge(defValue, newValue)
delete defObj2[key]
continue
} else {
// 基础类型,直接覆盖
delete defObj2[key]
newObj2[key] = newValue
continue
}
}
// defObj 里面剩下的是被删掉的
lodash.forEach(defObj2, (defValue, key) => {
newObj2[key] = null
})
return newObj2
}
let timer
const configApi = {
async startAutoDownloadRemoteConfig () {
@ -112,7 +64,25 @@ const configApi = {
return
}
if (response && response.statusCode === 200) {
fs.writeFileSync(_getRemoteSavePath(), body)
const originalRemoteSavePath = _getRemoteSavePath('original_', '5')
fs.writeFileSync(originalRemoteSavePath, body)
log.info('保存原来的远程配置文件成功:', originalRemoteSavePath)
// 尝试解析远程配置,如果解析失败,则不保存它
let remoteConfig
try {
remoteConfig = JSON5.parse(body)
} catch (e) {
log.error('远程配置内容格式不正确:', body)
remoteConfig = null
}
if (remoteConfig != null) {
const remoteSavePath = _getRemoteSavePath()
fs.writeFileSync(remoteSavePath, JSON.stringify(remoteConfig, null, '\t'))
log.info('保存远程配置文件成功:', remoteSavePath)
}
resolve()
} else {
const message = '下载远程配置失败:' + response.message + ',code:' + response.statusCode
@ -128,48 +98,82 @@ const configApi = {
}
try {
const path = _getRemoteSavePath()
log.info('读取合并远程配置文件:', path)
if (fs.existsSync(path)) {
log.info('读取远程配置文件:', path)
const file = fs.readFileSync(path)
return JSON5.parse(file.toString())
} else {
log.warn('远程配置文件不存在:', path)
}
} catch (e) {
log.info('远程配置读取有误', e)
log.warn('远程配置读取失败:', e)
}
return {}
},
readRemoteConfigStr () {
if (get().app.remoteConfig.enabled !== true) {
return '{}'
}
try {
const path = _getRemoteSavePath()
if (fs.existsSync(path)) {
log.info('读取远程配置文件内容:', path)
const file = fs.readFileSync(path)
return file.toString()
} else {
log.warn('远程配置文件不存在:', path)
}
} catch (e) {
log.warn('远程配置内容读取失败:', e)
}
return '{}'
},
/**
* 保存自定义的 config
* @param newConfig
* @param remoteConfig //远程配置
*/
save (newConfig) {
// 对比默认config的异同
// configApi.set(newConfig)
const defConfig = configApi.getDefault()
let defConfig = configApi.getDefault()
// 如果开启了远程配置,则读取远程配置,合并到默认配置中
if (get().app.remoteConfig.enabled === true) {
doMerge(defConfig, configApi.readRemoteConfig())
defConfig = mergeApi.doMerge(defConfig, configApi.readRemoteConfig())
}
// 计算新配置与默认配置(启用远程配置时,含远程配置)的差异,并保存到 config.json 中
const diffConfig = mergeApi.doDiff(defConfig, newConfig)
const configPath = _getConfigPath()
fs.writeFileSync(configPath, JSON.stringify(diffConfig, null, '\t'))
log.info('保存自定义配置文件成功:', configPath)
// 重载配置
const allConfig = configApi.reload()
return {
diffConfig,
allConfig
}
const saveConfig = doMerge(defConfig, newConfig)
fs.writeFileSync(_getConfigPath(), JSON5.stringify(saveConfig, null, 2))
configApi.reload()
return saveConfig
},
doMerge,
doMerge: mergeApi.doMerge,
doDiff: mergeApi.doDiff,
/**
* 读取后合并配置
* 读取 config.json 合并配置
* @returns {*}
*/
reload () {
const path = _getConfigPath()
let userConfig
if (!fs.existsSync(path)) {
return configApi.get()
userConfig = {}
} else {
const file = fs.readFileSync(path)
userConfig = JSON5.parse(file.toString())
}
const file = fs.readFileSync(path)
const userConfig = JSON5.parse(file.toString())
configApi.set(userConfig)
const config = configApi.get()
const config = configApi.set(userConfig)
return config || {}
},
update (partConfig) {
@ -179,21 +183,18 @@ const configApi = {
get,
set (newConfig) {
if (newConfig == null) {
return
return configTarget
}
const merged = lodash.cloneDeep(newConfig)
const clone = lodash.cloneDeep(defConfig)
function customizer (objValue, srcValue) {
if (lodash.isArray(objValue)) {
return srcValue
}
}
lodash.mergeWith(merged, clone, customizer)
lodash.mergeWith(merged, configApi.readRemoteConfig(), customizer)
lodash.mergeWith(merged, newConfig, customizer)
_deleteDisabledItem(merged)
const merged = lodash.cloneDeep(defConfig)
const remoteConfig = configApi.readRemoteConfig()
mergeApi.doMerge(merged, remoteConfig)
mergeApi.doMerge(merged, newConfig)
mergeApi.deleteNullItems(merged)
configTarget = merged
log.info('加载配置完成')
return configTarget
},
getDefault () {

View File

@ -1,14 +1,18 @@
const path = require('path')
function getUserBasePath () {
const userHome = process.env.USERPROFILE || process.env.HOME || '/'
return path.resolve(userHome, './.dev-sidecar')
}
function getRootCaCertPath () {
return getUserBasePath() + '/dev-sidecar.ca.crt'
}
function getRootCaKeyPath () {
return getUserBasePath() + '/dev-sidecar.ca.key.pem'
}
module.exports = {
app: {
mode: 'default',
@ -17,7 +21,7 @@ module.exports = {
},
remoteConfig: {
enabled: true,
url: 'https://gitee.com/docmirror/dev-sidecar/raw/master/packages/core/src/config/remote_config.json5'
url: 'https://github.com/docmirror/dev-sidecar/raw/master/packages/core/src/config/remote_config.json5'
},
dock: {
hideWhenWinClose: false
@ -84,22 +88,29 @@ module.exports = {
'github.githubassets.com': {
'.*': {
proxy: 'github.githubassets.com',
backup: [
'assets.fastgit.org'
],
sni: 'assets.fastgit.org'
sni: 'baidu.com'
}
},
'camo.githubusercontent.com': {
'.*': {
proxy: 'camo.githubusercontent.com',
sni: 'baidu.com'
}
},
'collector.github.com': {
'.*': {
proxy: 'collector.github.com',
sni: 'baidu.com'
}
},
'customer-stories-feed.github.com': {
'.*': { proxy: 'customer-stories-feed.fastgit.org' }
},
'raw.githubusercontent.com': {
'.*': {
proxy: 'raw.githubusercontent.com',
sni: 'baidu.com'
}
// '.*': { proxy: 'raw.fastgit.org' }
},
'user-images.githubusercontent.com': {
'.*': {
@ -191,18 +202,25 @@ module.exports = {
}
},
whiteList: {
'*.cn': true,
'cn.*': true,
'*china*': true,
'dingtalk.com': true,
'*.dingtalk.com': true,
'apple.com': true,
'*.apple.com': true,
'microsoft.com': true,
'*.microsoft.com': true,
'alipay.com': true,
'*.alipay.com': true,
'pay.weixin.qq.com': true,
'www.baidu.com': true
'qq.com': true,
'*.qq.com': true,
'baidu.com': true,
'*.baidu.com': true
},
// sniList: {
sniList: {
// 'github.com': 'abaidu.com'
// },
},
dns: {
providers: {
aliyun: {
@ -227,20 +245,15 @@ module.exports = {
}
},
mapping: {
// 'assets.fastgit.org': 'usa',
'*github*.com': 'quad9',
'*github.io': 'quad9',
'*stackoverflow.com': 'quad9',
'*.electronjs.org': 'quad9',
'*amazonaws.com': 'quad9',
'*githubusercontent.com': 'quad9',
'*yarnpkg.com': 'quad9',
'*cloudfront.net': 'quad9',
'*cloudflare.com': 'quad9',
'*github.io': 'quad9',
'img.shields.io': 'quad9',
'*.githubusercontent.com': 'quad9',
'*.githubassets.com': 'quad9',
// "解决push的时候需要输入密码的问题",
'github.com': 'quad9',
'*github.com': 'quad9',
'*.vuepress.vuejs.org': 'quad9',
'gh.docmirror.top': 'quad9',
'*v2ex.com': 'quad9',
@ -250,7 +263,7 @@ module.exports = {
},
speedTest: {
enabled: true,
interval: 60000,
interval: 300000,
hostnameList: ['github.com'],
dnsProviders: ['usa', 'quad9', 'rubyfish']
}

View File

@ -1,10 +1,22 @@
{
server: {
intercepts: {
'github.githubassets.com': {
'.*': {
proxy: 'github.githubassets.com',
sni: 'baidu.com',
"server": {
"intercepts": {
"github.githubassets.com": {
".*": {
"proxy": "github.githubassets.com",
"sni": "baidu.com"
}
},
"camo.githubusercontent.com": {
".*": {
"proxy": "camo.githubusercontent.com",
"sni": "baidu.com"
}
},
"collector.github.com": {
".*": {
"proxy": "collector.github.com",
"sni": "baidu.com"
}
},
"www.gstatic.com": {
@ -13,43 +25,50 @@
}
}
},
dns: {
mapping: {
'*jetbrains.com': 'quad9',
'*azureedge.net': 'quad9',
'*stackoverflow.com': 'quad9'
},
speedTest: {
interval: 300000,
"dns": {
"mapping": {
"*jetbrains.com": "quad9",
"*azureedge.net": "quad9",
"*stackoverflow.com": "quad9"
},
"speedTest": {
"interval": 300000
}
}
},
plugin: {
overwall: {
targets: {
'*azureedge.net': true,
'github.com': true,
'*wikimedia.org': true,
'v2ex.com': true,
'*cloudfront.net': true,
'*bing.com': true,
'*discourse-cdn.com': true,
'*gravatar.com': true,
'*docker.com': true,
'*vueuse.org': true,
'*elastic.co': true,
'*optimizely.com': true,
'*stackpathcdn.com': true,
'*fastly.net': true,
'*cloudflare.com': true,
'*233v2.com': true,
'*v2fly.org': true,
'*telegram.org': true,
'*amazon.com': true,
'*googleapis.com': true,
'*cloudflareinsights.com': true,
'*.intlify.dev': true,
'*segment.io': true
"proxy": {
"excludeIpList": {
}
},
"plugin": {
"overwall": {
"targets": {
"*github*.com": true,
"*wikimedia.org": true,
"v2ex.com": true,
"*azureedge.net": true,
"*cloudfront.net": true,
"*bing.com": true,
"*discourse-cdn.com": true,
"*gravatar.com": true,
"*docker.com": true,
"*vueuse.org": true,
"*elastic.co": true,
"*optimizely.com": true,
"*stackpathcdn.com": true,
"*fastly.net": true,
"*cloudflare.com": true,
"*233v2.com": true,
"*v2fly.org": true,
"*telegram.org": true,
"*amazon.com": true,
"*googleapis.com": true,
"*.google-analytics.com": true,
"*cloudflareinsights.com": true,
"*.intlify.dev": true,
"*segment.io": true,
"*.shields.io": true,
"*.jsdelivr.net": true
}
}
}

View File

@ -83,7 +83,7 @@ async function shutdown () {
try {
const plugins = []
for (const key in plugin) {
if (status.plugin[key].enabled && plugin[key].close) {
if (status.plugin[key] && status.plugin[key].enabled && plugin[key].close) {
const close = async () => {
try {
await plugin[key].close()
@ -99,7 +99,7 @@ async function shutdown () {
await Promise.all(plugins)
}
} catch (error) {
log.error('插件关闭失败'.error)
log.error('插件关闭失败', error)
}
if (status.proxy.enabled) {

View File

@ -0,0 +1,87 @@
const lodash = require('lodash')
/**
* 找出 newObj 相对于 oldObj 有差异的部分
*
* @param oldObj
* @param newObj
* @returns {{}|*}
*/
function doDiff (oldObj, newObj) {
if (newObj == null) {
return oldObj
}
// 临时的对象,用于找出被删除的数据
const tempObj = { ...oldObj }
// 删除空项,使差异对象更干净一些,体现出用户自定义内容
deleteNullItems(tempObj)
// 保存差异的对象
const diffObj = {}
// 读取新对象,并解析
for (const key in newObj) {
const newValue = newObj[key]
const oldValue = oldObj[key]
// 新值不为空,旧值为空时,直接取新值
if (newValue != null && oldValue == null) {
diffObj[key] = newValue
continue
}
// 新旧值相等时,忽略
if (lodash.isEqual(newValue, oldValue)) {
delete tempObj[key]
continue
}
// 新的值为数组时,直接取新值
if (lodash.isArray(newValue)) {
diffObj[key] = newValue
delete tempObj[key]
continue
}
// 新的值为对象时,递归合并
if (lodash.isObject(newValue)) {
diffObj[key] = doDiff(oldValue, newValue)
delete tempObj[key]
continue
}
// 基础类型,直接覆盖
delete tempObj[key]
diffObj[key] = newValue
}
// tempObj 里面剩下的是被删掉的数据
lodash.forEach(tempObj, (oldValue, key) => {
// 将被删除的属性设置为null目的是为了merge时将被删掉的对象设置为null达到删除的目的
diffObj[key] = null
})
return diffObj
}
function deleteNullItems (target) {
lodash.forEach(target, (item, key) => {
if (item == null) {
delete target[key]
}
if (lodash.isObject(item)) {
deleteNullItems(item)
}
})
}
module.exports = {
doMerge: function (oldObj, newObj) {
return lodash.mergeWith(oldObj, newObj, function (objValue, srcValue) {
if (lodash.isArray(objValue)) {
return srcValue
}
})
},
doDiff,
deleteNullItems
}

View File

@ -10,7 +10,7 @@ module.exports = {
}
},
targets: {
'github.com': true,
'*github*.com': true,
'*wikimedia.org': true,
'v2ex.com': true,
'*azureedge.net': true,
@ -30,9 +30,12 @@ module.exports = {
'*telegram.org': true,
'*amazon.com': true,
'*googleapis.com': true,
'*.google-analytics.com': true,
'*cloudflareinsights.com': true,
'*.intlify.dev': true,
'*segment.io': true
'*segment.io': true,
'*.shields.io': true,
'*.jsdelivr.net': true
},
pac: {
enabled: true,

View File

@ -54,7 +54,187 @@ module.exports = {
name: '系统代理',
use: 'local',
other: [],
setEnv: false
setEnv: false,
excludeIpList: {
// region 常用国内可访问域名
// 中国大陆
'*.cn': true,
'cn.*': true,
'*china*': true,
// 系统之家
'*.xitongzhijia.net': true,
// CSDN
'*.csdn.net': true,
// 百度
'*.baidu.com': true,
'*.baiducontent.com': true,
'*.bdimg.com': true,
'*.bdstatic.com': true,
'*.bdydns.com': true,
// 腾讯
'*.tencent.com': true,
'*.qq.com': true,
'*.weixin.com': true,
'*.weixinbridge.com': true,
'*.wechat.com': true,
'*.idqqimg.com': true,
'*.gtimg.com': true,
'*.qpic.com': true,
'*.qlogo.com': true,
'*.myapp.com': true,
'*.myqcloud.com': true,
// 阿里
'*.aliyun.com': true,
'*.alipay.com': true,
'*.taobao.com': true,
'*.tmall.com': true,
'*.alipayobjects.com': true,
'*.dingtalk.com': true,
'*.mmstat.com': true,
'*.alicdn.com': true,
'*.hdslb.com': true,
// Gitee
'gitee.com': true,
'*.gitee.com': true,
'*.gitee.io': true,
'*.giteeusercontent.com': true,
// Mozilla Firefox
'*.mozilla.org': true,
'*.mozilla.com': true,
'*.mozilla.net': true,
'*.firefox.com': true,
'*.firefox.org': true,
'*.mozillademos.org': true,
'*.mozillians.org': true,
'*.mozillians.net': true,
'*.mozillians.com': true,
// OSS
'*.sonatype.org': true,
// Maven镜像
'*.maven.org': true,
// Maven Repository
'*.mvnrepository.com': true,
'challenges.cloudflare.com': true, // 在访问 mvnrepository.com 的人机校验时使用,国内可直接访问,所以不需要代理,代理了反而变慢了。
// 苹果
'*.apple.com': true,
'*.icloud.com': true,
// 微软
'*.microsoft.com': true,
'*.windows.com': true,
'*.office.com': true,
'*.office.net': true,
'*.live.com': true,
'*.msn.com': true,
// WPS
'*.wps.com': true,
// 奇虎
'*.qihoo.com': true,
'*.qihucdn.com': true,
// 360
'*.360.com': true,
'*.360safe.com': true,
'*.360buyimg.com': true,
'*.360buy.com': true,
// 京东
'*.jd.com': true,
'*.jcloud.com': true,
'*.jcloudcs.com': true,
'*.jcloudcache.com': true,
'*.jcloudcdn.com': true,
'*.jcloudlb.com': true,
// 哔哩哔哩
'*.bilibili.com': true,
'*.bilivideo.com.com': true,
'*.biliapi.net': true,
// 移动
'*.10086.com': true,
'*.10086cloud.com': true,
// 移动139邮箱
'*.139.com': true,
// 迅雷
'*.xunlei.com': true,
// 网站ICP备案查询
'*.icpapi.com': true,
// AGE动漫
'*.agedm.*': true,
'*.zhimg.com': true,
'*.bdxiguaimg.com': true,
'*.toutiaoimg.com': true,
'*.bytecdntp.com': true,
'*.bytegoofy.com': true,
'*.toutiao.com': true,
'*.toutiaovod.com': true,
'*.aliyuncs.com': true,
'*.127.net': true,
'43.240.74.134': true,
// ZzzFun
'*.zzzfun.one': true,
'*.zzzfun.vip': true,
// 必应
'*.bing.com': true,
// 我的个人域名
'*.easyj.icu': true,
// 未知公司
'*.bcebos.com': true,
'icannwiki.org': true,
'*.icannwiki.org': true,
'*.sectigo.com': true,
'*.pingdom.net': true,
// endregion
// 本地地址,无需代理
localhost: true,
'localhost.*': true, // 部分VPN会在host中添加这种格式的域名指向127.0.0.1,所以也排除掉
'127.*': true,
'test.*': true, // 本地开发时,测试用的虚拟域名格式,无需代理
// 服务器端常用地址,无需代理
'10.*': true,
'172.16.*': true,
'172.17.*': true,
'172.18.*': true,
'172.19.*': true,
'172.20.*': true,
'172.21.*': true,
'172.22.*': true,
'172.23.*': true,
'172.24.*': true,
'172.25.*': true,
'172.26.*': true,
'172.27.*': true,
'172.28.*': true,
'172.29.*': true,
'172.30.*': true,
'172.31.*': true,
// 局域网地址,无需代理
'192.168.*': true
}
},
status: {
enabled: false,

View File

@ -69,9 +69,10 @@ const serverApi = {
serverConfig.plugin = allConfig.plugin
// fireStatus('ing') // 启动中
const basePath = serverConfig.setting.userBasePath
const runningConfig = path.join(basePath, '/running.json')
fs.writeFileSync(runningConfig, JSON5.stringify(serverConfig, null, 2))
const serverProcess = fork(mitmproxyPath, [runningConfig])
const runningConfigPath = path.join(basePath, '/running.json')
fs.writeFileSync(runningConfigPath, JSON.stringify(serverConfig, null, '\t'))
log.info('保存运行时配置文件成功:', runningConfigPath)
const serverProcess = fork(mitmproxyPath, [runningConfigPath])
server = {
id: serverProcess.pid,
process: serverProcess,
@ -106,7 +107,7 @@ const serverApi = {
event.fire('speed', msg.event)
}
})
return { port: runningConfig.port }
return { port: serverConfig.port }
},
async kill () {
if (server) {

View File

@ -6,38 +6,10 @@ const Registry = require('winreg')
const execute = Shell.execute
const execFile = Shell.execFile
const refreshInternetPs = require('./refresh-internet')
const PowerShell = require('node-powershell')
const log = require('../../../utils/util.log')
const path = require('path')
const childProcess = require('child_process')
const util = require('util')
const fs = require('fs')
const _exec = util.promisify(childProcess.exec)
const extraPath = require('../extra-path/index')
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.*'
]
// '<-loopback>'
let config = null
async function _winUnsetProxy (exec, setEnv) {
// eslint-disable-next-line no-constant-condition
@ -53,24 +25,31 @@ async function _winUnsetProxy (exec, setEnv) {
regKey.get('HTTPS_PROXY', (err) => {
if (!err) {
regKey.remove('HTTPS_PROXY', async (err) => {
log.info('删除环境变量https_proxy', err)
log.warn('删除环境变量https_proxy失败:', err)
await exec('setx DS_REFRESH "1"')
})
}
})
} catch (e) {
log.error(e)
log.error('启动系统代理失败:', e)
}
}
async function _winSetProxy (exec, ip, port, setEnv) {
let lanIpStr = ''
for (const string of _lanIP) {
lanIpStr += string + ';'
// 延迟加载config
if (config == null) {
config = require('../../../config.js')
}
// http=127.0.0.1:8888;https=127.0.0.1:8888 考虑这种方式
let excludeIpStr = ''
for (const ip in config.get().proxy.excludeIpList) {
if (config.get().proxy.excludeIpList[ip] === true) {
excludeIpStr += ip + ';'
}
}
const proxyPath = extraPath.getProxyExePath()
await execFile(proxyPath, ['global', `http=http://${ip}:${port};https=http://${ip}:${port}`, lanIpStr])
await execFile(proxyPath, ['global', `http=http://${ip}:${port};https=http://${ip}:${port}`, excludeIpStr])
if (setEnv) {
log.info('同时设置 https_proxy')
@ -96,8 +75,7 @@ const executor = {
return _winUnsetProxy(exec, setEnv)
} else {
// 设置代理
log.info('设置代理', ip, port, setEnv)
log.info('设置代理:', ip, port, setEnv)
return _winSetProxy(exec, ip, port, setEnv)
}
},

View File

@ -3,9 +3,11 @@ const server = require('@docmirror/mitmproxy')
const JSON5 = require('json5')
const path = require('path')
const home = process.env.USER_HOME || process.env.HOME || 'C:/Users/Administrator/'
let configPath = path.join(home, '.dev-sidecar/running.json')
let configPath
if (process.argv && process.argv.length > 3) {
configPath = process.argv[2]
} else {
configPath = path.join(home, '.dev-sidecar/running.json')
}
const fs = require('fs')

View File

@ -0,0 +1,88 @@
const lodash = require('lodash')
const mergeApi = require('../src/merge.js')
// 默认配置
const defConfig = {
a: {
aa: { value: 1 },
bb: { value: 2 }
},
b: { c: 2 },
c: 1,
d: [1, 2, 3],
e: {
aa: 2,
ee: 5
},
f: {
x: 1
},
g: [1, 2],
h: null,
i: null
}
// 自定义配置
const customConfig = {
a: {
bb: { value: 2 },
cc: { value: 3 }
},
b: { c: 2 },
c: null,
d: [1, 2, 3, 4],
e: {
aa: 2,
ee: 5,
ff: 6
},
f: {},
g: [1, 2],
h: null
}
// doDiff
const doDiffResult = mergeApi.doDiff(defConfig, customConfig)
console.log('doDiffResult:', JSON.stringify(doDiffResult, null, 2))
console.log('\r')
// 校验doDiff结果
const doDiffExpect = {
a: {
aa: null,
cc: { value: 3 }
},
c: null,
d: [1, 2, 3, 4],
e: {
ff: 6
},
f: {
x: null
}
}
console.log('check diff result:', lodash.isEqual(doDiffResult, doDiffExpect))
console.log('\r')
// doMerge
const doMergeResult = mergeApi.doMerge(defConfig, doDiffResult)
// delete null item
mergeApi.deleteNullItems(doMergeResult)
console.log('running:', JSON.stringify(doMergeResult, null, 2))
// 校验doMerge结果
const doMergeExpect = {
a: {
bb: { value: 2 },
cc: { value: 3 }
},
b: { c: 2 },
d: [1, 2, 3, 4],
e: {
aa: 2,
ee: 5,
ff: 6
},
f: {},
g: [1, 2]
}
console.log('check merge result:', lodash.isEqual(doMergeResult, doMergeExpect))
console.log('\r')

View File

@ -64,7 +64,8 @@ const localApi = {
},
save (setting = {}) {
const settingPath = _getSettingsPath()
fs.writeFileSync(settingPath, JSON5.stringify(setting, null, 2))
fs.writeFileSync(settingPath, JSON.stringify(setting, null, '\t'))
log.info('保存setting配置文件成功', settingPath)
}
},
/**
@ -108,7 +109,7 @@ function _getSettingsPath () {
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir)
}
return dir + '/setting.json5'
return dir + '/setting.json'
}
function invoke (api, param) {

View File

@ -63,14 +63,10 @@ function install (app, api) {
function openGithubUrl () {
api.ipc.openExternal('https://github.com/docmirror/dev-sidecar/releases')
}
function openGiteeUrl () {
api.ipc.openExternal('https://gitee.com/docmirror/dev-sidecar/releases')
}
return <div>
<div>请前往github或gitee项目release页面下载新版本手动安装</div>
<div>请前往github项目release页面下载新版本手动安装</div>
<ol>
<li><a onClick={openGithubUrl}>Github release</a></li>
<li><a onClick={openGiteeUrl}>Gitee release</a></li>
</ol>
</div>
}

View File

@ -26,8 +26,8 @@ export function apiInit (app) {
},
invoke,
send,
openExternal (href) {
shell.openExternal(href)
async openExternal (href) {
await shell.openExternal(href)
},
openPath (file) {
shell.openPath(file)

View File

@ -190,7 +190,7 @@ export default {
},
doSave () {
return api.config.save(this.targetConfig).then(ret => {
this.$emit('change', ret)
this.$emit('change', ret.diffConfig)
})
},
deleteDnsMapping (item, index) {

View File

@ -13,7 +13,7 @@
<template slot="title">
{{title}}
<a-button type="primary" style="float:right" @click="doSetup()"></a-button>
<a-button style="float:right;margin-right:10px;" @click="openExternal('https://gitee.com/docmirror/dev-sidecar/blob/master/doc/caroot.md')"></a-button>
<a-button style="float:right;margin-right:10px;" @click="openExternal('https://github.com/docmirror/dev-sidecar/blob/master/doc/caroot.md')"></a-button>
</template>
<div>
<b>本应用在非安全模式下必须安装和信任CA根证书</b>该证书是应用启动时本地随机生成的<br/>
@ -73,8 +73,8 @@ export default {
}
},
methods: {
openExternal (url) {
this.$api.ipc.openExternal(url)
async openExternal (url) {
await this.$api.ipc.openExternal(url)
},
afterVisibleChange (val) {
},

View File

@ -7,6 +7,7 @@ export default {
},
data () {
return {
key: undefined,
config: undefined,
status: {},
labelCol: { span: 4 },
@ -31,16 +32,19 @@ export default {
this.status = this.$status
const config = await this.$api.config.reload()
this.$set(this, 'config', config)
this.setConfig(config)
this.systemPlatform = await this.$api.info.getSystemPlatform()
console.log('config', this.config, this.systemPlatform)
// eslint-disable-next-line no-debugger
this.printConfig()
if (this.ready) {
return this.ready(this.config)
}
},
async apply () {
if (this.applyLoading === true) {
return
}
this.applyLoading = true
await this.applyBefore()
await this.saveConfig()
@ -71,8 +75,11 @@ export default {
})
},
saveConfig () {
return this.$api.config.save(this.config).then(() => {
return this.$api.config.save(this.config).then((ret) => {
this.$message.info('设置已保存')
this.setConfig(ret.allConfig)
this.printConfig('after saveConfig(), ')
return ret
})
},
getConfig (key) {
@ -82,6 +89,12 @@ export default {
}
return value
},
setConfig (newConfig) {
this.$set(this, 'config', newConfig)
},
printConfig (prefix = '') {
console.log(`${prefix}${this.key} page config:`, this.config, this.systemPlatform)
},
getStatus (key) {
const value = lodash.get(this.status, key)
if (value == null) {

View File

@ -95,8 +95,6 @@
<div>如果它解决了你的问题请不要吝啬你的star哟点这里
<a-icon style="margin-right:10px;" type="arrow-right" theme="outlined"/>
</div>
<a @click="openExternal('https://gitee.com/docmirror/dev-sidecar')"><img
src='https://gitee.com/docmirror/dev-sidecar/badge/star.svg?theme=dark' alt='star'/></a>
<a @click="openExternal('https://github.com/docmirror/dev-sidecar')"><img alt="GitHub stars"
src="https://img.shields.io/github/stars/docmirror/dev-sidecar?logo=github"></a>
</div>
@ -335,8 +333,8 @@ export default {
doCheckUpdate (fromUser = true) {
this.$api.update.checkForUpdate(fromUser)
},
openExternal (url) {
this.$api.ipc.openExternal(url)
async openExternal (url) {
await this.$api.ipc.openExternal(url)
},
onShutdownTipClose (e) {
this.$confirm({

View File

@ -105,8 +105,8 @@ export default {
mounted () {
},
methods: {
openExternal (url) {
this.$api.ipc.openExternal(url)
async openExternal (url) {
await this.$api.ipc.openExternal(url)
},
async applyAfter () {
if (this.status.server.enabled) {

View File

@ -17,6 +17,9 @@
<a-tag v-else color="red">
当前未启动
</a-tag>
<div class="form-help">
<a @click="openExternal('https://github.com/docmirror/dev-sidecar/blob/master/doc/recover.md')"></a>
</div>
</a-form-item>
<a-form-item v-if="isWindows()" label="设置环境变量" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-checkbox v-model="config.proxy.setEnv" >
@ -29,6 +32,26 @@
<a-button @click="loopbackVisible=true"></a-button>
<div class="form-help">解决OneNoteMicrosoftStoreOutlook等UWP应用开启代理后无法访问网络的问题</div>
</a-form-item>
<a-form-item label="排除地址配置" :label-col="labelCol" :wrapper-col="wrapperCol">
<div>
<a-row :gutter="10">
<a-col :span="22">
<span>访问的域名或IP符合下列格式时将跳过系统代理</span>
</a-col>
<a-col :span="2">
<a-button type="primary" icon="plus" @click="addExcludeIp()"/>
</a-col>
</a-row>
<a-row :gutter="10" v-for="(item,index) of excludeIpList" :key='index'>
<a-col :span="22">
<a-input :disabled="item.value === false" v-model="item.key"></a-input>
</a-col>
<a-col :span="2">
<a-button type="danger" icon="minus" @click="delExcludeIp(item,index)"/>
</a-col>
</a-row>
</div>
</a-form-item>
</div>
<template slot="footer">
<div class="footer-bar">
@ -54,7 +77,7 @@
<div>1此设置用于解决OneNoteMicrosoftStoreOutlook等UWP应用无法访问网络的问题</div>
<div>2点击右上方按钮打开EnableLoopback然后按下图所示操作即可</div>
<div>3注意此操作需要<b style="color:red">DevSidecar以管理员身份启动</b>才能打开下面的EnableLoopback设置界面</div>
<img style="margin-top:20px;border:1px solid #eee" width="80%" src="loopback.png" />
<img style="margin-top:20px;border:1px solid #eee" width="80%" src="loopback.png"/>
</div>
</a-drawer>
@ -70,7 +93,8 @@ export default {
data () {
return {
key: 'proxy',
loopbackVisible: false
loopbackVisible: false,
excludeIpList: []
}
},
async created () {
@ -78,6 +102,15 @@ export default {
mounted () {
},
methods: {
async openExternal (url) {
await this.$api.ipc.openExternal(url)
},
ready () {
this.initExcludeIpList()
},
async applyBefore () {
this.submitExcludeIpList()
},
async applyAfter () {
await this.$api.proxy.restart()
},
@ -91,6 +124,33 @@ export default {
}
this.$message.error('打开失败:' + e.message)
}
},
getProxyConfig () {
return this.config.proxy
},
initExcludeIpList () {
this.excludeIpList = []
for (const key in this.config.proxy.excludeIpList) {
const value = this.config.proxy.excludeIpList[key]
this.excludeIpList.push({
key, value
})
}
},
addExcludeIp () {
this.excludeIpList.unshift({ key: '', value: true })
},
delExcludeIp (item, index) {
this.excludeIpList.splice(index, 1)
},
submitExcludeIpList () {
const excludeIpList = {}
for (const item of this.excludeIpList) {
if (item.key) {
excludeIpList[item.key] = item.value
}
}
this.config.proxy.excludeIpList = excludeIpList
}
}
}

View File

@ -12,7 +12,7 @@
本应用开机自启
</a-checkbox>
<div class="form-help">
windows下建议开启开机自启<a @click="openExternal('https://gitee.com/docmirror/dev-sidecar/blob/master/doc/recover.md')"></a>
windows下建议开启开机自启<a @click="openExternal('https://github.com/docmirror/dev-sidecar/blob/master/doc/recover.md')"></a>
</div>
</a-form-item>
<a-form-item v-if="systemPlatform ==='mac'" label="隐藏Dock图标" :label-col="labelCol" :wrapper-col="wrapperCol">
@ -35,6 +35,13 @@
<a-form-item label="远程配置地址" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-input v-model="config.app.remoteConfig.url"></a-input>
</a-form-item>
<a-form-item label="重载远程配置" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-button :disabled="config.app.remoteConfig.enabled === false" :loading="reloadLoading" icon="sync" @click="reloadRemoteConfig()"></a-button>
<div class="form-help">
注意部分远程配置文件所在站点修改内容后可能需要等待一段时间才能生效
<br/>如果重载远程配置后发现下载的还是修改前的内容请稍等片刻再重试
</div>
</a-form-item>
<a-form-item label="首页提示" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-radio-group v-model="config.app.showShutdownTip"
default-value="true" button-style="solid">
@ -84,7 +91,8 @@ export default {
mixins: [Plugin],
data () {
return {
key: 'app'
key: 'app',
reloadLoading: false
}
},
created () {
@ -93,16 +101,55 @@ export default {
mounted () {
},
methods: {
openExternal (url) {
this.$api.ipc.openExternal(url)
async openExternal (url) {
await this.$api.ipc.openExternal(url)
},
onAutoStartChange () {
this.$api.autoStart.enabled(this.config.app.autoStart.enabled)
this.saveConfig()
},
onRemoteConfigEnabledChange () {
this.saveConfig()
this.$message.info('请重启加速服务')
async reloadAndRestart () {
this.$api.config.reload()
if (this.status.server.enabled || this.status.proxy.enabled) {
await this.$api.proxy.restart()
await this.$api.server.restart()
this.$message.info('代理服务和系统代理重启成功')
} else {
this.$message.info('代理服务和系统代理未启动,无需重启')
}
},
async onRemoteConfigEnabledChange () {
await this.saveConfig()
if (this.config.app.remoteConfig.enabled === true) {
this.reloadLoading = true
this.$message.info('开始下载远程配置')
await this.$api.config.downloadRemoteConfig()
this.$message.info('下载远程配置成功,开始重启代理服务和系统代理')
await this.reloadAndRestart()
this.reloadLoading = false
} else {
this.$message.info('开始重启代理服务和系统代理')
await this.reloadAndRestart()
}
},
async reloadRemoteConfig () {
this.reloadLoading = true
const remoteConfig = {}
await this.$api.config.readRemoteConfigStr().then((ret) => { remoteConfig.old = ret })
await this.$api.config.downloadRemoteConfig()
await this.$api.config.readRemoteConfigStr().then((ret) => { remoteConfig.new = ret })
if (remoteConfig.old === remoteConfig.new) {
this.$message.info('远程配置没有变化,不做任何处理。')
this.$message.info('如果您确实修改了远程配置,请稍等片刻再重试!')
} else {
this.$message.info('获取到了最新的远程配置,开始重启代理服务和系统代理')
await this.reloadAndRestart()
}
this.reloadLoading = false
}
}
}

View File

@ -17,7 +17,11 @@ module.exports = function createRequestHandler (createIntercepts, middlewares, e
const rOptions = commonUtil.getOptionsFormRequest(req, ssl, externalProxy)
rOptions.agent.options.rejectUnauthorized = setting.verifySsl
if (rOptions.agent) {
rOptions.agent.options.rejectUnauthorized = setting.verifySsl
} else if (rOptions.agent !== false) {
log.error('rOptions.agent 的值有问题:', rOptions)
}
if (rOptions.headers.connection === 'close') {
req.socket.setKeepAlive(false)

View File

@ -16,6 +16,9 @@ module.exports = (config) => {
if (!setting.script.dirAbsolutePath) {
setting.script.dirAbsolutePath = path.join(setting.rootDir, setting.script.defaultDir)
}
if (setting.verifySsl !== false) {
setting.verifySsl = true
}
const overwallConfig = serverConfig.plugin.overwall
if (!overwallConfig.pac.pacFileAbsolutePath) {

View File

@ -0,0 +1,5 @@
cd ../
npm install cnpm -g --registry=https://registry.npm.taobao.org
cnpm install lerna@6 -g
cnpm install phantomjs -g

View File

@ -0,0 +1,3 @@
cd ../
lerna bootstrap

View File

@ -0,0 +1,3 @@
cd ../packages/gui
npm run electron

View File

@ -0,0 +1,3 @@
cd ../packages/gui
npm run electron:build

View File

@ -1,57 +0,0 @@
import lodash from "lodash";
const defConfig = {a:{aa:1,bb:2},b:{c:2},d:[1,2,3],e:{ee:1,aa:2}}
const newConfig = {a:{aa:1,bb:2},d:[5],e:{bb:2,ee:2,aa:2}}
const result = { d: [ 5 ],e:{ee:2} }
const load = {a:1,d:[5,1,2,3]}
const DELETE = '____DELETE____'
// lodash.mergeWith(defConfig,newConfig, (objValue, srcValue, key, object, source, stack) => {
// console.log('stack', stack,'key',key)
//
// if (lodash.isArray(srcValue)) {
// return srcValue
// }
// if(lodash.isEqual(objValue,srcValue)){
// //如何删除
// return DELETE
// }
// })
function doMerge (defObj, newObj) {
const defObj2 = { ...defObj }
const newObj2 = {}
lodash.forEach(newObj,(newValue,key)=>{
// const newValue = newObj[key]
const defValue = defObj[key]
if (lodash.isEqual(newValue, defValue)) {
delete defObj2[key]
return
}
if (lodash.isArray(newValue)) {
delete defObj2[key]
newObj2[key] = newValue
return
}
if (lodash.isObject(newValue)) {
newObj2[key] = doMerge(defValue, newValue)
delete defObj2[key]
} else {
// 基础类型,直接覆盖
delete defObj2[key]
newObj2[key] = newValue
}
})
// defObj 里面剩下的是被删掉的
lodash.forEach(defObj2, (defValue, key) => {
newObj2[key] = null
})
return newObj2
}
console.log(doMerge(defConfig,newConfig))