diff --git a/README.md b/README.md index 8ef5e3d2..454451d5 100644 --- a/README.md +++ b/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 开启后 +![](./doc/avatar2.png) +![](./doc/avatar1.png) + + ## 感谢 本项目使用lerna包管理工具 diff --git a/doc/avatar1.png b/doc/avatar1.png new file mode 100644 index 00000000..623aa936 Binary files /dev/null and b/doc/avatar1.png differ diff --git a/doc/avatar2.png b/doc/avatar2.png new file mode 100644 index 00000000..680f09bc Binary files /dev/null and b/doc/avatar2.png differ diff --git a/packages/core/package.json b/packages/core/package.json index 9bd8bcf3..49a7e49f 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -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, diff --git a/packages/core/src/config/index.js b/packages/core/src/config/index.js index 9c87c962..071615f0 100644 --- a/packages/core/src/config/index.js +++ b/packages/core/src/config/index.js @@ -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' } } }, diff --git a/packages/gui/public/index.html b/packages/gui/public/index.html index 60adb88e..41cb07a2 100644 --- a/packages/gui/public/index.html +++ b/packages/gui/public/index.html @@ -8,9 +8,6 @@ <%= htmlWebpackPlugin.options.title %> -
diff --git a/packages/gui/src/background.js b/packages/gui/src/background.js index 20176602..a43f738b 100644 --- a/packages/gui/src/background.js +++ b/packages/gui/src/background.js @@ -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) diff --git a/packages/gui/src/bridge/index.js b/packages/gui/src/bridge/index.js index 4b2088c3..fae19b92 100644 --- a/packages/gui/src/bridge/index.js +++ b/packages/gui/src/bridge/index.js @@ -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} + */ startup () { return DevSidecar.api.startup({ mitmproxyPath }) }, server: { + /** + * 启动代理服务 + * @returns {Promise<{port: *}>} + */ start () { return DevSidecar.api.server.start({ mitmproxyPath }) }, + /** + * 重启代理服务 + * @returns {Promise} + */ 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 diff --git a/packages/gui/src/bridge/update-handle.js b/packages/gui/src/bridge/update-handle.js index a8d9062e..30f8415a 100644 --- a/packages/gui/src/bridge/update-handle.js +++ b/packages/gui/src/bridge/update-handle.js @@ -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 diff --git a/packages/gui/src/main.js b/packages/gui/src/main.js index 19ea4f79..e536112e 100644 --- a/packages/gui/src/main.js +++ b/packages/gui/src/main.js @@ -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 diff --git a/packages/gui/src/view/api.js b/packages/gui/src/view/api.js index 9271d973..03699a54 100644 --- a/packages/gui/src/view/api.js +++ b/packages/gui/src/view/api.js @@ -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) diff --git a/packages/gui/src/view/index.js b/packages/gui/src/view/index.js index 436bbdde..96d709d7 100644 --- a/packages/gui/src/view/index.js +++ b/packages/gui/src/view/index.js @@ -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) } } diff --git a/packages/gui/src/view/mixins/plugin.js b/packages/gui/src/view/mixins/plugin.js index b5597c7d..74aa0314 100644 --- a/packages/gui/src/view/mixins/plugin.js +++ b/packages/gui/src/view/mixins/plugin.js @@ -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 () { diff --git a/packages/gui/src/view/event.js b/packages/gui/src/view/modules/error/index.js similarity index 64% rename from packages/gui/src/view/event.js rename to packages/gui/src/view/modules/error/index.js index a11f8a54..d8fd718c 100644 --- a/packages/gui/src/view/event.js +++ b/packages/gui/src/view/modules/error/index.js @@ -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 +} diff --git a/packages/gui/src/view/modules/index.js b/packages/gui/src/view/modules/index.js new file mode 100644 index 00000000..522310ad --- /dev/null +++ b/packages/gui/src/view/modules/index.js @@ -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) + } +} diff --git a/packages/gui/src/view/modules/update/index.js b/packages/gui/src/view/modules/update/index.js new file mode 100644 index 00000000..28f6fed4 --- /dev/null +++ b/packages/gui/src/view/modules/update/index.js @@ -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 =>

{value.version}更新内容:

{value.releaseNotes}
, + 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 =>

{value.version}更新内容:

{value.releaseNotes}
, + onOk () { + console.log('OK') + api.update.doUpdateNow() + }, + onCancel () { + console.log('Cancel') + } + }) + } +} + +export default { + install +} diff --git a/packages/gui/src/view/pages/index.vue b/packages/gui/src/view/pages/index.vue index 6ff938b8..9c3c9aeb 100644 --- a/packages/gui/src/view/pages/index.vue +++ b/packages/gui/src/view/pages/index.vue @@ -4,10 +4,13 @@ 给开发者的辅助工具 安装根证书 + + 检查更新 + -
+
@@ -38,8 +41,6 @@