# 新特性:
1. 系统代理中的排除列表,可配置化;可在界面中配置,也可在远程配置中配置 # 问题修复: 1. 空指针异常导致插件关闭失败的问题修复 2. 偶发的空指针异常导致代理请求失败,原因不明,暂时规避掉 # 配置调整: 1. 添加几项targets配置,优化1项配置 2. 添加几项拦截配置 3. 添加很多项系统代理排除项,并调整白名单配置 4. 优化dns配置 5. `.gitignore` 中,排除掉 `package-lock.json` # 功能优化: 1. 远程配置内容格式不正确时,不保存它 2. 部分日志优化 3. 封装 merge.js 的 doDiff 和 doMarge 两个方法,方便使用和测试,同时添加测试用例 `mergeTest.js`,删除老的 `mergeTest.mjs`;doDiff优化过,使 config.json5 的内容更准确的体现用户自定义配置 4. 打开链接的方法,全部改为异步 # 文档: 1. 移除部分 `gitee仓库` 相关的内容,因为gitee的仓库被禁了,部分gitee地址改为github地址 2. 代码贡献说明中,添加环境准备相关说明;同时添加4个bat脚本文件方便windows用户快速贡献代码pull/274/head
parent
0ce1a88897
commit
d0096d209c
|
@ -6,4 +6,5 @@ gen
|
|||
node_modules/
|
||||
*.lock
|
||||
*.log
|
||||
pnpm-lock.yaml
|
||||
pnpm-lock.yaml
|
||||
package-lock.json
|
101
README.md
101
README.md
|
@ -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 加速
|
||||
|
||||
#### 1)git 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/) 这个很容易超限
|
||||
#### 2)github.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系统使用时,首页的系统代理开关无法打开
|
||||
#### 1)Mac系统使用时,首页的系统代理开关无法打开
|
||||
出现这个问题可能是没有开启系统代理命令的执行权限
|
||||
```
|
||||
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: 请确认证书已正确安装在“信任的根证书颁发机构”下
|
||||
#### 1)windows: 请确认证书已正确安装在“信任的根证书颁发机构”下
|
||||
|
||||
#### 3.2 mac: 请确认证书已经被安装并已经设置信任。
|
||||
#### 2)mac: 请确认证书已经被安装并已经设置信任。
|
||||
|
||||
#### 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
|
||||
|
||||
|
||||
|
|
|
@ -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
|
@ -6,22 +6,14 @@ 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
|
||||
}
|
||||
|
@ -40,46 +32,6 @@ function _getConfigPath () {
|
|||
return dir + '/config.json5'
|
||||
}
|
||||
|
||||
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,19 @@ const configApi = {
|
|||
return
|
||||
}
|
||||
if (response && response.statusCode === 200) {
|
||||
fs.writeFileSync(_getRemoteSavePath(), body)
|
||||
// 尝试解析远程配置,如果解析失败,则不保存它
|
||||
let remoteConfig
|
||||
try {
|
||||
remoteConfig = JSON5.parse(body)
|
||||
} catch (e) {
|
||||
log.error('远程配置内容格式不正确:', body)
|
||||
remoteConfig = null
|
||||
}
|
||||
|
||||
if (remoteConfig != null) {
|
||||
fs.writeFileSync(_getRemoteSavePath(), body)
|
||||
}
|
||||
|
||||
resolve()
|
||||
} else {
|
||||
const message = '下载远程配置失败:' + response.message + ',code:' + response.statusCode
|
||||
|
@ -128,13 +92,15 @@ 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 {}
|
||||
|
@ -142,34 +108,39 @@ const configApi = {
|
|||
/**
|
||||
* 保存自定义的 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())
|
||||
}
|
||||
const saveConfig = doMerge(defConfig, newConfig)
|
||||
fs.writeFileSync(_getConfigPath(), JSON5.stringify(saveConfig, null, 2))
|
||||
|
||||
// 计算新配置与默认配置(启用远程配置时,含远程配置)的差异,并保存到 config.json5 中
|
||||
const diffConfig = mergeApi.doDiff(defConfig, newConfig)
|
||||
fs.writeFileSync(_getConfigPath(), JSON5.stringify(diffConfig, null, 2))
|
||||
configApi.reload()
|
||||
return saveConfig
|
||||
return diffConfig
|
||||
},
|
||||
doMerge,
|
||||
doMerge: mergeApi.doMerge,
|
||||
doDiff: mergeApi.doDiff,
|
||||
/**
|
||||
* 读取后合并配置
|
||||
* 读取 config.json5 后,合并配置
|
||||
* @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) {
|
||||
|
@ -181,17 +152,13 @@ const configApi = {
|
|||
if (newConfig == null) {
|
||||
return
|
||||
}
|
||||
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
|
||||
|
|
|
@ -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,
|
||||
'qq.com': true,
|
||||
'*.qq.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
|
||||
'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']
|
||||
}
|
||||
|
|
|
@ -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,46 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
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
|
||||
"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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -54,7 +54,108 @@ module.exports = {
|
|||
name: '系统代理',
|
||||
use: 'local',
|
||||
other: [],
|
||||
setEnv: false
|
||||
setEnv: false,
|
||||
excludeIpList: [
|
||||
// region 中国大陆,可直接访问,无需代理
|
||||
|
||||
// 中国大陆域名,大部分可直接访问,无需代理
|
||||
'*.cn',
|
||||
'cn.*',
|
||||
|
||||
// CSDN
|
||||
'*.csdn.net',
|
||||
|
||||
// 百度
|
||||
'*.baidu.com',
|
||||
|
||||
// 腾讯
|
||||
'*.tencent.com',
|
||||
'*.qq.com',
|
||||
'*.weixin.com',
|
||||
'*.wechat.com',
|
||||
|
||||
// 阿里
|
||||
'*.alipay.com',
|
||||
'*.taobao.com',
|
||||
'*.tmall.com',
|
||||
'*.aliyun.com',
|
||||
'*.dingtalk.com', // 不排除会导致钉钉的团队文档打不开(原因未知)
|
||||
|
||||
// Gitee
|
||||
'gitee.com',
|
||||
'*.gitee.com',
|
||||
'*.gitee.io',
|
||||
|
||||
// OSS
|
||||
'*.sonatype.org',
|
||||
// Maven镜像
|
||||
'*.maven.org',
|
||||
// Maven Repository
|
||||
'*.mvnrepository.com',
|
||||
'challenges.cloudflare.com', // 在访问 mvnrepository.com 的人机校验时使用,国内可直接访问,所以不需要代理,代理了反而变慢了。
|
||||
|
||||
// 苹果
|
||||
'*.apple.com',
|
||||
'*.icloud.com',
|
||||
|
||||
// 微软
|
||||
'*.microsoft.com',
|
||||
'*.windows.com',
|
||||
'*.office.com',
|
||||
'*.office.net',
|
||||
'*.live.com',
|
||||
'*.msn.com',
|
||||
|
||||
// WPS
|
||||
'*.wps.com',
|
||||
|
||||
// 奇虎
|
||||
'*.qihoo.com',
|
||||
'*.qihucdn.com',
|
||||
// 360
|
||||
'*.360.com',
|
||||
'*.360safe.com',
|
||||
'*.360buyimg.com',
|
||||
'*.360buy.com',
|
||||
|
||||
// 京东
|
||||
'*.jd.com',
|
||||
'*.jcloud.com',
|
||||
'*.jcloudcs.com',
|
||||
'*.jcloudcache.com',
|
||||
'*.jcloudcdn.com',
|
||||
'*.jcloudlb.com',
|
||||
|
||||
// endregion
|
||||
|
||||
// 本地地址,无需代理
|
||||
'localhost',
|
||||
'localhost.*', // 部分VPN会在host中添加这种格式的域名指向127.0.0.1,所以也排除掉
|
||||
'127.*',
|
||||
'test.*', // 本地开发时,测试用的虚拟域名格式,无需代理
|
||||
|
||||
// 服务器端常用地址,无需代理
|
||||
'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.*'
|
||||
]
|
||||
},
|
||||
status: {
|
||||
enabled: false,
|
||||
|
|
|
@ -69,9 +69,9 @@ 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, JSON5.stringify(serverConfig, null, 2))
|
||||
const serverProcess = fork(mitmproxyPath, [runningConfigPath])
|
||||
server = {
|
||||
id: serverProcess.pid,
|
||||
process: serverProcess,
|
||||
|
@ -106,7 +106,7 @@ const serverApi = {
|
|||
event.fire('speed', msg.event)
|
||||
}
|
||||
})
|
||||
return { port: runningConfig.port }
|
||||
return { port: serverConfig.port }
|
||||
},
|
||||
async kill () {
|
||||
if (server) {
|
||||
|
|
|
@ -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
|
||||
|
@ -59,14 +31,23 @@ async function _winUnsetProxy (exec, setEnv) {
|
|||
}
|
||||
})
|
||||
} catch (e) {
|
||||
log.error(e)
|
||||
log.error('启动系统代理失败:', e)
|
||||
}
|
||||
}
|
||||
|
||||
async function _winSetProxy (exec, ip, port, setEnv) {
|
||||
// 延迟加载config
|
||||
if (config == null) {
|
||||
config = require('../../../config.js')
|
||||
}
|
||||
|
||||
let lanIpStr = ''
|
||||
for (const string of _lanIP) {
|
||||
lanIpStr += string + ';'
|
||||
for (const excludeIpPattern of config.get().proxy.excludeIpList) {
|
||||
// 跳过起注释作用的数据
|
||||
if (excludeIpPattern.indexOf('#') >= 0) {
|
||||
continue
|
||||
}
|
||||
lanIpStr += excludeIpPattern + ';'
|
||||
}
|
||||
// http=127.0.0.1:8888;https=127.0.0.1:8888 考虑这种方式
|
||||
const proxyPath = extraPath.getProxyExePath()
|
||||
|
|
|
@ -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')
|
|
@ -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>
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ export function apiInit (app) {
|
|||
},
|
||||
invoke,
|
||||
send,
|
||||
openExternal (href) {
|
||||
async openExternal (href) {
|
||||
shell.openExternal(href)
|
||||
},
|
||||
openPath (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,7 +73,7 @@ export default {
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
openExternal (url) {
|
||||
async openExternal (url) {
|
||||
this.$api.ipc.openExternal(url)
|
||||
},
|
||||
afterVisibleChange (val) {
|
||||
|
|
|
@ -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,7 +333,7 @@ export default {
|
|||
doCheckUpdate (fromUser = true) {
|
||||
this.$api.update.checkForUpdate(fromUser)
|
||||
},
|
||||
openExternal (url) {
|
||||
async openExternal (url) {
|
||||
this.$api.ipc.openExternal(url)
|
||||
},
|
||||
onShutdownTipClose (e) {
|
||||
|
|
|
@ -105,7 +105,7 @@ export default {
|
|||
mounted () {
|
||||
},
|
||||
methods: {
|
||||
openExternal (url) {
|
||||
async openExternal (url) {
|
||||
this.$api.ipc.openExternal(url)
|
||||
},
|
||||
async applyAfter () {
|
||||
|
|
|
@ -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">解决OneNote、MicrosoftStore、Outlook等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 getProxyConfig().excludeIpList" :key='index'>
|
||||
<a-col :span="22">
|
||||
<a-input v-model="getProxyConfig().excludeIpList[index]"></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">
|
||||
|
@ -78,6 +101,9 @@ export default {
|
|||
mounted () {
|
||||
},
|
||||
methods: {
|
||||
async openExternal (url) {
|
||||
this.$api.ipc.openExternal(url)
|
||||
},
|
||||
async applyAfter () {
|
||||
await this.$api.proxy.restart()
|
||||
},
|
||||
|
@ -91,6 +117,15 @@ export default {
|
|||
}
|
||||
this.$message.error('打开失败:' + e.message)
|
||||
}
|
||||
},
|
||||
getProxyConfig () {
|
||||
return this.config.proxy
|
||||
},
|
||||
addExcludeIp () {
|
||||
this.getProxyConfig().excludeIpList.unshift('')
|
||||
},
|
||||
delExcludeIp (item, index) {
|
||||
this.getProxyConfig().excludeIpList.splice(index, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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">
|
||||
|
@ -93,7 +93,7 @@ export default {
|
|||
mounted () {
|
||||
},
|
||||
methods: {
|
||||
openExternal (url) {
|
||||
async openExternal (url) {
|
||||
this.$api.ipc.openExternal(url)
|
||||
},
|
||||
onAutoStartChange () {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
cd ../
|
||||
|
||||
npm install cnpm -g --registry=https://registry.npm.taobao.org
|
||||
cnpm install lerna@6 -g
|
||||
cnpm install phantomjs -g
|
|
@ -0,0 +1,3 @@
|
|||
cd ../
|
||||
|
||||
lerna bootstrap
|
|
@ -0,0 +1,3 @@
|
|||
cd ../packages/gui
|
||||
|
||||
npm run electron
|
|
@ -0,0 +1,3 @@
|
|||
cd ../packages/gui
|
||||
|
||||
npm run electron:build
|
|
@ -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))
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue