├── myModel ├── Version.go ├── 自动更新模块_test.go └── 自动更新模块.go ├── .github ├── releasesText.md └── workflows │ └── publish.yml ├── assets └── image-20240807232923351.png ├── frontend ├── src │ ├── assets │ │ └── main.css │ ├── components │ │ ├── boxs │ │ │ ├── td │ │ │ │ ├── Progress │ │ │ │ │ └── Progress.vue │ │ │ │ ├── Switch │ │ │ │ │ └── Switch.vue │ │ │ │ ├── Button │ │ │ │ │ └── Button.vue │ │ │ │ ├── Link │ │ │ │ │ └── Link.vue │ │ │ │ └── Select │ │ │ │ │ └── Select.vue │ │ │ └── el │ │ │ │ ├── Switch │ │ │ │ └── Switch.vue │ │ │ │ ├── Tooltip │ │ │ │ └── Tooltip.vue │ │ │ │ ├── Button │ │ │ │ └── Button.vue │ │ │ │ ├── ProgressBar │ │ │ │ └── ProgressBar.vue │ │ │ │ ├── FlexLayout │ │ │ │ └── FlexLayout.vue │ │ │ │ ├── TextEdit │ │ │ │ └── TextEdit.vue │ │ │ │ ├── RadioButton │ │ │ │ └── RadioButton.vue │ │ │ │ ├── CheckBox │ │ │ │ └── CheckBox.vue │ │ │ │ ├── Tabs │ │ │ │ └── Tabs.vue │ │ │ │ ├── Table │ │ │ │ └── Table.vue │ │ │ │ ├── Tree │ │ │ │ └── Tree.vue │ │ │ │ ├── ControlButton │ │ │ │ └── ControlButton.vue │ │ │ │ ├── Menu │ │ │ │ └── Menu.vue │ │ │ │ ├── Label │ │ │ │ └── Label.vue │ │ │ │ ├── CustomComponent │ │ │ │ └── CustomComponent.vue │ │ │ │ ├── TabsTW │ │ │ │ └── TabsTW.vue │ │ │ │ └── CommonLayout │ │ │ │ └── CommonLayout.vue │ │ └── RenderDesignComponentPreview.vue │ ├── App.vue │ ├── main.js │ ├── Helper.js │ ├── win │ │ ├── __aux_code.js │ │ ├── __load_data.js │ │ ├── event.js │ │ └── design.json │ └── public.js ├── jsconfig.json ├── index.html ├── README.md ├── wailsjs │ └── go │ │ └── main │ │ ├── App.d.ts │ │ └── App.js ├── package.json └── vite.config.js ├── template.json ├── wails.json ├── README.md ├── .gitignore ├── action ├── config.json ├── run_override_test.go └── run_override.go ├── main.go ├── README.zh-Hans.md ├── app.go ├── go.mod └── go.sum /myModel/Version.go: -------------------------------------------------------------------------------- 1 | package myModel 2 | 3 | var Version = `v0.0.1` 4 | -------------------------------------------------------------------------------- /.github/releasesText.md: -------------------------------------------------------------------------------- 1 | # overrideManager 2 | 3 | 奋斗了{{用了多少时间}},本次更新内容如下: 4 | 5 | {{最新发布信息}} 6 | 7 | {{变更内容}} -------------------------------------------------------------------------------- /assets/image-20240807232923351.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duolabmeng6/overrideManager/HEAD/assets/image-20240807232923351.png -------------------------------------------------------------------------------- /frontend/src/assets/main.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | margin: 0; 4 | padding: 0; 5 | } 6 | * { 7 | -webkit-user-select: none; 8 | } -------------------------------------------------------------------------------- /frontend/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "paths": { 5 | "@/*": ["src/*"] 6 | } 7 | }, 8 | "include": ["src/**/*"] 9 | } 10 | -------------------------------------------------------------------------------- /template.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wails-template-vue-go-easy", 3 | "shortname": "vue", 4 | "author": "duolabmeng6 <1715109585@qq.com>", 5 | "description": "Window visualization project", 6 | "helpurl": "https://github.com/duolabmeng6/wails-template-vue-go-easy" 7 | } -------------------------------------------------------------------------------- /wails.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://wails.io/schemas/config.v2.json", 3 | "name": "overrideManager", 4 | "outputfilename": "overrideManager", 5 | "frontend:install": "npm install", 6 | "frontend:build": "npm run build", 7 | "frontend:dev:watcher": "npm run dev", 8 | "frontend:dev:serverUrl": "auto", 9 | "author": { 10 | "name": "“xxxxxxx”", 11 | "email": "xxxxxxx@qq.com" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /frontend/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | myproject 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /frontend/README.md: -------------------------------------------------------------------------------- 1 | # Vue 3 + Vite 2 | 3 | This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 ` 20 | -------------------------------------------------------------------------------- /frontend/src/components/boxs/el/Switch/Switch.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 26 | -------------------------------------------------------------------------------- /frontend/src/components/boxs/el/Tooltip/Tooltip.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 28 | -------------------------------------------------------------------------------- /frontend/src/components/boxs/el/Button/Button.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | 13 | 26 | -------------------------------------------------------------------------------- /frontend/src/components/boxs/el/ProgressBar/ProgressBar.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/bin 2 | node_modules 3 | frontend/dist 4 | .DS_Store 5 | 6 | # Logs 7 | logs 8 | *.log 9 | npm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | pnpm-debug.log* 13 | lerna-debug.log* 14 | 15 | node_modules 16 | .DS_Store 17 | dist 18 | dist-ssr 19 | coverage 20 | *.local 21 | 22 | /cypress/videos/ 23 | /cypress/screenshots/ 24 | 25 | # Editor directories and files 26 | .vscode/* 27 | !.vscode/extensions.json 28 | .idea 29 | *.suo 30 | *.ntvs* 31 | *.njsproj 32 | *.sln 33 | *.sw? 34 | .vscode 35 | *.lockb 36 | package-lock.json 37 | package.json.md5 38 | /frontend/package.json.md5 39 | /frontend/package-lock.json 40 | frontend/wailsjs/runtime/* 41 | *.lockb -------------------------------------------------------------------------------- /frontend/src/components/boxs/td/Switch/Switch.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 29 | -------------------------------------------------------------------------------- /frontend/src/components/boxs/td/Button/Button.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 31 | -------------------------------------------------------------------------------- /action/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "bind": "0.0.0.0:8181", 3 | "proxy_url": "", 4 | "timeout": 600, 5 | "codex_api_base": "http://127.0.0.1:5001/v1", 6 | "codex_api_key": "sk-6a05efdddb81434f9cb1fff4ee83fa04", 7 | "codex_api_organization": "", 8 | "codex_api_project": "", 9 | "codex_max_tokens": 500, 10 | "code_instruct_model": "deepseek-coder", 11 | "chat_api_base": "https://api.deepseek.com/v1", 12 | "chat_api_key": "sk-6a05efdddb81434f9cb1fff4ee83fa04", 13 | "chat_api_organization": "", 14 | "chat_api_project": "", 15 | "chat_max_tokens": 4096, 16 | "chat_model_default": "deepseek-chat", 17 | "chat_model_map": { 18 | }, 19 | "chat_locale": "zh_CN", 20 | "auth_token": "" 21 | } -------------------------------------------------------------------------------- /frontend/src/components/boxs/td/Link/Link.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 31 | -------------------------------------------------------------------------------- /frontend/src/components/boxs/el/FlexLayout/FlexLayout.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 29 | -------------------------------------------------------------------------------- /frontend/src/components/boxs/el/TextEdit/TextEdit.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 28 | 29 | 36 | -------------------------------------------------------------------------------- /frontend/src/components/boxs/td/Select/Select.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 34 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "embed" 5 | 6 | "github.com/wailsapp/wails/v2" 7 | "github.com/wailsapp/wails/v2/pkg/options" 8 | "github.com/wailsapp/wails/v2/pkg/options/assetserver" 9 | ) 10 | 11 | //go:embed all:frontend/dist 12 | var assets embed.FS 13 | 14 | func main() { 15 | // Create an instance of the app structure 16 | app := NewApp() 17 | 18 | // Create application with options 19 | err := wails.Run(&options.App{ 20 | Title: "myproject", 21 | Width: 1024, 22 | Height: 768, 23 | StartHidden: true, 24 | AssetServer: &assetserver.Options{ 25 | Assets: assets, 26 | }, 27 | BackgroundColour: &options.RGBA{R: 255, G: 255, B: 255, A: 1}, 28 | OnStartup: app.startup, 29 | Bind: []interface{}{ 30 | app, 31 | }, 32 | }) 33 | 34 | if err != nil { 35 | println("Error:", err.Error()) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /frontend/wailsjs/go/main/App.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL 3 | // This file is automatically generated. DO NOT EDIT 4 | 5 | export function E停止服务器() { 6 | return window['go']['main']['App']['E停止服务器'](); 7 | } 8 | 9 | export function E写到文件(arg1, arg2) { 10 | return window['go']['main']['App']['E写到文件'](arg1, arg2); 11 | } 12 | 13 | export function E取运行目录() { 14 | return window['go']['main']['App']['E取运行目录'](); 15 | } 16 | 17 | export function E启动服务器(arg1) { 18 | return window['go']['main']['App']['E启动服务器'](arg1); 19 | } 20 | 21 | export function E检查更新() { 22 | return window['go']['main']['App']['E检查更新'](); 23 | } 24 | 25 | export function E读入文本(arg1) { 26 | return window['go']['main']['App']['E读入文本'](arg1); 27 | } 28 | 29 | export function GetVersion() { 30 | return window['go']['main']['App']['GetVersion'](); 31 | } 32 | -------------------------------------------------------------------------------- /frontend/src/components/boxs/el/RadioButton/RadioButton.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 42 | -------------------------------------------------------------------------------- /frontend/src/components/boxs/el/CheckBox/CheckBox.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 42 | -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eview", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "vite", 7 | "build": "vite build", 8 | "preview": "vite preview" 9 | }, 10 | "dependencies": { 11 | "@guolao/vue-monaco-editor": "1.3.0", 12 | "@vitejs/plugin-vue-jsx": "^3.0.2", 13 | "element-plus": "^2.3.14", 14 | "monaco-editor": "0.38.0", 15 | "pinia": "^2.1.6", 16 | "pinyin-pro": "^3.16.3", 17 | "tdesign-icons-vue-next": "^0.2.2", 18 | "tdesign-vue-next": "^1.6.5", 19 | "uuid": "^9.0.1", 20 | "vue": "^3.3.4", 21 | "vue-i18n": "^9.6.1", 22 | "vue3-sfc-loader": "^0.8.4" 23 | }, 24 | "devDependencies": { 25 | "@iconify/vue": "^4.1.1", 26 | "@vitejs/plugin-vue": "^4.2.3", 27 | "monaco-editor-webpack-plugin": "^7.1.0", 28 | "unplugin-auto-import": "^0.16.6", 29 | "unplugin-icons": "^0.16.6", 30 | "unplugin-vue-components": "^0.25.1", 31 | "vite": "^4.4.11" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /frontend/src/App.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | 42 | -------------------------------------------------------------------------------- /frontend/src/main.js: -------------------------------------------------------------------------------- 1 | import {createApp} from 'vue' 2 | import {createPinia} from 'pinia' 3 | // import ElementPlus from 'element-plus' 4 | import 'element-plus/dist/index.css' 5 | // import TDesign from 'tdesign-vue-next' 6 | import 'tdesign-vue-next/es/style/index.css' 7 | 8 | import App from './App.vue' 9 | import Helper from "./Helper.js" 10 | 11 | 12 | import RenderDesignComponentPreview from "./components/RenderDesignComponentPreview.vue" 13 | 14 | const app = createApp(App) 15 | 16 | app.component('RenderDesignComponent', RenderDesignComponentPreview) 17 | 18 | 19 | const BoxComponentNames_el = Helper.registerBoxComponentNames(app, 'el', import.meta.glob('./components/boxs/el/**/*.vue', {eager: true})) 20 | const BoxComponentNames_td = Helper.registerBoxComponentNames(app, 'td', import.meta.glob('./components/boxs/td/**/*.vue', {eager: true})) 21 | 22 | 23 | 24 | app.use(createPinia()) 25 | // app.use(TDesign) 26 | // app.use(ElementPlus) 27 | app.config.warnHandler = function (msg, vm, trace) { 28 | // 自定义处理警告的逻辑,或者什么都不做以屏蔽 29 | }; 30 | app.mount('#app') 31 | 32 | -------------------------------------------------------------------------------- /frontend/src/components/boxs/el/Tabs/Tabs.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 33 | -------------------------------------------------------------------------------- /frontend/src/components/boxs/el/Table/Table.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | -------------------------------------------------------------------------------- /frontend/src/components/boxs/el/Tree/Tree.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 49 | -------------------------------------------------------------------------------- /README.zh-Hans.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 |

6 |

7 | 8 |
9 | 10 | 11 | 12 | [English](README.md) · [简体中文](README.zh-Hans.md) 13 | 14 | 15 | 16 |
17 | 18 | # 窗口设计师 GoEasyDesigner 的演示项目 19 | 20 | 用于运行窗口设计师设计好界面和程序 21 | 22 | 23 | ![](https://user-images.githubusercontent.com/59047063/270091148-a89d2ab9-9ba3-4efc-b0fa-0a7dcc3bcfc1.gif) 24 | 25 | 26 | 创建项目 27 | 28 | ``` 29 | wails init -n "go-easy-demo" -t https://github.com/duolabmeng6/wails-template-vue-go-easy 30 | ``` 31 | 32 | 运行窗口 33 | 34 | ``` 35 | cd go-easy-demo 36 | wails dev 37 | ``` 38 | 39 | 40 | [下载 GoEasyDesigner 窗口设计师](https://github.com/duolabmeng6/GoEasyDesigner/releases) 41 | 42 | [ GoEasyDesigner 项目地址](https://github.com/duolabmeng6/GoEasyDesigner) 43 | 44 | # 在线体验窗口设计师 45 | 46 | 网页端仅提供基本的界面设计,如需更好编码体验,请下载客户端. 47 | 48 | 国内地址: https://go.kenhong.com/ 49 | 50 | 国外地址: https://g.yx24.me 51 | 52 | 画好界面点保存,会下载2个文件 `design.json`,`__aux_code.js` 注意你的浏览器允许下载多个文件的权限 53 | 54 | 下载本项目的代码 复制 `go-easy-demo` 文件夹作为开发项目 55 | 56 | `go-easy-demo/frontend/src/win/design.json` 57 | 58 | `go-easy-demo/frontend/src/win/__aux_code.js` 59 | 60 | 运行项目 就可以看到你设计好的界面了. 61 | 62 | ``` 63 | cd go-easy-demo 64 | wails dev 65 | ``` 66 | 67 | 68 | -------------------------------------------------------------------------------- /frontend/src/Helper.js: -------------------------------------------------------------------------------- 1 | function registerBoxComponentNames(app, uiName, meta) { 2 | let ComponentNames = [] 3 | const componentsContext = meta; 4 | 5 | const keys = Object.keys(componentsContext).map((path) => { 6 | const name = path.split('/').pop().replace(/\.\w+$/, ''); 7 | const module = componentsContext[path]; 8 | //如果名称后面是 属性 或者是 Attr 就不要加入 9 | if (!(name.endsWith("属性") || name.endsWith("Attr"))) { 10 | ComponentNames.push(name) 11 | } 12 | // console.log("注册组件", uiName, name) 13 | app.component(uiName + name, module.default); 14 | // app.component(name, module.default); 15 | return name; 16 | }); 17 | 18 | return ComponentNames; 19 | 20 | } 21 | 22 | function registerBoxComponentDefaultValue(app, uiName, meta) { 23 | let ComponentDefaultValue = {} 24 | const componentsContext = meta; 25 | 26 | const keys = Object.keys(componentsContext).map((path) => { 27 | const name = path.split('/').pop().replace(/\.\w+$/, ''); 28 | const module = componentsContext[path]; 29 | ComponentDefaultValue[name] = module.default; 30 | return name; 31 | }); 32 | 33 | return ComponentDefaultValue; 34 | } 35 | 36 | export default { 37 | registerBoxComponentNames, 38 | registerBoxComponentDefaultValue 39 | } -------------------------------------------------------------------------------- /action/run_override_test.go: -------------------------------------------------------------------------------- 1 | package action 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "github.com/duolabmeng6/goefun/ecore" 7 | "sync" 8 | "testing" 9 | "time" 10 | ) 11 | 12 | func Test_run_override(t *testing.T) { 13 | var logBuffer bytes.Buffer 14 | // 输出捕获的日志 15 | var mu sync.Mutex 16 | 17 | configContent := ecore.E读入文本("/Users/ll/Desktop/2024/override2ui/action/config.json") 18 | //_, _ := Run_override(configContent) 19 | Run_override(configContent, &logBuffer) 20 | // 使用time.Ticker定期检查logBuffer 21 | ticker := time.NewTicker(100 * time.Millisecond) 22 | defer ticker.Stop() 23 | 24 | // 使用goroutine异步处理日志输出 25 | go func() { 26 | for range ticker.C { 27 | mu.Lock() // 锁定缓冲区,避免竞态条件 28 | if logBuffer.Len() > 0 { 29 | fmt.Print(logBuffer.String()) // 使用fmt.Print而不是println 30 | logBuffer.Reset() 31 | } 32 | mu.Unlock() // 解锁缓冲区 33 | } 34 | }() 35 | 36 | //println(ok, err.Error()) 37 | //time.Sleep(time.Second * 1) 38 | //eh := ehttp.NewHttp() 39 | //text, err := eh.Get("http://127.0.0.1:8181/models") 40 | //println(text, err) 41 | //time.Sleep(time.Second * 2) 42 | //Stop_override() 43 | // 44 | //time.Sleep(time.Second * 3) 45 | //ok, err = Run_override(configContent) 46 | //println(ok, err) 47 | //time.Sleep(time.Second * 1) 48 | //text, err = eh.Get("http://127.0.0.1:8181/models") 49 | //println(text, err) 50 | time.Sleep(time.Second * 30) 51 | //Stop_override() 52 | 53 | } 54 | -------------------------------------------------------------------------------- /frontend/src/components/boxs/el/ControlButton/ControlButton.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 43 | -------------------------------------------------------------------------------- /frontend/src/win/__aux_code.js: -------------------------------------------------------------------------------- 1 | 2 | import designData from './design.json'; 3 | 4 | function __aux_code() { 5 | return { 6 | Win : designData[0], 7 | 选择夹3 : designData[0].childComponents[0], 8 | ContentArea3 : designData[0].childComponents[0].childComponents[0], 9 | 编辑框1 : designData[0].childComponents[0].childComponents[0].childComponents[0], 10 | 按钮_启动服务 : designData[0].childComponents[0].childComponents[0].childComponents[1], 11 | 标签1 : designData[0].childComponents[0].childComponents[0].childComponents[2], 12 | 按钮_重置配置 : designData[0].childComponents[0].childComponents[0].childComponents[3], 13 | 按钮_保存配置 : designData[0].childComponents[0].childComponents[0].childComponents[4], 14 | ContentArea4 : designData[0].childComponents[0].childComponents[1], 15 | 按钮_检查更新 : designData[0].childComponents[0].childComponents[1].childComponents[0], 16 | ContentArea5 : designData[0].childComponents[0].childComponents[2], 17 | 编辑框2 : designData[0].childComponents[0].childComponents[2].childComponents[0], 18 | 标签2 : designData[0].childComponents[0].childComponents[2].childComponents[1], 19 | 标签3 : designData[0].childComponents[0].childComponents[2].childComponents[2], 20 | 按钮1 : designData[0].childComponents[0].childComponents[2].childComponents[3], 21 | ContentArea1 : designData[0].childComponents[0].childComponents[3], 22 | 编辑框3 : designData[0].childComponents[0].childComponents[3].childComponents[0], 23 | 24 | } 25 | } 26 | export default __aux_code 27 | -------------------------------------------------------------------------------- /frontend/src/components/boxs/el/Menu/Menu.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 43 | -------------------------------------------------------------------------------- /frontend/src/components/boxs/el/Label/Label.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 31 | -------------------------------------------------------------------------------- /frontend/src/components/boxs/el/CustomComponent/CustomComponent.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | -------------------------------------------------------------------------------- /app.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "changeme/action" 6 | "changeme/myModel" 7 | "context" 8 | "fmt" 9 | "github.com/duolabmeng6/goefun/ecore" 10 | "github.com/duolabmeng6/goefun/etool" 11 | "github.com/wailsapp/wails/v2/pkg/runtime" 12 | "sync" 13 | "time" 14 | ) 15 | 16 | // App struct 17 | type App struct { 18 | ctx context.Context 19 | mu sync.Mutex 20 | ticker *time.Ticker 21 | logBuffer bytes.Buffer 22 | } 23 | 24 | // NewApp creates a new App application struct 25 | func NewApp() *App { 26 | return &App{} 27 | } 28 | 29 | // startup is called when the app starts. The context is saved 30 | // so we can call the runtime methods 31 | func (a *App) startup(ctx context.Context) { 32 | a.ctx = ctx 33 | a.ticker = time.NewTicker(1000 * time.Millisecond) 34 | //a.logBuffer = bytes.Buffer 35 | go func() { 36 | for range a.ticker.C { 37 | fmt.Println("ticker") 38 | a.mu.Lock() // 锁定缓冲区,避免竞态条件 39 | if a.logBuffer.Len() > 0 { 40 | fmt.Print(a.logBuffer.String()) // 使用fmt.Print而不是println 41 | jsonstring := etool.E到Json(map[string]string{ 42 | "logs": a.logBuffer.String(), 43 | }) 44 | runtime.EventsEmit(a.ctx, "logs", jsonstring) 45 | a.logBuffer.Reset() 46 | } 47 | a.mu.Unlock() // 解锁缓冲区 48 | } 49 | }() 50 | 51 | } 52 | 53 | func (a *App) GetVersion() string { 54 | println("GetVersion", myModel.Version) 55 | return myModel.Version 56 | } 57 | func (a *App) E检查更新() string { 58 | myModel.E检查更新() 59 | return "ok" 60 | } 61 | 62 | func (a *App) E启动服务器(配置内容 string) string { 63 | _, err := action.Run_override(配置内容, &a.logBuffer) 64 | if err != nil { 65 | return err.Error() 66 | } 67 | //defer a.ticker.Stop() 68 | jsonstring := etool.E到Json(map[string]string{ 69 | "logs": "已启动服务器", 70 | }) 71 | runtime.EventsEmit(a.ctx, "logs", jsonstring) 72 | return "启动成功" 73 | } 74 | 75 | func (a *App) E停止服务器() string { 76 | action.Stop_override() 77 | return "已停止" 78 | } 79 | 80 | func (a *App) E写到文件(文件路径 string, 写出数据 string) error { 81 | err := ecore.E写到文件(文件路径, []byte(写出数据)) 82 | return err 83 | } 84 | func (a *App) E读入文本(文件路径 string) string { 85 | data := ecore.E读入文本(文件路径) 86 | return data 87 | } 88 | func (a *App) E取运行目录() string { 89 | data := ecore.E取运行目录() 90 | return data 91 | } 92 | -------------------------------------------------------------------------------- /frontend/vite.config.js: -------------------------------------------------------------------------------- 1 | import {fileURLToPath, URL} from 'node:url' 2 | 3 | import {defineConfig} from 'vite' 4 | import vue from '@vitejs/plugin-vue' 5 | 6 | import AutoImport from 'unplugin-auto-import/vite' 7 | import Components from 'unplugin-vue-components/vite' 8 | import {ElementPlusResolver} from 'unplugin-vue-components/resolvers' 9 | import IconsResolver from 'unplugin-icons/resolver' 10 | import vueJsx from '@vitejs/plugin-vue-jsx' 11 | 12 | import { TDesignResolver } from 'unplugin-vue-components/resolvers'; 13 | 14 | // https://vitejs.dev/config/ 15 | export default defineConfig({ 16 | server: { 17 | host: "0.0.0.0", 18 | hmr: { 19 | host: 'localhost', 20 | protocol: 'ws', 21 | } 22 | }, 23 | publicDir: "public", 24 | plugins: [ 25 | vue(), 26 | vueJsx(), 27 | AutoImport({ 28 | imports: ['vue'], 29 | resolvers: [ 30 | ElementPlusResolver(), 31 | 32 | // Auto import icon components 33 | // 自动导入图标组件 34 | IconsResolver({ 35 | prefix: 'Icon', 36 | }), 37 | TDesignResolver({ 38 | library: 'vue-next' 39 | }) 40 | ], 41 | }), 42 | Components({ 43 | resolvers: [ 44 | // Auto register icon components 45 | // 自动注册图标组件 46 | IconsResolver({ 47 | enabledCollections: ['ep'], 48 | }), 49 | // Auto register Element Plus components 50 | // 自动导入 Element Plus 组件 51 | ElementPlusResolver(), 52 | TDesignResolver({ 53 | library: 'vue-next' 54 | }) 55 | ], 56 | }), 57 | 58 | ], 59 | resolve: { 60 | alias: { 61 | '@': fileURLToPath(new URL('./src', import.meta.url)) 62 | } 63 | }, 64 | esbuild: { 65 | jsxFactory: 'h', 66 | jsxFragment: 'Fragment', 67 | // jsxInject: `import React from 'react'`, 68 | }, 69 | optimizeDeps: { 70 | include: [ 71 | './src/win/design.json', 72 | './src/win/__load_data.js', 73 | './src/win/__aux_code.js', 74 | './src/win/event.js', 75 | ] 76 | } 77 | }) 78 | -------------------------------------------------------------------------------- /frontend/src/win/__load_data.js: -------------------------------------------------------------------------------- 1 | import {ref} from 'vue' 2 | import {defineStore} from 'pinia' 3 | import * as systemFc from "../../wailsjs/runtime/runtime"; // 根据实际文件路径进行修改 4 | import {BindWindowEvent} from './event' 5 | import __aux_code from "./__aux_code"; 6 | import designData from './design.json'; 7 | 8 | export const __load_data = defineStore('window_data', { 9 | state: () => { 10 | return { 11 | list : ref(designData), 12 | comps : __aux_code(designData) 13 | } 14 | }, 15 | actions: { 16 | async init() { 17 | 18 | BindWindowEvent(this, this.comps) 19 | try { 20 | if (this.comps.Win.hasOwnProperty("event_created")) { 21 | await this.WinCreated() 22 | } 23 | } catch (e) { 24 | console.log("WinCreated To be defined") 25 | } 26 | 27 | const dthis = this 28 | 29 | try { 30 | setTimeout(function () { 31 | systemFc.WindowShow() 32 | }, 200) 33 | 34 | if (dthis.comps.Win.width.includes('v') || dthis.comps.Win.width.includes('%')) { 35 | return; 36 | } 37 | if (dthis.comps.Win.height.includes('v') || dthis.comps.Win.height.includes('%')) { 38 | return; 39 | } 40 | systemFc.WindowSetSize(parseInt(dthis.comps.Win.width), parseInt(dthis.comps.Win.height)) 41 | //Recalculate the width and height of the client area 42 | setTimeout(function () { 43 | var WidthFix = parseInt(dthis.comps.Win.width) - window.innerWidth 44 | var HeightFix = parseInt(dthis.comps.Win.height) - window.innerHeight 45 | systemFc.WindowSetSize(parseInt(dthis.comps.Win.width) + WidthFix, parseInt(dthis.comps.Win.height) + HeightFix) 46 | document.body.style.overflow = 'auto' 47 | }, 1) 48 | systemFc.WindowSetTitle(dthis.comps.Win.text) 49 | //Move to the center of the screen 50 | systemFc.WindowCenter() 51 | } catch (e) { 52 | console.error("Error initializing win size", e) 53 | } 54 | 55 | }, 56 | handleAllEvents(el, e, item, callFuncName) { 57 | try { 58 | var dynamicFunction = undefined 59 | eval(`dynamicFunction = this.${callFuncName}`) 60 | dynamicFunction(e, item) 61 | } catch (e) { 62 | console.log("Function call error", callFuncName, "dynamicFunction", dynamicFunction, "e", e) 63 | } 64 | }, 65 | 66 | }, 67 | }) -------------------------------------------------------------------------------- /frontend/src/components/boxs/el/TabsTW/TabsTW.vue: -------------------------------------------------------------------------------- 1 | 53 | 54 | 55 | 100 | 101 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module changeme 2 | 3 | go 1.21 4 | 5 | toolchain go1.21.1 6 | 7 | require ( 8 | github.com/duolabmeng6/goefun v1.3.8 9 | github.com/gin-gonic/gin v1.9.1 10 | github.com/ncruces/zenity v0.10.13 11 | github.com/tidwall/gjson v1.14.4 12 | github.com/tidwall/sjson v1.1.7 13 | github.com/wailsapp/wails/v2 v2.9.1 14 | golang.org/x/net v0.25.0 15 | ) 16 | 17 | require ( 18 | github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible // indirect 19 | github.com/akavel/rsrc v0.10.2 // indirect 20 | github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 // indirect 21 | github.com/bep/debounce v1.2.1 // indirect 22 | github.com/bytedance/sonic v1.9.1 // indirect 23 | github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect 24 | github.com/dchest/jsmin v0.0.0-20220218165748-59f39799265f // indirect 25 | github.com/fsnotify/fsnotify v1.5.4 // indirect 26 | github.com/gabriel-vasile/mimetype v1.4.2 // indirect 27 | github.com/gin-contrib/sse v0.1.0 // indirect 28 | github.com/go-ole/go-ole v1.2.6 // indirect 29 | github.com/go-playground/locales v0.14.1 // indirect 30 | github.com/go-playground/universal-translator v0.18.1 // indirect 31 | github.com/go-playground/validator/v10 v10.14.0 // indirect 32 | github.com/goccy/go-json v0.10.2 // indirect 33 | github.com/godbus/dbus/v5 v5.1.0 // indirect 34 | github.com/gogf/gf/v2 v2.4.1 // indirect 35 | github.com/gogf/guuid v1.0.0 // indirect 36 | github.com/google/uuid v1.3.0 // indirect 37 | github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect 38 | github.com/joho/godotenv v1.5.1 // indirect 39 | github.com/josephspurrier/goversioninfo v1.4.0 // indirect 40 | github.com/json-iterator/go v1.1.12 // indirect 41 | github.com/klauspost/cpuid/v2 v2.2.4 // indirect 42 | github.com/kr/pretty v0.3.0 // indirect 43 | github.com/kr/text v0.2.0 // indirect 44 | github.com/labstack/echo/v4 v4.10.2 // indirect 45 | github.com/labstack/gommon v0.4.0 // indirect 46 | github.com/leaanthony/go-ansi-parser v1.6.0 // indirect 47 | github.com/leaanthony/gosod v1.0.3 // indirect 48 | github.com/leaanthony/slicer v1.6.0 // indirect 49 | github.com/leaanthony/u v1.1.0 // indirect 50 | github.com/leodido/go-urn v1.2.4 // indirect 51 | github.com/mattn/go-colorable v0.1.13 // indirect 52 | github.com/mattn/go-isatty v0.0.19 // indirect 53 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 54 | github.com/modern-go/reflect2 v1.0.2 // indirect 55 | github.com/pelletier/go-toml/v2 v2.0.8 // indirect 56 | github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect 57 | github.com/pkg/errors v0.9.1 // indirect 58 | github.com/randall77/makefat v0.0.0-20210315173500-7ddd0e42c844 // indirect 59 | github.com/rivo/uniseg v0.4.4 // indirect 60 | github.com/rogpeppe/go-internal v1.8.0 // indirect 61 | github.com/samber/lo v1.38.1 // indirect 62 | github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf // indirect 63 | github.com/tidwall/match v1.1.1 // indirect 64 | github.com/tidwall/pretty v1.2.0 // indirect 65 | github.com/tkrajina/go-reflector v0.5.6 // indirect 66 | github.com/twitchyliquid64/golang-asm v0.15.1 // indirect 67 | github.com/ugorji/go/codec v1.2.11 // indirect 68 | github.com/valyala/bytebufferpool v1.0.0 // indirect 69 | github.com/valyala/fasttemplate v1.2.2 // indirect 70 | github.com/wailsapp/go-webview2 v1.0.10 // indirect 71 | github.com/wailsapp/mimetype v1.4.1 // indirect 72 | go.opentelemetry.io/otel v1.7.0 // indirect 73 | go.opentelemetry.io/otel/trace v1.7.0 // indirect 74 | golang.org/x/arch v0.3.0 // indirect 75 | golang.org/x/crypto v0.23.0 // indirect 76 | golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect 77 | golang.org/x/image v0.18.0 // indirect 78 | golang.org/x/sys v0.22.0 // indirect 79 | golang.org/x/text v0.16.0 // indirect 80 | google.golang.org/protobuf v1.30.0 // indirect 81 | gopkg.in/ini.v1 v1.67.0 // indirect 82 | gopkg.in/yaml.v3 v3.0.1 // indirect 83 | ) 84 | -------------------------------------------------------------------------------- /myModel/自动更新模块_test.go: -------------------------------------------------------------------------------- 1 | package myModel 2 | 3 | import ( 4 | "fmt" 5 | "github.com/duolabmeng6/goefun/ecore" 6 | "github.com/ncruces/zenity" 7 | "os/user" 8 | "path/filepath" 9 | "testing" 10 | ) 11 | 12 | func Test简单(t *testing.T) { 13 | E检查更新() 14 | } 15 | func TestE获取Github仓库Releases版本和更新内容(t *testing.T) { 16 | info := E获取Github仓库Releases版本和更新内容() 17 | ecore.E调试输出(info) 18 | 19 | } 20 | 21 | func Test下载(t *testing.T) { 22 | err := E下载带进度回调("https://github.com/duolabmeng6/GoEasyDesigner/releases/download/v0.2.4/GoEasyDesigner_MacOS.zip", 23 | "/Users/ll/Downloads/GoEasyDesigner_MacOS.zip", func(进度 float64) { 24 | // 进度回调函数 25 | fmt.Println("正在下载...", 进度) 26 | }) 27 | if err != nil { 28 | fmt.Println("下载出错:", err) 29 | } else { 30 | fmt.Println("下载完成") 31 | } 32 | 33 | } 34 | func Test系统版本(t *testing.T) { 35 | fmt.Println("系统是否为Windows:", E系统是否为window系统()) 36 | fmt.Println("系统是否为Linux:", E系统是否为linux系统()) 37 | fmt.Println("系统是否为Mac:", E系统是否为mac系统()) 38 | fmt.Println("是否为调试模式:", E是否为调试模式()) 39 | 40 | } 41 | 42 | func Test解压缩(t *testing.T) { 43 | 压缩包的路径 := "/Users/ll/Downloads/GoEasyDesigner_MacOS.zip" 44 | //解压目录 := "/Users/ll/Desktop/goproject/v3fanyi/mymodel/testzip/" 45 | //允许解压路径前缀 := []string{"qoq.app/Contents/"} 46 | //println(zip解压2(压缩包的路径, 解压目录, 允许解压路径前缀)) 47 | E更新自己MacOS应用(压缩包的路径, "GoEasyDesigner.app") 48 | } 49 | func Test更新流程MacOS(t *testing.T) { 50 | usr, err := user.Current() 51 | if err != nil { 52 | panic(err) 53 | } 54 | 下载文件夹路径 := filepath.Join(usr.HomeDir, "Downloads") 55 | 56 | println(下载文件夹路径) 57 | info := E获取Github仓库Releases版本和更新内容() 58 | 59 | err = E下载带进度回调(info.MacDownloadURL, 下载文件夹路径+"/mactest.zip", func(进度 float64) { 60 | // 进度回调函数 61 | fmt.Println("正在下载...", 进度) 62 | }) 63 | if err != nil { 64 | fmt.Println("下载出错:", err) 65 | return 66 | } 67 | 68 | flag, s := E更新自己MacOS应用(下载文件夹路径+"/mactest.zip", "qoq.app") 69 | println(flag, s) 70 | 71 | } 72 | 73 | func Test更新流程Window(t *testing.T) { 74 | // 75 | usr, err := user.Current() 76 | if err != nil { 77 | panic(err) 78 | } 79 | 下载文件夹路径 := filepath.Join(usr.HomeDir, "Downloads") 80 | 81 | //println(下载文件夹路径) 82 | //info := E获取Github仓库Releases版本和更新内容() 83 | // 84 | //err = E下载带进度回调(info.WinDownloadURL, 下载文件夹路径+"/GoEasyDesigner.exe", func(进度 float64) { 85 | // // 进度回调函数 86 | // fmt.Println("正在下载...", 进度) 87 | //}) 88 | //if err != nil { 89 | // fmt.Println("下载出错:", err) 90 | // return 91 | //} 92 | 93 | flag, s := E更新自己Window应用(下载文件夹路径 + "/GoEasyDesigner.exe") 94 | println(flag, s) 95 | 96 | } 97 | 98 | func Test整个流程(t *testing.T) { 99 | 100 | 下载文件夹路径 := E取用户下载文件夹路径() 101 | info := E获取Github仓库Releases版本和更新内容() 102 | println(info.MacDownloadURL) 103 | println(下载文件夹路径) 104 | if info.Version == Version { 105 | err := zenity.Info("当前已经是最新版本") 106 | if err != nil { 107 | return 108 | } 109 | return 110 | } 111 | 112 | err := zenity.Question("软件有新版本可用,是否更新?\n当前版本:"+ 113 | Version+ 114 | "\n最新版本:"+info.Version, 115 | zenity.Title("更新提示"), 116 | zenity.Icon(zenity.QuestionIcon), 117 | zenity.OKLabel("更新"), 118 | zenity.CancelLabel("取消")) 119 | ecore.E调试输出(err) 120 | println("更新", err) 121 | if err != nil { 122 | return 123 | } 124 | progress, _ := zenity.Progress( 125 | zenity.Title("软件更新"), 126 | zenity.MaxValue(100), // 设置最大进度值为100 127 | ) 128 | 129 | progress.Text("正在下载...") 130 | 131 | err = E下载带进度回调(info.MacDownloadURL, 下载文件夹路径+"/"+应用名称+"_MacOS.zip", func(进度 float64) { 132 | fmt.Println("正在下载...", 进度) 133 | progress.Text("正在下载..." + fmt.Sprintf("%.2f", 进度) + "%") 134 | progress.Value(int(进度)) 135 | }) 136 | if err != nil { 137 | fmt.Println("下载出错:", err) 138 | zenity.Info("下载错误,检查你的网络") 139 | progress.Close() 140 | return 141 | } 142 | progress.Text("下载完成 即将完成更新") 143 | if progress.Close() != nil { 144 | fmt.Println("点击了取消") 145 | return 146 | } 147 | fmt.Println("下载完成了") 148 | flag, s := E更新自己MacOS应用(下载文件夹路径+"/"+应用名称+"_MacOS.zip", 应用名称+".app") 149 | println(flag, s) 150 | } 151 | -------------------------------------------------------------------------------- /frontend/src/components/RenderDesignComponentPreview.vue: -------------------------------------------------------------------------------- 1 | 53 | 54 | 110 | 111 | -------------------------------------------------------------------------------- /frontend/src/win/event.js: -------------------------------------------------------------------------------- 1 | import * as systemFc from "../../wailsjs/runtime"; 2 | import * as goFc from "../../wailsjs/go/main/App"; 3 | import {__load_data} from './__load_data' 4 | import {ElMessage} from "element-plus"; 5 | 6 | let odata = { 7 | "bind": "0.0.0.0:8181", 8 | "proxy_url": "", 9 | "timeout": 600, 10 | "codex_api_base": "https://api.deepseek.com/beta/v1", 11 | "codex_api_key": "sk-这里填写你的key", 12 | "codex_api_organization": "", 13 | "codex_api_project": "", 14 | "codex_max_tokens": 500, 15 | "code_instruct_model": "deepseek-coder", 16 | "chat_api_base": "https://api.deepseek.com/v1", 17 | "chat_api_key": "sk-这里填写你的key", 18 | "chat_api_organization": "", 19 | "chat_api_project": "", 20 | "chat_max_tokens": 4096, 21 | "chat_model_default": "deepseek-chat", 22 | "chat_model_map": {}, 23 | "chat_locale": "zh_CN", 24 | "auth_token": "" 25 | } 26 | let letvscode = { 27 | "github.copilot.advanced": { 28 | "debug.overrideCAPIUrl": "http://127.0.0.1:8181/v1", 29 | "debug.overrideProxyUrl": "http://127.0.0.1:8181", 30 | "debug.chatOverrideProxyUrl": "http://127.0.0.1:8181/v1/chat/completions", 31 | "authProvider": "github-enterprise" 32 | }, 33 | "github-enterprise.uri": "https://cocopilot.org", 34 | } 35 | 36 | export function BindWindowEvent() { 37 | const c = __load_data() 38 | let comps = c.comps 39 | c.WinCreated = async function () { 40 | console.log("Win创建完毕") 41 | comps.编辑框3.text = "" 42 | systemFc.EventsOn("logs", function (data) { 43 | let jsondata = JSON.parse(data); 44 | console.log("jsondata",jsondata) 45 | comps.编辑框3.text = comps.编辑框3.text + jsondata.logs; 46 | }); 47 | 48 | comps.Win.text = "overrideManager " + await goFc.GetVersion(); 49 | comps.选择夹3.value = "0" 50 | 51 | //这个odata的数据需要json格式化 52 | comps.编辑框1.text = JSON.stringify(odata, null, 4) 53 | comps.编辑框2.text = JSON.stringify(letvscode, null, 4) 54 | 55 | comps.标签2.text = `安装 VSCode Copilot 56 | Copilot 1.219.0 57 | Copilotchat 0.17.1 58 | 按 ctrl+shift+p 输入 settings 打开首选项 加入这些配置 重启vscode` 59 | 60 | 61 | let 配置文件目录 = await goFc.E取运行目录() 62 | 63 | let data = await goFc.E读入文本(配置文件目录 + "/my-config.conf") 64 | if (data !== "") { 65 | ElMessage.success('已读取配置和启动服务 配置文件路径:' + 配置文件目录 + "/my-config.conf"); 66 | 67 | comps.编辑框1.text = data 68 | c.按钮_启动服务被单击() 69 | } 70 | 71 | 72 | } 73 | 74 | c.按钮_启动服务被单击 = async function () { 75 | if (comps.按钮_启动服务.text === "启动服务") { 76 | let 启动状态 = await goFc.E启动服务器(comps.编辑框1.text) 77 | console.log("启动状态", 启动状态) 78 | if (启动状态 == '启动成功') { 79 | comps.按钮_启动服务.text = "停止服务" 80 | ElMessage.success('已启动'); 81 | } else { 82 | ElMessage.error(启动状态); 83 | } 84 | comps.标签1.text = 启动状态 85 | } else { 86 | comps.按钮_启动服务.text = "启动服务" 87 | await goFc.E停止服务器() 88 | comps.标签1.text = "已停止" 89 | ElMessage.success('已停止'); 90 | 91 | } 92 | 93 | 94 | } 95 | 96 | c.按钮_重置配置被单击 = async function () { 97 | console.log("按钮_重置配置被单击") 98 | comps.编辑框1.text = JSON.stringify(odata, null, 4) 99 | ElMessage.success('已重置'); 100 | } 101 | 102 | c.按钮_保存配置被单击 = async function () { 103 | console.log("按钮_保存配置被单击") 104 | let 配置文件目录 = await goFc.E取运行目录() 105 | await goFc.E写到文件(配置文件目录 + "/my-config.conf", comps.编辑框1.text) 106 | 107 | ElMessage.success('保存到' + 配置文件目录 + "/my-config.conf"); 108 | } 109 | 110 | c.标签3被单击 = async function () { 111 | console.log("标签3被单击") 112 | systemFc.BrowserOpenURL("https://my.rongyiapi.com/post/rang-Copilot-yong-shang-DeepSeek-zong-yu-gao-ming-bai-le-vscode-he-JetBrainsIDE-du-neng-yong.html") 113 | 114 | } 115 | 116 | c.按钮1被单击 = async function () { 117 | systemFc.ClipboardSetText(comps.编辑框2.text) 118 | ElMessage.success('已复制'); 119 | 120 | } 121 | 122 | c.按钮_检查更新被单击 = async function () { 123 | ElMessage.success('检查更新中'); 124 | await goFc.E检查更新(); 125 | } 126 | //Don't delete the event function flag 127 | } -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: 发布软件 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | paths-ignore: 7 | - '**/*.md' 8 | - '**/*.yml' 9 | - .gitignore 10 | - .editorconfig 11 | 12 | permissions: write-all # 给所有工作写权限 13 | 14 | 15 | jobs: 16 | jobs_v: 17 | name: 构建版本号和变更信息 18 | runs-on: ubuntu-latest 19 | outputs: 20 | version: ${{ steps.create_version.outputs.NewVersion }} # 版本号 21 | body: ${{ steps.create_body.outputs.Body }} # 版本变更内容 22 | steps: 23 | - uses: actions/checkout@v4 24 | with: 25 | submodules: recursive 26 | fetch-depth: 0 27 | - name: 检查是否 "发布" 28 | run: | 29 | latest_commit_message=$(git log -1 --pretty=%B) 30 | if [[ $latest_commit_message == *"发布"* ]]; then 31 | echo "找到发布关键字继续工作流" 32 | else 33 | echo "没有找到发布关键字停止工作流" 34 | exit 1 # 停止工作流程 35 | fi 36 | - name: 递增版本号 37 | id: create_version 38 | uses: duolabmeng6/action-autotag-python@master 39 | with: 40 | token: ${{ secrets.GITHUB_TOKEN }} 41 | - name: 获取更新日志 42 | id: create_body 43 | uses: duolabmeng6/action-Releases-log@main 44 | with: 45 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 46 | FILE: .github/releasesText.md 47 | KEYS: bug,改进,优化,新增,删除 48 | - name: 查看版本号和更新日志 49 | run: | 50 | echo ${{ format('version={0}', steps.create_version.outputs.NewVersion ) }} 51 | echo "${{ steps.create_body.outputs.Body }}" 52 | 53 | jobs_macos: 54 | # 暂停 55 | #if: false 56 | needs: [ jobs_v ] 57 | name: 构建macos软件 58 | runs-on: macos-12 59 | env: 60 | version: ${{ needs.jobs_v.outputs.version }} 61 | body: ${{ needs.jobs_v.outputs.Body }} 62 | steps: 63 | - name: Checkout code 64 | uses: actions/checkout@v3 65 | - name: 构建缓存 66 | uses: actions/cache@v3 67 | with: 68 | path: | 69 | /Users/runner/.npm 70 | key: ${{ runner.os }}-js-${{ hashFiles('**/package.json') }} 71 | restore-keys: | 72 | ${{ runner.os }}-js- 73 | - name: 查看文件 74 | run: | 75 | pwd 76 | ls -la 77 | echo "New Body: ${{ env.body }}" 78 | 79 | - name: 安装 go 80 | uses: actions/setup-go@v4 81 | with: 82 | go-version: '^1.21.0' 83 | cache-dependency-path: | 84 | **/go.sum 85 | **/go.mod 86 | go-version-file: 'go.mod' 87 | - run: go version 88 | - name: 安装 wails 工具 89 | run: | 90 | go install github.com/wailsapp/wails/v2/cmd/wails@latest 91 | wails 92 | - name: 生成 Version.go 文件 93 | run: | 94 | echo -e "package myModel\n\nvar Version = \"${version}\"" > myModel/Version.go 95 | cat myModel/Version.go 96 | - name: 编译 97 | run: | 98 | pwd 99 | wails build 100 | ls -la 101 | - name: 查看编译的文件保存 102 | run: | 103 | pwd 104 | ls -la 105 | mkdir -p /tmp/artifacts 106 | cp -r build/bin/overrideManager.app /tmp/artifacts/overrideManager.app 107 | cp -r build/dmg.sh /tmp/artifacts/dmg.sh 108 | chmod +x /tmp/artifacts/overrideManager.app/Contents/MacOS/overrideManager 109 | - name: 创建压缩包 110 | run: | 111 | cd /tmp/artifacts/ 112 | ./dmg.sh 113 | zip -r ./overrideManager_MacOS.zip ./overrideManager.app 114 | 115 | - name: 上传产物 116 | uses: actions/upload-artifact@v3 117 | with: 118 | name: macos 119 | path: | 120 | /tmp/artifacts/*.zip 121 | /tmp/artifacts/*.dmg 122 | 123 | 124 | jobs_window: 125 | needs: jobs_v # 等待 jobs_v 任务完成才执行 126 | name: 构建window软件 127 | timeout-minutes: 20 128 | runs-on: windows-2022 129 | env: 130 | version: ${{ needs.jobs_v.outputs.version }} 131 | body: ${{ needs.jobs_v.outputs.Body }} 132 | steps: 133 | - uses: actions/checkout@v3 134 | with: 135 | submodules: recursive 136 | - name: 构建缓存 137 | uses: actions/cache@v3 138 | with: 139 | path: | 140 | C:\npm\cache 141 | key: ${{ runner.os }}-js-${{ hashFiles('**/package.json') }} 142 | restore-keys: | 143 | ${{ runner.os }}-js- 144 | - name: 读入环境信息 145 | run: | 146 | echo ${{ format('version {0}', env.version ) }} # 版本号 147 | - name: 安装 go 148 | uses: actions/setup-go@v4 149 | with: 150 | go-version: '^1.21.0' 151 | cache-dependency-path: | 152 | **/go.sum 153 | **/go.mod 154 | go-version-file: 'go.mod' 155 | - run: go version 156 | - name: 安装 UPX 157 | uses: crazy-max/ghaction-upx@v2 158 | with: 159 | install-only: true 160 | - name: 安装 wails 工具 161 | run: | 162 | go install github.com/wailsapp/wails/v2/cmd/wails@latest 163 | wails 164 | - name: 生成 Version.go 文件 165 | shell: bash 166 | run: | 167 | echo -e "package myModel\n\nvar Version = \"${version}\"" > myModel/Version.go 168 | cat myModel/Version.go 169 | - name: 编译exe 170 | run: | 171 | wails build -webview2 embed -upx 172 | ls 173 | - name: 上传产物 174 | uses: actions/upload-artifact@v3 175 | with: 176 | name: window 177 | path: | 178 | build/bin/*.exe 179 | 180 | 181 | jobs4: 182 | needs: [ jobs_v,jobs_macos,jobs_window ] 183 | name: 发布版本 184 | runs-on: ubuntu-latest 185 | env: 186 | version: ${{ needs.jobs_v.outputs.version }} 187 | body: ${{ needs.jobs_v.outputs.Body }} 188 | steps: 189 | - uses: actions/checkout@v3 190 | with: 191 | submodules: recursive 192 | fetch-depth: 0 193 | - name: 下载产物 194 | id: download 195 | uses: actions/download-artifact@v3 196 | with: 197 | path: ./ 198 | - name: 读入环境信息 199 | run: | 200 | echo ${{ format('version {0}', env.version ) }} 201 | echo ${{steps.download.outputs.download-path}} 202 | ls -R 203 | - name: 发布文件 204 | uses: ncipollo/release-action@v1 205 | with: 206 | token: ${{ secrets.GITHUB_TOKEN }} 207 | allowUpdates: true # 覆盖文件 208 | #draft: true # 草稿 自己可见 版本号会保持一样 默认是自动发布 latest 209 | #prerelease: true # 预发布 别人可以看到 版本号会继续加 210 | tag: ${{ env.version }} # 版本号 v0.1.0 211 | body: ${{ env.body }} 212 | artifacts: "macos/*.zip,macos/*.dmg,window/*.exe,window/*.zip" 213 | 214 | -------------------------------------------------------------------------------- /frontend/src/public.js: -------------------------------------------------------------------------------- 1 | const parseDimension = (value) => { 2 | //检查是否包含 vw vh % 等单位 3 | if (typeof value === 'string') { 4 | if(value === "inherit" || value === "auto"){ 5 | return value; 6 | } 7 | if(value.includes('v') || value.includes('%')){ 8 | return value; 9 | } 10 | } 11 | return `${parseInt(value)}px`; 12 | }; 13 | 14 | const getItemStyle = (item) => { 15 | const style = { 16 | top: parseDimension(item.top), 17 | left: parseDimension(item.left), 18 | width: parseDimension(item.width), 19 | height: parseDimension(item.height), 20 | border: item.border, 21 | background: item.background, 22 | zIndex: item.层级, 23 | color: item.textCorlor, 24 | }; 25 | 26 | return style; 27 | }; 28 | 29 | const getItemStyle2 = (item) => { 30 | // console.log("??"); 31 | let style = { 32 | top: parseDimension(item.top), 33 | left: parseDimension(item.left), 34 | width: parseDimension(item.width), 35 | height: parseDimension(item.height), 36 | }; 37 | // const element窗口 = document.getElementById("窗口"); 38 | // if (element窗口) { 39 | // const rect = element窗口.getBoundingClientRect(); 40 | // // style.top = parseInt(style.top) + rect.top + "px"; 41 | // // style.left = parseInt(style.left) + rect.left + "px"; 42 | // } 43 | 44 | const designer = document.getElementById("designer"); 45 | let rect_designer = {} 46 | if (designer) { 47 | rect_designer = designer.getBoundingClientRect(); 48 | } else { 49 | return style 50 | } 51 | 52 | const element = document.querySelector(`[data-id="${item.data_id}"]`); 53 | if (element) { 54 | //获取元素在浏览器中的绝对位置 55 | const rect = element.getBoundingClientRect(); 56 | style.top = `${rect.top - rect_designer.top}px`; 57 | style.left = `${rect.left - rect_designer.left}px`; 58 | style.width = `${rect.width}px`; 59 | style.height = `${rect.height}px`; 60 | } else { 61 | style.display = "none" 62 | return style; 63 | } 64 | if (style.top == "0px" && style.left == "0px" && style.width == "0px" && style.height == "0px") { 65 | style.display = "none" 66 | return style; 67 | } 68 | style.display = "block" 69 | 70 | return style; 71 | }; 72 | const getItemStyleShape = (item) => { 73 | const style = { 74 | top: parseDimension(item.top), 75 | left: parseDimension(item.left), 76 | right: parseDimension(item.right), 77 | bottom: parseDimension(item.bottom), 78 | width: parseDimension(item.width), 79 | height: parseDimension(item.height), 80 | border: item.border, 81 | background: item.background, 82 | zIndex: item.层级, 83 | position: 'absolute', 84 | overflowY: item.overflowY || 'visible', 85 | overflowX: item.overflowX || 'visible' 86 | }; 87 | 88 | 89 | 90 | if (item.position !== undefined) { 91 | style.position = item.position; 92 | } 93 | if (item.图片 !== undefined) { 94 | if (item.backgroundSize !== undefined) { 95 | style.backgroundSize = '100% 100%'; 96 | } 97 | if (item.backgroundRepeat !== undefined) { 98 | style.backgroundRepeat = 'no-repeat'; 99 | } 100 | if (item.backgroundPosition !== undefined) { 101 | style.backgroundPosition = 'center'; 102 | } 103 | if (item.backgroundAttachment !== undefined) { 104 | style.backgroundAttachment = 'scroll'; 105 | } 106 | style.backgroundImage = `url(${item.图片})`; 107 | style.backgroundSize = item.backgroundSize 108 | style.backgroundRepeat = item.backgroundRepeat 109 | style.backgroundPosition = item.backgroundPosition 110 | style.backgroundAttachment = item.backgroundAttachment 111 | } 112 | if (item.fontSize !== undefined) { 113 | item.fontSize = item.fontSize || 12; 114 | } 115 | 116 | return style; 117 | }; 118 | 119 | 120 | /* 生成组件对应关系方便ide 提示 */ 121 | 122 | function generateComponentCode(components, parentPath = '') { 123 | const codeLines = []; 124 | let k = 0; 125 | let codeLine; 126 | for (const component of components) { 127 | let componentName = component["名称"]; 128 | const componentPath = `${parentPath}.子组件[${k}]`; 129 | const componentPath2 = `${parentPath}`; 130 | k = k + 1; 131 | // componentName 如果带有空格 删除空格 并且把后面1个字母大写 132 | if (componentName) { 133 | if (componentName.includes(" ")) { 134 | const arr = componentName.split(" "); 135 | let newName = ""; 136 | for (let i = 0; i < arr.length; i++) { 137 | newName = newName + arr[i].charAt(0).toUpperCase() + arr[i].slice(1); 138 | } 139 | componentName = newName; 140 | } 141 | } 142 | 143 | 144 | codeLine = `组件.${componentName} = list[0]${componentPath}`; 145 | if (componentName == "" || componentName == undefined) { 146 | } else { 147 | codeLines.push(codeLine); 148 | } 149 | 150 | if (component["子组件"] && component["子组件"].length > 0) { 151 | const childCodeLines = generateComponentCode(component["子组件"], componentPath); 152 | codeLines.push(...childCodeLines); 153 | } 154 | } 155 | 156 | return codeLines; 157 | } 158 | 159 | function 生成辅助代码(obj) { 160 | const codeLines = generateComponentCode(obj); 161 | let code = " 组件.窗口 = list[0]\r\n" 162 | for (const codeLine of codeLines) { 163 | code = code + " " + codeLine + "\r\n" 164 | } 165 | let codeTpl = ` 166 | function __辅助代码(list, 组件) { 167 | ${code} 168 | return 组件 169 | } 170 | export default __辅助代码 171 | ` 172 | return codeTpl 173 | } 174 | 175 | // const jsonData = require('./design.json'); 176 | // console.log(生成辅助代码(jsonData[0].子组件)) 177 | 178 | 179 | function 取父目录(path) { 180 | // 将所有的反斜杠 \ 替换为斜杠 / 181 | var convertedPath = path.replace(/\\/g, '/'); 182 | 183 | // 使用正则表达式获取父目录 184 | var parentDirectory = convertedPath.replace(/\/[^/]*$/, ''); 185 | 186 | return parentDirectory; 187 | } 188 | 189 | function InsertCode(jscode, insertionCode) { 190 | // 获取函数名称 窗口.按钮3被点击 = function () { 截取 按钮3被点击 191 | const 函数名称 = insertionCode.substring(insertionCode.indexOf(".") + 1, insertionCode.indexOf("=")).trim(); 192 | 193 | // 检查是否已经存在 194 | if (jscode.includes(函数名称)) { 195 | return jscode; 196 | } 197 | 198 | // Define the regular expression pattern 199 | const pattern = `(\\/\\/Don't delete the event function flag[^\\n]*)`; 200 | 201 | // Compile the regular expression 202 | const re = new RegExp(pattern); 203 | 204 | // Replace the matching pattern with the insertion code 205 | const result = jscode.replace(re, `${insertionCode}$1`); 206 | 207 | return result; 208 | } 209 | 210 | export {getItemStyle, getItemStyle2, getItemStyleShape, 生成辅助代码, 取父目录, InsertCode}; -------------------------------------------------------------------------------- /frontend/src/components/boxs/el/CommonLayout/CommonLayout.vue: -------------------------------------------------------------------------------- 1 | 132 | 133 | 160 | 164 | -------------------------------------------------------------------------------- /frontend/src/win/design.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "1", 4 | "name": "Win", 5 | "componentName": "Window", 6 | "text": "verride Manager", 7 | "top": "0", 8 | "left": "0", 9 | "width": "700", 10 | "height": "600", 11 | "background": "rgba(0, 0, 0, 0.05)", 12 | "noPlace": false, 13 | "noDrag": true, 14 | "disable": false, 15 | "visible": true, 16 | "zIndex": 0, 17 | "childComponents": [ 18 | { 19 | "top": "0", 20 | "left": "0", 21 | "width": "100%", 22 | "height": "100%", 23 | "value": "3", 24 | "noPlace": true, 25 | "visible": true, 26 | "disable": false, 27 | "zIndex": 0, 28 | "overflowY": "hidden", 29 | "overflowX": "hidden", 30 | "type": "border-card", 31 | "tagPosition": "top", 32 | "childComponents": [ 33 | { 34 | "id": "id-65309", 35 | "name": "ContentArea3", 36 | "text": "override 配置", 37 | "componentName": "elContainer", 38 | "top": "0", 39 | "left": "0", 40 | "width": "100%", 41 | "height": "100%", 42 | "noPlace": false, 43 | "noDrag": true, 44 | "visible": true, 45 | "disable": false, 46 | "pid": "id-13078", 47 | "childComponents": [ 48 | { 49 | "top": "13", 50 | "left": "17", 51 | "width": "669", 52 | "height": "466", 53 | "noPlace": true, 54 | "visible": true, 55 | "disable": false, 56 | "zIndex": 0, 57 | "size": "custom", 58 | "内容": "", 59 | "type": "textarea", 60 | "placeholder": "请输入..", 61 | "maxlength": -1, 62 | "id": "id-41279", 63 | "componentName": "elTextEdit", 64 | "componentRawName": "TextEdit", 65 | "name": "编辑框1", 66 | "text": "", 67 | "fid": "id-65309", 68 | "data_id": "6aa594" 69 | }, 70 | { 71 | "top": 494, 72 | "left": 15, 73 | "width": "76", 74 | "height": "40", 75 | "noPlace": true, 76 | "buttonType": "default", 77 | "visible": true, 78 | "disable": false, 79 | "size": "custom", 80 | "zIndex": 0, 81 | "text": "启动服务", 82 | "id": "id-66742", 83 | "componentName": "elButton", 84 | "componentRawName": "Button", 85 | "name": "按钮_启动服务", 86 | "fid": "id-65309", 87 | "data_id": "802b92", 88 | "event_click": "按钮_启动服务被单击" 89 | }, 90 | { 91 | "top": "491", 92 | "left": "199", 93 | "width": "327", 94 | "height": "40", 95 | "noPlace": true, 96 | "visible": true, 97 | "disable": false, 98 | "zIndex": 0, 99 | "size": "default", 100 | "truncated": false, 101 | "tag": "p", 102 | "tagPosition": "text-left-center", 103 | "corlor": "#606266", 104 | "text": "状态: 未启动", 105 | "id": "id-47778", 106 | "componentName": "elLabel", 107 | "componentRawName": "Label", 108 | "name": "标签1", 109 | "fid": "id-65309", 110 | "data_id": "d5505e" 111 | }, 112 | { 113 | "top": 494, 114 | "left": 106, 115 | "width": "76", 116 | "height": "40", 117 | "noPlace": true, 118 | "buttonType": "default", 119 | "visible": true, 120 | "disable": false, 121 | "size": "custom", 122 | "zIndex": 0, 123 | "text": "重置配置", 124 | "id": "id-48794", 125 | "componentName": "elButton", 126 | "componentRawName": "Button", 127 | "name": "按钮_重置配置", 128 | "fid": "id-65309", 129 | "data_id": "33f75f", 130 | "event_click": "按钮_重置配置被单击" 131 | }, 132 | { 133 | "top": 494, 134 | "left": 605, 135 | "width": "76", 136 | "height": "40", 137 | "noPlace": true, 138 | "buttonType": "default", 139 | "visible": true, 140 | "disable": false, 141 | "size": "custom", 142 | "zIndex": 0, 143 | "text": "保存配置", 144 | "id": "id-27078", 145 | "componentName": "elButton", 146 | "componentRawName": "Button", 147 | "name": "按钮_保存配置", 148 | "fid": "id-65309", 149 | "data_id": "11b6ed", 150 | "event_click": "按钮_保存配置被单击" 151 | } 152 | ], 153 | "data_id": "130ec7" 154 | }, 155 | { 156 | "id": "id-20457", 157 | "name": "ContentArea4", 158 | "text": "软件设置", 159 | "componentName": "elContainer", 160 | "top": "0", 161 | "left": "0", 162 | "width": "100%", 163 | "height": "100%", 164 | "noPlace": false, 165 | "noDrag": true, 166 | "visible": true, 167 | "disable": false, 168 | "pid": "id-13078", 169 | "childComponents": [ 170 | { 171 | "top": "26", 172 | "left": "40", 173 | "width": "76", 174 | "height": "40", 175 | "noPlace": true, 176 | "buttonType": "default", 177 | "visible": true, 178 | "disable": false, 179 | "size": "custom", 180 | "zIndex": 0, 181 | "text": "检查更新", 182 | "id": "id-21196", 183 | "componentName": "elButton", 184 | "componentRawName": "Button", 185 | "name": "按钮_检查更新", 186 | "fid": "id-20457", 187 | "data_id": "c572ac", 188 | "event_click": "按钮_检查更新被单击" 189 | } 190 | ], 191 | "data_id": "ab919b" 192 | }, 193 | { 194 | "id": "id-49704", 195 | "name": "ContentArea5", 196 | "text": "vscode配置", 197 | "componentName": "elContainer", 198 | "top": "0", 199 | "left": "0", 200 | "width": "100%", 201 | "height": "100%", 202 | "noPlace": false, 203 | "noDrag": true, 204 | "visible": true, 205 | "disable": false, 206 | "pid": "id-13078", 207 | "childComponents": [ 208 | { 209 | "top": "18", 210 | "left": "17", 211 | "width": "651", 212 | "height": "322", 213 | "noPlace": true, 214 | "visible": true, 215 | "disable": false, 216 | "zIndex": 0, 217 | "size": "custom", 218 | "内容": "", 219 | "type": "textarea", 220 | "placeholder": "请输入..", 221 | "maxlength": -1, 222 | "id": "id-54714", 223 | "componentName": "elTextEdit", 224 | "componentRawName": "TextEdit", 225 | "name": "编辑框2", 226 | "text": "编辑框2", 227 | "fid": "id-49704", 228 | "data_id": "e141df" 229 | }, 230 | { 231 | "top": "358", 232 | "left": "21", 233 | "width": "526", 234 | "height": "123", 235 | "noPlace": true, 236 | "visible": true, 237 | "disable": false, 238 | "zIndex": 0, 239 | "size": "default", 240 | "truncated": false, 241 | "tag": "p", 242 | "tagPosition": "text-top-left", 243 | "corlor": "#606266", 244 | "text": "教程", 245 | "id": "id-39613", 246 | "componentName": "elLabel", 247 | "componentRawName": "Label", 248 | "name": "标签2", 249 | "fid": "id-49704", 250 | "data_id": "883479" 251 | }, 252 | { 253 | "top": "488", 254 | "left": "17", 255 | "width": "258", 256 | "height": "40", 257 | "noPlace": true, 258 | "visible": true, 259 | "disable": false, 260 | "zIndex": 0, 261 | "size": "default", 262 | "truncated": false, 263 | "tag": "p", 264 | "tagPosition": "text-center", 265 | "corlor": "#606266", 266 | "text": "打开详细教程教程", 267 | "id": "id-79669", 268 | "componentName": "elLabel", 269 | "componentRawName": "Label", 270 | "name": "标签3", 271 | "fid": "id-49704", 272 | "data_id": "208c8b", 273 | "event_click": "标签3被单击" 274 | }, 275 | { 276 | "top": "352", 277 | "left": "587", 278 | "width": "76", 279 | "height": "40", 280 | "noPlace": true, 281 | "buttonType": "default", 282 | "visible": true, 283 | "disable": false, 284 | "size": "custom", 285 | "zIndex": 0, 286 | "text": "复制配置", 287 | "id": "id-19657", 288 | "componentName": "elButton", 289 | "componentRawName": "Button", 290 | "name": "按钮1", 291 | "fid": "id-49704", 292 | "data_id": "05b11e", 293 | "event_click": "按钮1被单击" 294 | } 295 | ], 296 | "data_id": "430c6a" 297 | }, 298 | { 299 | "id": "id-77320", 300 | "name": "ContentArea1", 301 | "text": "日志", 302 | "componentName": "elContainer", 303 | "top": "0", 304 | "left": "0", 305 | "width": "100%", 306 | "height": "100%", 307 | "noPlace": false, 308 | "noDrag": true, 309 | "visible": true, 310 | "disable": false, 311 | "pid": "id-13078", 312 | "childComponents": [ 313 | { 314 | "top": "9", 315 | "left": "11", 316 | "width": "670", 317 | "height": "374", 318 | "noPlace": true, 319 | "visible": true, 320 | "disable": false, 321 | "zIndex": 0, 322 | "size": "custom", 323 | "内容": "", 324 | "type": "textarea", 325 | "placeholder": "请输入..", 326 | "maxlength": -1, 327 | "id": "id-34301", 328 | "componentName": "elTextEdit", 329 | "componentRawName": "TextEdit", 330 | "name": "编辑框3", 331 | "text": "编辑框3", 332 | "fid": "id-77320", 333 | "data_id": "b9dda5" 334 | } 335 | ], 336 | "data_id": "195f1e" 337 | } 338 | ], 339 | "id": "id-13078", 340 | "componentName": "elTabs", 341 | "componentRawName": "Tabs", 342 | "name": "选择夹3", 343 | "fid": "1", 344 | "data_id": "7f068e" 345 | } 346 | ], 347 | "data_id": "83546e", 348 | "event_created": "Win创建完毕" 349 | } 350 | ] -------------------------------------------------------------------------------- /myModel/自动更新模块.go: -------------------------------------------------------------------------------- 1 | package myModel 2 | 3 | import ( 4 | "archive/zip" 5 | "encoding/json" 6 | "fmt" 7 | "github.com/duolabmeng6/goefun/ecore" 8 | "github.com/ncruces/zenity" 9 | "io" 10 | "net/http" 11 | "os" 12 | "os/exec" 13 | "os/user" 14 | "path/filepath" 15 | "runtime" 16 | "strings" 17 | "time" 18 | ) 19 | 20 | var 应用名称 = "overrideManager" 21 | var owner = "duolabmeng6" // GitHub 仓库的所有者 22 | var repo = "overrideManager" // GitHub 仓库的名称 23 | 24 | type GithubJSONData []struct { 25 | URL string `json:"url"` 26 | AssetsURL string `json:"assets_url"` 27 | UploadURL string `json:"upload_url"` 28 | HTMLURL string `json:"html_url"` 29 | ID int `json:"id"` 30 | Author struct { 31 | Login string `json:"login"` 32 | ID int `json:"id"` 33 | NodeID string `json:"node_id"` 34 | AvatarURL string `json:"avatar_url"` 35 | GravatarID string `json:"gravatar_id"` 36 | URL string `json:"url"` 37 | HTMLURL string `json:"html_url"` 38 | FollowersURL string `json:"followers_url"` 39 | FollowingURL string `json:"following_url"` 40 | GistsURL string `json:"gists_url"` 41 | StarredURL string `json:"starred_url"` 42 | SubscriptionsURL string `json:"subscriptions_url"` 43 | OrganizationsURL string `json:"organizations_url"` 44 | ReposURL string `json:"repos_url"` 45 | EventsURL string `json:"events_url"` 46 | ReceivedEventsURL string `json:"received_events_url"` 47 | Type string `json:"type"` 48 | SiteAdmin bool `json:"site_admin"` 49 | } `json:"author"` 50 | NodeID string `json:"node_id"` 51 | TagName string `json:"tag_name"` 52 | TargetCommitish string `json:"target_commitish"` 53 | Name string `json:"name"` 54 | Draft bool `json:"draft"` 55 | Prerelease bool `json:"prerelease"` 56 | CreatedAt time.Time `json:"created_at"` 57 | PublishedAt time.Time `json:"published_at"` 58 | Assets []struct { 59 | URL string `json:"url"` 60 | ID int `json:"id"` 61 | NodeID string `json:"node_id"` 62 | Name string `json:"name"` 63 | Label string `json:"label"` 64 | Uploader struct { 65 | Login string `json:"login"` 66 | ID int `json:"id"` 67 | NodeID string `json:"node_id"` 68 | AvatarURL string `json:"avatar_url"` 69 | GravatarID string `json:"gravatar_id"` 70 | URL string `json:"url"` 71 | HTMLURL string `json:"html_url"` 72 | FollowersURL string `json:"followers_url"` 73 | FollowingURL string `json:"following_url"` 74 | GistsURL string `json:"gists_url"` 75 | StarredURL string `json:"starred_url"` 76 | SubscriptionsURL string `json:"subscriptions_url"` 77 | OrganizationsURL string `json:"organizations_url"` 78 | ReposURL string `json:"repos_url"` 79 | EventsURL string `json:"events_url"` 80 | ReceivedEventsURL string `json:"received_events_url"` 81 | Type string `json:"type"` 82 | SiteAdmin bool `json:"site_admin"` 83 | } `json:"uploader"` 84 | ContentType string `json:"content_type"` 85 | State string `json:"state"` 86 | Size int `json:"size"` 87 | DownloadCount int `json:"download_count"` 88 | CreatedAt time.Time `json:"created_at"` 89 | UpdatedAt time.Time `json:"updated_at"` 90 | BrowserDownloadURL string `json:"browser_download_url"` 91 | } `json:"assets"` 92 | TarballURL string `json:"tarball_url"` 93 | ZipballURL string `json:"zipball_url"` 94 | Body string `json:"body"` 95 | } 96 | type ReleaseInfo struct { 97 | Version string `json:"版本号"` 98 | DownloadURLs []string `json:"下载地址列表"` 99 | MacDownloadURL string `json:"mac下载地址"` 100 | WinDownloadURL string `json:"win下载地址"` 101 | Changelog string `json:"更新内容"` 102 | ReleaseTime string `json:"发布时间"` 103 | } 104 | 105 | func E获取Github仓库Releases版本和更新内容() *ReleaseInfo { 106 | //owner := "duolabmeng6" // GitHub 仓库的所有者 107 | //repo := "GoEasyDesigner" // GitHub 仓库的名称 108 | var urls []string 109 | _url := fmt.Sprintf("https://api.github.com/repos/%s/%s/releases", owner, repo) 110 | urls = append(urls, _url) 111 | //_url = fmt.Sprintf("https://go.kenhong.com/releases_latest.json") 112 | //urls = append(urls, _url) 113 | // 访问urls中的内容 如果第一个访问失败了 就继续下一个 114 | var resp *http.Response 115 | var err error 116 | for _, url := range urls { 117 | resp, err = http.Get(url) 118 | if err == nil { 119 | if resp.StatusCode != http.StatusOK { 120 | fmt.Println("请求失败:", resp.Status, url) 121 | continue 122 | } 123 | break 124 | } 125 | fmt.Println("请求失败:", err) 126 | } 127 | defer resp.Body.Close() 128 | 129 | body, err := io.ReadAll(resp.Body) 130 | if err != nil { 131 | fmt.Println("读取响应失败:", err) 132 | return nil 133 | } 134 | //var err error 135 | //body := ecore.E读入文件("/Users/ll/Desktop/goproject/v3fanyi/mymodel/githubdata.json") 136 | 137 | var releases GithubJSONData 138 | 139 | err = json.Unmarshal(body, &releases) 140 | if err != nil { 141 | fmt.Println("解析响应失败:", err) 142 | return nil 143 | } 144 | if len(releases) <= 0 { 145 | return nil 146 | } 147 | 148 | //latestRelease := releases[0] 149 | //version := latestRelease.TagName 150 | //fmt.Println("最新的 Release 版本号:", version) 151 | //fmt.Println("最新的 Release 版本号:", latestRelease.Body) 152 | //// 循环获取 文件名和下载地址 153 | //for _, asset := range latestRelease.Assets { 154 | // fmt.Println(asset.Name, asset.BrowserDownloadURL) 155 | //} 156 | 157 | latestRelease := releases[0] 158 | version := latestRelease.TagName 159 | downloadURLs := make([]string, 0) 160 | macDownloadURL := "" 161 | winDownloadURL := "" 162 | 163 | // 获取文件名和下载地址 164 | for _, asset := range latestRelease.Assets { 165 | downloadURLs = append(downloadURLs, asset.BrowserDownloadURL) 166 | //查找文本是否包含 macos.zip 和 .exe 不区分大小写 167 | if strings.Contains(strings.ToLower(asset.Name), "macos.zip") { 168 | macDownloadURL = asset.BrowserDownloadURL 169 | } 170 | if strings.Contains(strings.ToLower(asset.Name), ".exe") { 171 | winDownloadURL = asset.BrowserDownloadURL 172 | } 173 | 174 | } 175 | 176 | releaseInfo := &ReleaseInfo{ 177 | Version: version, 178 | DownloadURLs: downloadURLs, 179 | MacDownloadURL: "https://mirror.ghproxy.com/" + macDownloadURL, 180 | WinDownloadURL: "https://mirror.ghproxy.com/" + winDownloadURL, 181 | Changelog: latestRelease.Body, 182 | ReleaseTime: ecore.E到时间(latestRelease.CreatedAt.String()).E时间到文本("Y-m-d H:i:s"), 183 | } 184 | 185 | return releaseInfo 186 | } 187 | 188 | func E下载带进度回调(下载地址 string, 文件保存路径 string, fc func(进度 float64)) error { 189 | resp, err := http.Get(下载地址) 190 | if err != nil { 191 | return err 192 | } 193 | defer resp.Body.Close() 194 | 195 | out, err := os.Create(文件保存路径) 196 | if err != nil { 197 | return err 198 | } 199 | defer out.Close() 200 | 201 | 下载文件大小 := resp.ContentLength 202 | 已下载大小 := int64(0) 203 | buf := make([]byte, 1024) 204 | 205 | 进度Ticker := time.Tick(time.Millisecond * 50) //降低刷新的频率 206 | 207 | for { 208 | n, err := resp.Body.Read(buf) 209 | if n > 0 { 210 | _, err := out.Write(buf[:n]) 211 | if err != nil { 212 | return err 213 | } 214 | 215 | 已下载大小 += int64(n) 216 | 进度 := float64(已下载大小) / float64(下载文件大小) * 100 217 | 218 | select { 219 | case <-进度Ticker: 220 | if fc != nil { 221 | fc(进度) // 调用进度回调函数 222 | } 223 | default: 224 | // 不触发进度回调 225 | } 226 | } 227 | 228 | if err != nil { 229 | if err != io.EOF { 230 | return err 231 | } 232 | break 233 | } 234 | } 235 | fc(100) // 调用进度回调函数 236 | 237 | return nil 238 | } 239 | 240 | func E系统是否为window系统() bool { 241 | return strings.ToLower(runtime.GOOS) == "windows" 242 | } 243 | 244 | func E系统是否为linux系统() bool { 245 | return strings.ToLower(runtime.GOOS) == "linux" 246 | } 247 | 248 | func E系统是否为mac系统() bool { 249 | return strings.ToLower(runtime.GOOS) == "darwin" 250 | } 251 | 252 | // E是否为调试模式 253 | // 判断当前的环境是否为编译后的程序 254 | // 真为调试模式 255 | // 假为编译后的程序 256 | func E是否为调试模式() bool { 257 | debugMode := false 258 | if os.Getenv("DEBUG") != "" { 259 | debugMode = true 260 | } 261 | 262 | return debugMode 263 | } 264 | 265 | func 取自身MacOs应用路径() string { 266 | // 如果不处于编译状态反馈空 267 | 编译后路径, err := os.Executable() 268 | //println("编译后路径", 编译后路径) 269 | if err != nil { 270 | return "" 271 | } 272 | // 调试模式下的路径 273 | //编译后路径 = "/Users/ll/Desktop/goproject/v3fanyi/bin/qoq.app/Contents/MacOS/qoq" 274 | // 编译后路径 取父目录 275 | 编译后路径 = 编译后路径[:strings.LastIndex(编译后路径, "/")] 276 | 277 | app目录 := 编译后路径[:strings.LastIndex(编译后路径, "/")] 278 | app目录 = app目录[:strings.LastIndex(app目录, "/")] 279 | 父目录名称 := 编译后路径[strings.LastIndex(编译后路径, "/")+1:] 280 | if 父目录名称 == "MacOS" { 281 | return app目录 282 | } else { 283 | return "" 284 | } 285 | } 286 | 287 | func E更新自己MacOS应用(资源压缩包 string, 应用名称 string) (bool, string) { 288 | //资源压缩包 = "/Users/ll/Downloads/GoEasyDesigner_MacOS.zip" 289 | //应用名称 = "GoEasyDesigner.app" 290 | //println("资源压缩包", 资源压缩包) 291 | //println("应用名称", 应用名称) 292 | 293 | MacOs应用路径 := 取自身MacOs应用路径() 294 | //fmt.Println("MacOs应用路径", MacOs应用路径) 295 | //MacOs应用路径 := "/Users/ll/Downloads/" + 应用名称 296 | if MacOs应用路径 != "" { 297 | app目录父目录 := MacOs应用路径[:strings.LastIndex(MacOs应用路径, "/")] 298 | fmt.Printf("资源压缩包 %s app目录父目录%s MacOs应用路径%s \r\n", 资源压缩包, app目录父目录, MacOs应用路径) 299 | if MacOs应用路径 != "" { 300 | 解压结果 := zip解压(资源压缩包, app目录父目录, []string{应用名称 + "/Contents/"}) 301 | println("解压结果", 解压结果) 302 | // 解压完成后删除压缩包 303 | //os.Remove(资源压缩包) 304 | MacOs应用路径 = filepath.Join(app目录父目录, 应用名称) 305 | // QApplication.quit() 306 | 应用名称 = 应用名称[:strings.LastIndex(应用名称, ".")] 307 | 运行命令 := fmt.Sprintf("killall %s && open -n -a %s", 应用名称, MacOs应用路径) 308 | println("运行命令", 运行命令) 309 | cmd := exec.Command("sh", "-c", 运行命令) 310 | err := cmd.Run() 311 | if err != nil { 312 | fmt.Println(err) 313 | return false, "killall失败 请自己重启应用" 314 | } 315 | return true, MacOs应用路径 316 | } 317 | } else { 318 | fmt.Println("非MacOS编译环境") 319 | return false, "非MacOS编译环境" 320 | } 321 | fmt.Println("应用路径为空") 322 | return false, "应用路径为空" 323 | } 324 | 325 | func zip解压(压缩包的路径 string, 解压目录 string, 允许解压路径前缀 []string) bool { 326 | // 保持权限和软连接解压 327 | // 允许解压路径前缀 例如 ["my_app.app/Contents/"] 不填则全部解压 328 | 329 | 文件, err := zip.OpenReader(压缩包的路径) 330 | if err != nil { 331 | fmt.Println(err) 332 | return false 333 | } 334 | defer 文件.Close() 335 | 336 | for _, info := range 文件.File { 337 | // 检查目标文件路径是否在允许解压路径前缀中 338 | if len(允许解压路径前缀) > 0 { 339 | 允许解压 := false 340 | for _, 路径 := range 允许解压路径前缀 { 341 | if strings.HasPrefix(info.Name, 路径) { 342 | 允许解压 = true 343 | } 344 | } 345 | if !允许解压 { 346 | continue 347 | } 348 | } 349 | 350 | 文件名 := info.Name 351 | 352 | 目标文件路径 := filepath.Join(解压目录, 文件名) 353 | 354 | 权限 := info.Mode().Perm() 355 | if info.Mode()&os.ModeSymlink != 0 { // 检查是否为软连接 356 | 软连接位置, err := readLink(info) 357 | if err != nil { 358 | fmt.Println(err) 359 | continue 360 | } 361 | // 检查目标文件路径是否存在,如果存在就删除,防止创建失败 362 | if _, err := os.Lstat(目标文件路径); err == nil { 363 | os.Remove(目标文件路径) 364 | } 365 | err = os.Symlink(软连接位置, 目标文件路径) 366 | if err != nil { 367 | fmt.Println(err) 368 | } 369 | } else { 370 | // 删除文件重新解压 371 | if _, err := os.Lstat(目标文件路径); err == nil { 372 | // 检查是否为文件 373 | if !info.Mode().IsDir() { 374 | os.Remove(目标文件路径) 375 | } 376 | } 377 | err = extractFile(info, 目标文件路径) 378 | if err != nil { 379 | fmt.Println(err) 380 | } 381 | 382 | // 修改文件权限 383 | if _, err := os.Lstat(目标文件路径); err == nil { 384 | err = os.Chmod(目标文件路径, 权限) 385 | if err != nil { 386 | fmt.Println(err) 387 | } 388 | } 389 | } 390 | } 391 | 392 | return true 393 | } 394 | 395 | func readLink(info *zip.File) (string, error) { 396 | file, err := info.Open() 397 | if err != nil { 398 | return "", err 399 | } 400 | defer file.Close() 401 | 402 | linkName := make([]byte, info.FileInfo().Size()) 403 | _, err = io.ReadFull(file, linkName) 404 | if err != nil { 405 | return "", err 406 | } 407 | 408 | return string(linkName), nil 409 | } 410 | func extractFile(info *zip.File, 目标文件路径 string) error { 411 | file, err := info.Open() 412 | if err != nil { 413 | return err 414 | } 415 | defer file.Close() 416 | 417 | if info.FileInfo().IsDir() { 418 | err = os.MkdirAll(目标文件路径, info.Mode()) 419 | if err != nil { 420 | return err 421 | } 422 | } else { 423 | writer, err := os.OpenFile(目标文件路径, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, info.Mode()) 424 | if err != nil { 425 | return err 426 | } 427 | defer writer.Close() 428 | 429 | _, err = io.Copy(writer, file) 430 | if err != nil { 431 | return err 432 | } 433 | } 434 | 435 | return nil 436 | } 437 | 438 | func E取用户下载文件夹路径() string { 439 | usr, err := user.Current() 440 | if err != nil { 441 | fmt.Println("pull:", err) 442 | return "" 443 | } 444 | 下载文件夹路径 := filepath.Join(usr.HomeDir, "Downloads") 445 | return 下载文件夹路径 446 | } 447 | 448 | func 取自身路径Window() (string, error) { 449 | exe, err := os.Executable() 450 | if err != nil { 451 | return "", err 452 | } 453 | return exe, nil 454 | } 455 | 456 | func E更新自己Window应用(exe资源文件路径 string) (bool, string) { 457 | // window更新方法 458 | 自身路径Window, _ := 取自身路径Window() 459 | 460 | //文件名 := filepath.Base(自身路径Window) 461 | // 检查文件是否存在 462 | 旧的文件名 := 自身路径Window + ".old.bak" 463 | if _, err := os.Stat(旧的文件名); err == nil { 464 | // 删除文件 465 | os.Remove(旧的文件名) 466 | } 467 | 468 | os.Rename(自身路径Window, 旧的文件名) 469 | os.Rename(exe资源文件路径, 自身路径Window) 470 | 471 | // 结束自身运行然后重启自己 472 | cmd := exec.Command(自身路径Window) 473 | cmd.Args = append(cmd.Args, os.Args[1:]...) 474 | cmd.Start() 475 | 476 | os.Exit(0) // 此处退出当前进程 477 | return true, "" 478 | } 479 | 480 | func E检查更新_Mac() { 481 | 482 | 下载文件夹路径 := E取用户下载文件夹路径() 483 | info := E获取Github仓库Releases版本和更新内容() 484 | if info == nil { 485 | err := zenity.Info("检查更新失败") 486 | if err != nil { 487 | return 488 | } 489 | return 490 | } 491 | println(info.MacDownloadURL) 492 | println(下载文件夹路径) 493 | if info.Version == Version { 494 | err := zenity.Info("当前已经是最新版本") 495 | if err != nil { 496 | return 497 | } 498 | return 499 | } 500 | 501 | err := zenity.Question("软件有新版本可用,是否更新?\n当前版本:"+ 502 | Version+ 503 | "\n最新版本:"+info.Version, 504 | zenity.Title("更新提示"), 505 | zenity.Icon(zenity.QuestionIcon), 506 | zenity.OKLabel("更新"), 507 | zenity.CancelLabel("取消")) 508 | ecore.E调试输出(err) 509 | println("更新", err) 510 | if err != nil { 511 | return 512 | } 513 | progress, _ := zenity.Progress( 514 | zenity.Title("软件更新"), 515 | zenity.MaxValue(100), // 设置最大进度值为100 516 | ) 517 | 518 | progress.Text("正在下载...") 519 | 520 | err = E下载带进度回调(info.MacDownloadURL, 下载文件夹路径+"/"+应用名称+"_MacOS.zip", func(进度 float64) { 521 | fmt.Println("正在下载...", 进度) 522 | progress.Text("正在下载..." + fmt.Sprintf("%.2f", 进度) + "%") 523 | progress.Value(int(进度)) 524 | }) 525 | if err != nil { 526 | fmt.Println("下载出错:", err) 527 | zenity.Info("下载错误,检查你的网络") 528 | progress.Close() 529 | return 530 | } 531 | progress.Text("下载完成 即将完成更新") 532 | if progress.Close() != nil { 533 | fmt.Println("点击了取消") 534 | return 535 | } 536 | fmt.Println("下载完成了") 537 | flag, s := E更新自己MacOS应用(下载文件夹路径+"/"+应用名称+"_MacOS.zip", 应用名称+".app") 538 | println(flag, s) 539 | } 540 | 541 | func E检查更新_window() { 542 | 543 | 下载文件夹路径 := E取用户下载文件夹路径() 544 | info := E获取Github仓库Releases版本和更新内容() 545 | if info == nil { 546 | zenity.Info("网络原因无法获取更新信息") 547 | return 548 | } 549 | if info.Version == Version { 550 | err := zenity.Info("当前已经是最新版本") 551 | if err != nil { 552 | return 553 | } 554 | return 555 | } 556 | 557 | err := zenity.Question("软件有新版本可用,是否更新?\n当前版本:"+ 558 | Version+ 559 | "\n最新版本:"+info.Version, 560 | zenity.Title("更新提示"), 561 | zenity.Icon(zenity.QuestionIcon), 562 | zenity.OKLabel("更新"), 563 | zenity.CancelLabel("取消")) 564 | ecore.E调试输出(err) 565 | println("更新", err) 566 | if err != nil { 567 | return 568 | } 569 | progress, _ := zenity.Progress( 570 | zenity.Title("软件更新"), 571 | zenity.MaxValue(100), // 设置最大进度值为100 572 | ) 573 | 574 | progress.Text("正在下载...") 575 | 576 | err = E下载带进度回调(info.WinDownloadURL, 下载文件夹路径+"/"+应用名称+".exe", func(进度 float64) { 577 | fmt.Println("正在下载...", 进度) 578 | progress.Text("正在下载..." + fmt.Sprintf("%.2f", 进度) + "%") 579 | progress.Value(int(进度)) 580 | }) 581 | if err != nil { 582 | fmt.Println("下载出错:", err) 583 | zenity.Info("下载错误,检查你的网络") 584 | progress.Close() 585 | return 586 | } 587 | progress.Text("下载完成 即将完成更新") 588 | if progress.Close() != nil { 589 | fmt.Println("点击了取消") 590 | return 591 | } 592 | fmt.Println("下载完成了") 593 | flag, s := E更新自己Window应用(下载文件夹路径 + "/" + 应用名称 + ".exe") 594 | println(flag, s) 595 | } 596 | func E是否为window系统() bool { 597 | return runtime.GOOS == "windows" 598 | } 599 | 600 | func E是否为macOS系统() bool { 601 | return runtime.GOOS == "darwin" 602 | } 603 | 604 | func E是否为UbuntuLinux系统() bool { 605 | return runtime.GOOS == "linux" 606 | } 607 | 608 | func E检查更新() { 609 | if E是否为macOS系统() { 610 | E检查更新_Mac() 611 | } 612 | if E是否为window系统() { 613 | E检查更新_window() 614 | } 615 | } 616 | -------------------------------------------------------------------------------- /action/run_override.go: -------------------------------------------------------------------------------- 1 | package action 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "encoding/json" 7 | "errors" 8 | "fmt" 9 | "github.com/duolabmeng6/goefun/ecore" 10 | "io" 11 | "log" 12 | "net" 13 | "net/http" 14 | "net/url" 15 | "os" 16 | "reflect" 17 | "strconv" 18 | "strings" 19 | "time" 20 | 21 | "github.com/gin-gonic/gin" 22 | "github.com/tidwall/gjson" 23 | "github.com/tidwall/sjson" 24 | "golang.org/x/net/http2" 25 | ) 26 | 27 | const DefaultInstructModel = "gpt-3.5-turbo-instruct" 28 | 29 | const StableCodeModelPrefix = "stable-code" 30 | 31 | const DeepSeekCoderModel = "deepseek-coder" 32 | 33 | type config struct { 34 | Bind string `json:"bind"` 35 | ProxyUrl string `json:"proxy_url"` 36 | Timeout int `json:"timeout"` 37 | CodexApiBase string `json:"codex_api_base"` 38 | CodexApiKey string `json:"codex_api_key"` 39 | CodexApiOrganization string `json:"codex_api_organization"` 40 | CodexApiProject string `json:"codex_api_project"` 41 | CodexMaxTokens int `json:"codex_max_tokens"` 42 | CodeInstructModel string `json:"code_instruct_model"` 43 | ChatApiBase string `json:"chat_api_base"` 44 | ChatApiKey string `json:"chat_api_key"` 45 | ChatApiOrganization string `json:"chat_api_organization"` 46 | ChatApiProject string `json:"chat_api_project"` 47 | ChatMaxTokens int `json:"chat_max_tokens"` 48 | ChatModelDefault string `json:"chat_model_default"` 49 | ChatModelMap map[string]string `json:"chat_model_map"` 50 | ChatLocale string `json:"chat_locale"` 51 | AuthToken string `json:"auth_token"` 52 | } 53 | 54 | func readConfig(content string) *config { 55 | //content, err := os.ReadFile("config.json") 56 | //if nil != err { 57 | // log.Fatal(err) 58 | //} 59 | var err error 60 | 61 | _cfg := &config{} 62 | err = json.Unmarshal([]byte(content), &_cfg) 63 | if nil != err { 64 | log.Fatal(err) 65 | } 66 | 67 | v := reflect.ValueOf(_cfg).Elem() 68 | t := v.Type() 69 | 70 | for i := 0; i < v.NumField(); i++ { 71 | field := v.Field(i) 72 | tag := t.Field(i).Tag.Get("json") 73 | if tag == "" { 74 | continue 75 | } 76 | 77 | value, exists := os.LookupEnv("OVERRIDE_" + strings.ToUpper(tag)) 78 | if !exists { 79 | continue 80 | } 81 | 82 | switch field.Kind() { 83 | case reflect.String: 84 | field.SetString(value) 85 | case reflect.Bool: 86 | if boolValue, err := strconv.ParseBool(value); err == nil { 87 | field.SetBool(boolValue) 88 | } 89 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 90 | if intValue, err := strconv.ParseInt(value, 10, 64); err == nil { 91 | field.SetInt(intValue) 92 | } 93 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 94 | if uintValue, err := strconv.ParseUint(value, 10, 64); err == nil { 95 | field.SetUint(uintValue) 96 | } 97 | case reflect.Float32, reflect.Float64: 98 | if floatValue, err := strconv.ParseFloat(value, field.Type().Bits()); err == nil { 99 | field.SetFloat(floatValue) 100 | } 101 | } 102 | } 103 | if _cfg.CodeInstructModel == "" { 104 | _cfg.CodeInstructModel = DefaultInstructModel 105 | } 106 | 107 | if _cfg.CodexMaxTokens == 0 { 108 | _cfg.CodexMaxTokens = 500 109 | } 110 | 111 | if _cfg.ChatMaxTokens == 0 { 112 | _cfg.ChatMaxTokens = 4096 113 | } 114 | 115 | return _cfg 116 | } 117 | 118 | func getClient(cfg *config) (*http.Client, error) { 119 | transport := &http.Transport{ 120 | ForceAttemptHTTP2: true, 121 | DisableKeepAlives: false, 122 | } 123 | 124 | err := http2.ConfigureTransport(transport) 125 | if nil != err { 126 | return nil, err 127 | } 128 | 129 | if "" != cfg.ProxyUrl { 130 | proxyUrl, err := url.Parse(cfg.ProxyUrl) 131 | if nil != err { 132 | return nil, err 133 | } 134 | 135 | transport.Proxy = http.ProxyURL(proxyUrl) 136 | } 137 | 138 | client := &http.Client{ 139 | Transport: transport, 140 | Timeout: time.Duration(cfg.Timeout) * time.Second, 141 | } 142 | 143 | return client, nil 144 | } 145 | 146 | func abortCodex(c *gin.Context, status int) { 147 | c.Header("Content-Type", "text/event-stream") 148 | 149 | c.String(status, "data: [DONE]\n") 150 | c.Abort() 151 | } 152 | 153 | func closeIO(c io.Closer) { 154 | err := c.Close() 155 | if nil != err { 156 | log.Println(err) 157 | } 158 | } 159 | 160 | type ProxyService struct { 161 | cfg *config 162 | client *http.Client 163 | } 164 | 165 | func NewProxyService(cfg *config) (*ProxyService, error) { 166 | client, err := getClient(cfg) 167 | if nil != err { 168 | return nil, err 169 | } 170 | 171 | return &ProxyService{ 172 | cfg: cfg, 173 | client: client, 174 | }, nil 175 | } 176 | func AuthMiddleware(authToken string) gin.HandlerFunc { 177 | return func(c *gin.Context) { 178 | token := c.Param("token") 179 | if token != authToken { 180 | c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"}) 181 | c.Abort() 182 | return 183 | } 184 | c.Next() 185 | } 186 | } 187 | 188 | func (s *ProxyService) InitRoutes(e *gin.Engine) { 189 | e.GET("/_ping", s.pong) 190 | e.GET("/models", s.models) 191 | e.GET("/v1/models", s.models) 192 | authToken := s.cfg.AuthToken // replace with your dynamic value as needed 193 | if authToken != "" { 194 | // 鉴权 195 | v1 := e.Group("/:token/v1/", AuthMiddleware(authToken)) 196 | { 197 | v1.POST("/chat/completions", s.completions) 198 | v1.POST("/engines/copilot-codex/completions", s.codeCompletions) 199 | 200 | v1.POST("/v1/chat/completions", s.completions) 201 | v1.POST("/v1/engines/copilot-codex/completions", s.codeCompletions) 202 | } 203 | } else { 204 | e.POST("/v1/chat/completions", s.completions) 205 | e.POST("/v1/engines/copilot-codex/completions", s.codeCompletions) 206 | 207 | e.POST("/v1/v1/chat/completions", s.completions) 208 | e.POST("/v1/v1/engines/copilot-codex/completions", s.codeCompletions) 209 | } 210 | } 211 | 212 | type Pong struct { 213 | Now int `json:"now"` 214 | Status string `json:"status"` 215 | Ns1 string `json:"ns1"` 216 | } 217 | 218 | func (s *ProxyService) pong(c *gin.Context) { 219 | c.JSON(http.StatusOK, Pong{ 220 | Now: time.Now().Second(), 221 | Status: "ok", 222 | Ns1: "200 OK", 223 | }) 224 | } 225 | 226 | func (s *ProxyService) models(c *gin.Context) { 227 | c.JSON(http.StatusOK, gin.H{ 228 | "data": []gin.H{ 229 | { 230 | "capabilities": gin.H{ 231 | "family": "gpt-3.5-turbo", 232 | "object": "model_capabilities", 233 | "type": "chat", 234 | }, 235 | "id": "gpt-3.5-turbo", 236 | "name": "GPT 3.5 Turbo", 237 | "object": "model", 238 | "version": "gpt-3.5-turbo-0613", 239 | }, 240 | { 241 | "capabilities": gin.H{ 242 | "family": "gpt-3.5-turbo", 243 | "object": "model_capabilities", 244 | "type": "chat", 245 | }, 246 | "id": "gpt-3.5-turbo-0613", 247 | "name": "GPT 3.5 Turbo (2023-06-13)", 248 | "object": "model", 249 | "version": "gpt-3.5-turbo-0613", 250 | }, 251 | { 252 | "capabilities": gin.H{ 253 | "family": "gpt-4", 254 | "object": "model_capabilities", 255 | "type": "chat", 256 | }, 257 | "id": "gpt-4", 258 | "name": "GPT 4", 259 | "object": "model", 260 | "version": "gpt-4-0613", 261 | }, 262 | { 263 | "capabilities": gin.H{ 264 | "family": "gpt-4", 265 | "object": "model_capabilities", 266 | "type": "chat", 267 | }, 268 | "id": "gpt-4-0613", 269 | "name": "GPT 4 (2023-06-13)", 270 | "object": "model", 271 | "version": "gpt-4-0613", 272 | }, 273 | { 274 | "capabilities": gin.H{ 275 | "family": "gpt-4-turbo", 276 | "object": "model_capabilities", 277 | "type": "chat", 278 | }, 279 | "id": "gpt-4-0125-preview", 280 | "name": "GPT 4 Turbo (2024-01-25 Preview)", 281 | "object": "model", 282 | "version": "gpt-4-0125-preview", 283 | }, 284 | { 285 | "capabilities": gin.H{ 286 | "family": "text-embedding-ada-002", 287 | "object": "model_capabilities", 288 | "type": "embeddings", 289 | }, 290 | "id": "text-embedding-ada-002", 291 | "name": "Embedding V2 Ada", 292 | "object": "model", 293 | "version": "text-embedding-ada-002", 294 | }, 295 | { 296 | "capabilities": gin.H{ 297 | "family": "text-embedding-ada-002", 298 | "object": "model_capabilities", 299 | "type": "embeddings", 300 | }, 301 | "id": "text-embedding-ada-002-index", 302 | "name": "Embedding V2 Ada (Index)", 303 | "object": "model", 304 | "version": "text-embedding-ada-002", 305 | }, 306 | { 307 | "capabilities": gin.H{ 308 | "family": "text-embedding-3-small", 309 | "object": "model_capabilities", 310 | "type": "embeddings", 311 | }, 312 | "id": "text-embedding-3-small", 313 | "name": "Embedding V3 small", 314 | "object": "model", 315 | "version": "text-embedding-3-small", 316 | }, 317 | { 318 | "capabilities": gin.H{ 319 | "family": "text-embedding-3-small", 320 | "object": "model_capabilities", 321 | "type": "embeddings", 322 | }, 323 | "id": "text-embedding-3-small-inference", 324 | "name": "Embedding V3 small (Inference)", 325 | "object": "model", 326 | "version": "text-embedding-3-small", 327 | }, 328 | }, 329 | "object": "list", 330 | }) 331 | } 332 | 333 | func (s *ProxyService) completions(c *gin.Context) { 334 | ctx := c.Request.Context() 335 | 336 | body, err := io.ReadAll(c.Request.Body) 337 | if nil != err { 338 | c.AbortWithStatus(http.StatusBadRequest) 339 | return 340 | } 341 | 342 | model := gjson.GetBytes(body, "model").String() 343 | if mapped, ok := s.cfg.ChatModelMap[model]; ok { 344 | model = mapped 345 | } else { 346 | model = s.cfg.ChatModelDefault 347 | } 348 | body, _ = sjson.SetBytes(body, "model", model) 349 | 350 | if !gjson.GetBytes(body, "function_call").Exists() { 351 | messages := gjson.GetBytes(body, "messages").Array() 352 | lastIndex := len(messages) - 1 353 | if !strings.Contains(messages[lastIndex].Get("content").String(), "Respond in the following locale") { 354 | locale := s.cfg.ChatLocale 355 | if locale == "" { 356 | locale = "zh_CN" 357 | } 358 | body, _ = sjson.SetBytes(body, "messages."+strconv.Itoa(lastIndex)+".content", messages[lastIndex].Get("content").String()+"Respond in the following locale: "+locale+".") 359 | } 360 | } 361 | 362 | body, _ = sjson.DeleteBytes(body, "intent") 363 | body, _ = sjson.DeleteBytes(body, "intent_threshold") 364 | body, _ = sjson.DeleteBytes(body, "intent_content") 365 | 366 | if int(gjson.GetBytes(body, "max_tokens").Int()) > s.cfg.ChatMaxTokens { 367 | body, _ = sjson.SetBytes(body, "max_tokens", s.cfg.ChatMaxTokens) 368 | } 369 | 370 | proxyUrl := s.cfg.ChatApiBase + "/chat/completions" 371 | req, err := http.NewRequestWithContext(ctx, http.MethodPost, proxyUrl, io.NopCloser(bytes.NewBuffer(body))) 372 | if nil != err { 373 | c.AbortWithStatus(http.StatusInternalServerError) 374 | return 375 | } 376 | 377 | req.Header.Set("Content-Type", "application/json") 378 | req.Header.Set("Authorization", "Bearer "+s.cfg.ChatApiKey) 379 | if "" != s.cfg.ChatApiOrganization { 380 | req.Header.Set("OpenAI-Organization", s.cfg.ChatApiOrganization) 381 | } 382 | if "" != s.cfg.ChatApiProject { 383 | req.Header.Set("OpenAI-Project", s.cfg.ChatApiProject) 384 | } 385 | 386 | resp, err := s.client.Do(req) 387 | if nil != err { 388 | if errors.Is(err, context.Canceled) { 389 | c.AbortWithStatus(http.StatusRequestTimeout) 390 | return 391 | } 392 | 393 | log.Println("request conversation failed:", err.Error()) 394 | c.AbortWithStatus(http.StatusInternalServerError) 395 | return 396 | } 397 | defer closeIO(resp.Body) 398 | 399 | if resp.StatusCode != http.StatusOK { // log 400 | body, _ := io.ReadAll(resp.Body) 401 | log.Println("request completions failed:", string(body)) 402 | 403 | resp.Body = io.NopCloser(bytes.NewBuffer(body)) 404 | } 405 | 406 | c.Status(resp.StatusCode) 407 | 408 | contentType := resp.Header.Get("Content-Type") 409 | if "" != contentType { 410 | c.Header("Content-Type", contentType) 411 | } 412 | 413 | _, _ = io.Copy(c.Writer, resp.Body) 414 | } 415 | 416 | func (s *ProxyService) codeCompletions(c *gin.Context) { 417 | ctx := c.Request.Context() 418 | 419 | time.Sleep(200 * time.Millisecond) 420 | if ctx.Err() != nil { 421 | abortCodex(c, http.StatusRequestTimeout) 422 | return 423 | } 424 | 425 | body, err := io.ReadAll(c.Request.Body) 426 | if nil != err { 427 | abortCodex(c, http.StatusBadRequest) 428 | return 429 | } 430 | 431 | body = ConstructRequestBody(body, s.cfg) 432 | 433 | proxyUrl := s.cfg.CodexApiBase + "/completions" 434 | req, err := http.NewRequestWithContext(ctx, http.MethodPost, proxyUrl, io.NopCloser(bytes.NewBuffer(body))) 435 | if nil != err { 436 | abortCodex(c, http.StatusInternalServerError) 437 | return 438 | } 439 | 440 | req.Header.Set("Content-Type", "application/json") 441 | req.Header.Set("Authorization", "Bearer "+s.cfg.CodexApiKey) 442 | if "" != s.cfg.CodexApiOrganization { 443 | req.Header.Set("OpenAI-Organization", s.cfg.CodexApiOrganization) 444 | } 445 | if "" != s.cfg.CodexApiProject { 446 | req.Header.Set("OpenAI-Project", s.cfg.CodexApiProject) 447 | } 448 | 449 | resp, err := s.client.Do(req) 450 | if nil != err { 451 | if errors.Is(err, context.Canceled) { 452 | abortCodex(c, http.StatusRequestTimeout) 453 | return 454 | } 455 | 456 | log.Println("request completions failed:", err.Error()) 457 | abortCodex(c, http.StatusInternalServerError) 458 | return 459 | } 460 | defer closeIO(resp.Body) 461 | 462 | if resp.StatusCode != http.StatusOK { 463 | body, _ := io.ReadAll(resp.Body) 464 | log.Println("request completions failed:", string(body)) 465 | 466 | abortCodex(c, resp.StatusCode) 467 | return 468 | } 469 | 470 | c.Status(resp.StatusCode) 471 | 472 | contentType := resp.Header.Get("Content-Type") 473 | if "" != contentType { 474 | c.Header("Content-Type", contentType) 475 | } 476 | 477 | _, _ = io.Copy(c.Writer, resp.Body) 478 | } 479 | 480 | func ConstructRequestBody(body []byte, cfg *config) []byte { 481 | body, _ = sjson.DeleteBytes(body, "extra") 482 | body, _ = sjson.DeleteBytes(body, "nwo") 483 | body, _ = sjson.SetBytes(body, "model", cfg.CodeInstructModel) 484 | 485 | if int(gjson.GetBytes(body, "max_tokens").Int()) > cfg.CodexMaxTokens { 486 | body, _ = sjson.SetBytes(body, "max_tokens", cfg.CodexMaxTokens) 487 | } 488 | 489 | if strings.Contains(cfg.CodeInstructModel, StableCodeModelPrefix) { 490 | return constructWithStableCodeModel(body) 491 | } else if strings.HasPrefix(cfg.CodeInstructModel, DeepSeekCoderModel) { 492 | if gjson.GetBytes(body, "n").Int() > 1 { 493 | body, _ = sjson.SetBytes(body, "n", 1) 494 | } 495 | } 496 | 497 | if strings.HasSuffix(cfg.ChatApiBase, "chat") { 498 | // @Todo constructWithChatModel 499 | // 如果code base以chat结尾则构建chatModel,暂时没有好的prompt 500 | } 501 | 502 | return body 503 | } 504 | 505 | func constructWithStableCodeModel(body []byte) []byte { 506 | suffix := gjson.GetBytes(body, "suffix") 507 | prompt := gjson.GetBytes(body, "prompt") 508 | content := fmt.Sprintf("%s%s", prompt, suffix) 509 | 510 | // 创建新的 JSON 对象并添加到 body 中 511 | messages := []map[string]string{ 512 | { 513 | "role": "user", 514 | "content": content, 515 | }, 516 | } 517 | return constructWithChatModel(body, messages) 518 | } 519 | 520 | func constructWithChatModel(body []byte, messages interface{}) []byte { 521 | 522 | body, _ = sjson.SetBytes(body, "messages", messages) 523 | 524 | // fmt.Printf("Request Body: %s\n", body) 525 | // 2. 将转义的字符替换回原来的字符 526 | jsonStr := string(body) 527 | jsonStr = strings.ReplaceAll(jsonStr, "\\u003c", "<") 528 | jsonStr = strings.ReplaceAll(jsonStr, "\\u003e", ">") 529 | return []byte(jsonStr) 530 | } 531 | 532 | var server *http.Server 533 | 534 | func isPortInUse(port int) bool { 535 | conn, err := net.Listen("tcp", fmt.Sprintf(":%d", port)) 536 | if err != nil { 537 | return true 538 | } 539 | conn.Close() 540 | return false 541 | } 542 | func Run_override(configContent string, logWriter *bytes.Buffer) (bool, error) { 543 | cfg := readConfig(configContent) 544 | // 检查端口是否已被占用 545 | port := ecore.StrCut(cfg.Bind, ":$") 546 | if isPortInUse(int(ecore.E到整数(port))) { 547 | return false, fmt.Errorf("端口 %s 已在使用中", port) 548 | } 549 | 550 | gin.SetMode(gin.ReleaseMode) 551 | gin.DefaultWriter = logWriter 552 | r := gin.Default() 553 | 554 | proxyService, err := NewProxyService(cfg) 555 | if nil != err { 556 | log.Fatal(err) 557 | return false, err 558 | } 559 | 560 | proxyService.InitRoutes(r) 561 | 562 | server = &http.Server{ 563 | Addr: cfg.Bind, 564 | Handler: r, 565 | } 566 | //0.0.0.0:8181 567 | // 2024/08/08 18:51:06 listen: listen tcp 0.0.0.0:8181: bind: address already in use 我的程序为什么挂了 可以不挂吗 568 | go func() { 569 | if err := server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { 570 | log.Fatalf("listen: %s\n", err) 571 | } 572 | }() 573 | 574 | return true, nil 575 | } 576 | 577 | func Stop_override() { 578 | log.Println("Server is shutting down...") 579 | 580 | ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) 581 | defer cancel() 582 | 583 | if err := server.Shutdown(ctx); err != nil { 584 | log.Fatal("Server forced to shutdown:", err) 585 | } 586 | 587 | log.Println("Server exiting") 588 | } 589 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 2 | github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I= 3 | github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= 4 | github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw= 5 | github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= 6 | github.com/akavel/rsrc v0.10.2 h1:Zxm8V5eI1hW4gGaYsJQUhxpjkENuG91ki8B4zCrvEsw= 7 | github.com/akavel/rsrc v0.10.2/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= 8 | github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 h1:OYA+5W64v3OgClL+IrOD63t4i/RW7RqrAVl9LTZ9UqQ= 9 | github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394/go.mod h1:Q8n74mJTIgjX4RBBcHnJ05h//6/k6foqmgE45jTQtxg= 10 | github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY= 11 | github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0= 12 | github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= 13 | github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= 14 | github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= 15 | github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= 16 | github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= 17 | github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= 18 | github.com/clbanning/mxj v1.8.4 h1:HuhwZtbyvyOw+3Z1AowPkU87JkJUSv751ELWaiTpj8I= 19 | github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng= 20 | github.com/clbanning/mxj/v2 v2.5.5 h1:oT81vUeEiQQ/DcHbzSytRngP6Ky9O+L+0Bw0zSJag9E= 21 | github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= 22 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 23 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 24 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 25 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 26 | github.com/dchest/jsmin v0.0.0-20220218165748-59f39799265f h1:OGqDDftRTwrvUoL6pOG7rYTmWsTCvyEWFsMjg+HcOaA= 27 | github.com/dchest/jsmin v0.0.0-20220218165748-59f39799265f/go.mod h1:Dv9D0NUlAsaQcGQZa5kc5mqR9ua72SmA8VXi4cd+cBw= 28 | github.com/duolabmeng6/goefun v1.3.8 h1:eAeiAs4YBoK9xn5/SHuJVb6kxQIEOTOehdtboGONowM= 29 | github.com/duolabmeng6/goefun v1.3.8/go.mod h1:mg175FgUQ0tWPSfuobtIIaL7el8ZOYyLmJJi28dXOTg= 30 | github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= 31 | github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= 32 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 33 | github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= 34 | github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= 35 | github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= 36 | github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= 37 | github.com/ganlvtech/go-exportable-cookiejar v0.0.0-20181231191301-34af33d7487e h1:zF8BCigEVAtW07yhpupU1FQ8DEzINaJ6HVfPUQY/uqY= 38 | github.com/ganlvtech/go-exportable-cookiejar v0.0.0-20181231191301-34af33d7487e/go.mod h1:EdkZC5tfJxfNZYtycwAG0adNOJRpGUyIhLcG6DvhyU0= 39 | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= 40 | github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= 41 | github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= 42 | github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= 43 | github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= 44 | github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= 45 | github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= 46 | github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= 47 | github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= 48 | github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= 49 | github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= 50 | github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= 51 | github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= 52 | github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= 53 | github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= 54 | github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= 55 | github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= 56 | github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= 57 | github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= 58 | github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= 59 | github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= 60 | github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= 61 | github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= 62 | github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= 63 | github.com/gogf/gf v1.12.3 h1:71arUxK76Fr8tlbt3NcVKbWHnn0PBrLoAj8Fk06CmPM= 64 | github.com/gogf/gf v1.12.3/go.mod h1:toXfwdoKLjTZXhaQL3c5o4EZuzsFABratQvGyu5A/6w= 65 | github.com/gogf/gf/v2 v2.4.1 h1:snsuvDhNFiRoAuWBbKfIIng0KyMaRA87Qr03GLir5j8= 66 | github.com/gogf/gf/v2 v2.4.1/go.mod h1:tsbmtwcAl2chcYoq/fP9W2FZf06aw4i89X34nbSHo9Y= 67 | github.com/gogf/guuid v1.0.0 h1:tUB0VKMcFmbIrteVjRAEvoxXX7vQNOA6DMf1ub9xli8= 68 | github.com/gogf/guuid v1.0.0/go.mod h1:weuAJZ9kkvXmvYgQKitT0RdX0l+94D0eFf5NoJxDRFI= 69 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 70 | github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= 71 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 72 | github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= 73 | github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= 74 | github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 75 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 76 | github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 77 | github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= 78 | github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 79 | github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 80 | github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= 81 | github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 82 | github.com/gqcn/structs v1.1.1 h1:cyzGRwfmn3d1d54fwW3KUNyG9QxR0ldIeqwFGeBt638= 83 | github.com/gqcn/structs v1.1.1/go.mod h1:/aBhTBSsKQ2Ec9pbnYdGphtdWXHFn4KrCL0fXM/Adok= 84 | github.com/grokify/html-strip-tags-go v0.0.0-20190921062105-daaa06bf1aaf/go.mod h1:2Su6romC5/1VXOQMaWL2yb618ARB8iVo6/DR99A6d78= 85 | github.com/grokify/html-strip-tags-go v0.0.1 h1:0fThFwLbW7P/kOiTBs03FsJSV9RM2M/Q/MOnCQxKMo0= 86 | github.com/grokify/html-strip-tags-go v0.0.1/go.mod h1:2Su6romC5/1VXOQMaWL2yb618ARB8iVo6/DR99A6d78= 87 | github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck= 88 | github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs= 89 | github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= 90 | github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= 91 | github.com/josephspurrier/goversioninfo v1.4.0 h1:Puhl12NSHUSALHSuzYwPYQkqa2E1+7SrtAPJorKK0C8= 92 | github.com/josephspurrier/goversioninfo v1.4.0/go.mod h1:JWzv5rKQr+MmW+LvM412ToT/IkYDZjaclF2pKDss8IY= 93 | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= 94 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 95 | github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= 96 | github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= 97 | github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= 98 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 99 | github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= 100 | github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= 101 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 102 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 103 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 104 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 105 | github.com/labstack/echo/v4 v4.10.2 h1:n1jAhnq/elIFTHr1EYpiYtyKgx4RW9ccVgkqByZaN2M= 106 | github.com/labstack/echo/v4 v4.10.2/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k= 107 | github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8= 108 | github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= 109 | github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc= 110 | github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA= 111 | github.com/leaanthony/go-ansi-parser v1.6.0 h1:T8TuMhFB6TUMIUm0oRrSbgJudTFw9csT3ZK09w0t4Pg= 112 | github.com/leaanthony/go-ansi-parser v1.6.0/go.mod h1:+vva/2y4alzVmmIEpk9QDhA7vLC5zKDTRwfZGOp3IWU= 113 | github.com/leaanthony/gosod v1.0.3 h1:Fnt+/B6NjQOVuCWOKYRREZnjGyvg+mEhd1nkkA04aTQ= 114 | github.com/leaanthony/gosod v1.0.3/go.mod h1:BJ2J+oHsQIyIQpnLPjnqFGTMnOZXDbvWtRCSG7jGxs4= 115 | github.com/leaanthony/slicer v1.5.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY= 116 | github.com/leaanthony/slicer v1.6.0 h1:1RFP5uiPJvT93TAHi+ipd3NACobkW53yUiBqZheE/Js= 117 | github.com/leaanthony/slicer v1.6.0/go.mod h1:o/Iz29g7LN0GqH3aMjWAe90381nyZlDNquK+mtH2Fj8= 118 | github.com/leaanthony/u v1.1.0 h1:2n0d2BwPVXSUq5yhe8lJPHdxevE2qK5G99PMStMZMaI= 119 | github.com/leaanthony/u v1.1.0/go.mod h1:9+o6hejoRljvZ3BzdYlVL0JYCwtnAsVuN9pVTQcaRfI= 120 | github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= 121 | github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= 122 | github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= 123 | github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= 124 | github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= 125 | github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= 126 | github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 127 | github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= 128 | github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= 129 | github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= 130 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 131 | github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= 132 | github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= 133 | github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= 134 | github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 135 | github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= 136 | github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= 137 | github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= 138 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 139 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 140 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 141 | github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= 142 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 143 | github.com/ncruces/zenity v0.10.13 h1:0Gd/EdjjEQIhrFaJ05Q5ZvyjlcjnorlZpdzgUzqQIH0= 144 | github.com/ncruces/zenity v0.10.13/go.mod h1:UyAUPSjHm1hOdeZa3Lrh/zmItyGq+iH5AP6xSCx8CFM= 145 | github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= 146 | github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= 147 | github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= 148 | github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= 149 | github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= 150 | github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= 151 | github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= 152 | github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= 153 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 154 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 155 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 156 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 157 | github.com/randall77/makefat v0.0.0-20210315173500-7ddd0e42c844 h1:GranzK4hv1/pqTIhMTXt2X8MmMOuH3hMeUR0o9SP5yc= 158 | github.com/randall77/makefat v0.0.0-20210315173500-7ddd0e42c844/go.mod h1:T1TLSfyWVBRXVGzWd0o9BI4kfoO9InEgfQe4NV3mLz8= 159 | github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= 160 | github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= 161 | github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= 162 | github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= 163 | github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= 164 | github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= 165 | github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= 166 | github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= 167 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 168 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 169 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 170 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 171 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 172 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 173 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 174 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 175 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 176 | github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 177 | github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 178 | github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= 179 | github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 180 | github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf h1:Z2X3Os7oRzpdJ75iPqWZc0HeJWFYNCvKsfpQwFpRNTA= 181 | github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf/go.mod h1:M8agBzgqHIhgj7wEn9/0hJUZcrvt9VY+Ln+S1I5Mha0= 182 | github.com/tidwall/gjson v1.8.0/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk= 183 | github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= 184 | github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= 185 | github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= 186 | github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= 187 | github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= 188 | github.com/tidwall/pretty v1.1.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= 189 | github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= 190 | github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= 191 | github.com/tidwall/sjson v1.1.7 h1:sgVPwu/yygHJ2m1pJDLgGM/h+1F5odx5Q9ljG3imRm8= 192 | github.com/tidwall/sjson v1.1.7/go.mod h1:w/yG+ezBeTdUxiKs5NcPicO9diP38nk96QBAbIIGeFs= 193 | github.com/tkrajina/go-reflector v0.5.6 h1:hKQ0gyocG7vgMD2M3dRlYN6WBBOmdoOzJ6njQSepKdE= 194 | github.com/tkrajina/go-reflector v0.5.6/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4= 195 | github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= 196 | github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= 197 | github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= 198 | github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= 199 | github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= 200 | github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= 201 | github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= 202 | github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= 203 | github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= 204 | github.com/wailsapp/go-webview2 v1.0.10 h1:PP5Hug6pnQEAhfRzLCoOh2jJaPdrqeRgJKZhyYyDV/w= 205 | github.com/wailsapp/go-webview2 v1.0.10/go.mod h1:Uk2BePfCRzttBBjFrBmqKGJd41P6QIHeV9kTgIeOZNo= 206 | github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs= 207 | github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o= 208 | github.com/wailsapp/wails/v2 v2.9.1 h1:irsXnoQrCpeKzKTYZ2SUVlRRyeMR6I0vCO9Q1cvlEdc= 209 | github.com/wailsapp/wails/v2 v2.9.1/go.mod h1:7maJV2h+Egl11Ak8QZN/jlGLj2wg05bsQS+ywJPT0gI= 210 | github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 211 | go.opentelemetry.io/otel v1.7.0 h1:Z2lA3Tdch0iDcrhJXDIlC94XE+bxok1F9B+4Lz/lGsM= 212 | go.opentelemetry.io/otel v1.7.0/go.mod h1:5BdUoMIz5WEs0vt0CUEMtSSaTSHBBVwrhnz7+nrD5xk= 213 | go.opentelemetry.io/otel/sdk v1.7.0 h1:4OmStpcKVOfvDOgCt7UriAPtKolwIhxpnSNI/yK+1B0= 214 | go.opentelemetry.io/otel/sdk v1.7.0/go.mod h1:uTEOTwaqIVuTGiJN7ii13Ibp75wJmYUDe374q6cZwUU= 215 | go.opentelemetry.io/otel/trace v1.7.0 h1:O37Iogk1lEkMRXewVtZ1BBTVn5JEp8GrJvP92bJqC6o= 216 | go.opentelemetry.io/otel/trace v1.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48yyE4TNvoHqU= 217 | go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= 218 | go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= 219 | golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= 220 | golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= 221 | golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= 222 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 223 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 224 | golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= 225 | golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= 226 | golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc= 227 | golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= 228 | golang.org/x/image v0.18.0 h1:jGzIakQa/ZXI1I0Fxvaa9W7yP25TqT6cHIHn+6CqvSQ= 229 | golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E= 230 | golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 231 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 232 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 233 | golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 234 | golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 235 | golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 236 | golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= 237 | golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= 238 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 239 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 240 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 241 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 242 | golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 243 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 244 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 245 | golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 246 | golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 247 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 248 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 249 | golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 250 | golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 251 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 252 | golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 253 | golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 254 | golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 255 | golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 256 | golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 257 | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 258 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 259 | golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= 260 | golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 261 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 262 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 263 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 264 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 265 | golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0= 266 | golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= 267 | golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= 268 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 269 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 270 | golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= 271 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 272 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 273 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 274 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 275 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 276 | google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= 277 | google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 278 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 279 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= 280 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 281 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 282 | gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= 283 | gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= 284 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 285 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 286 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 287 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 288 | rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= 289 | --------------------------------------------------------------------------------