From b364b062061e157ae859e093db7321d54551ccef Mon Sep 17 00:00:00 2001 From: ZhuoQinghui <1302344380@qq.com> Date: Wed, 11 Jun 2025 14:42:45 +0800 Subject: [PATCH] Golang Code --- app.go | 27 +++++++ conf.go | 120 +++++++++++++++++++++++++++ dto.go | 27 +++++++ event-home.go | 219 ++++++++++++++++++++++++++++++++++++++++++++++++++ go.mod | 38 +++++++++ go.sum | 79 ++++++++++++++++++ main.go | 40 +++++++++ util.go | 91 +++++++++++++++++++++ wails.json | 13 +++ 9 files changed, 654 insertions(+) create mode 100644 app.go create mode 100644 conf.go create mode 100644 dto.go create mode 100644 event-home.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go create mode 100644 util.go create mode 100644 wails.json diff --git a/app.go b/app.go new file mode 100644 index 0000000..af53038 --- /dev/null +++ b/app.go @@ -0,0 +1,27 @@ +package main + +import ( + "context" + "fmt" +) + +// App struct +type App struct { + ctx context.Context +} + +// NewApp creates a new App application struct +func NewApp() *App { + return &App{} +} + +// startup is called when the app starts. The context is saved +// so we can call the runtime methods +func (a *App) startup(ctx context.Context) { + a.ctx = ctx +} + +// Greet returns a greeting for the given name +func (a *App) Greet(name string) string { + return fmt.Sprintf("Hello %s, It's show time!", name) +} diff --git a/conf.go b/conf.go new file mode 100644 index 0000000..78c0e2a --- /dev/null +++ b/conf.go @@ -0,0 +1,120 @@ +package main + +import ( + "encoding/json" + "fmt" + "os" + "path/filepath" +) + +type AppConf struct { + Path string `json:"Path"` + LastWorkspace string `json:"lastWorkspace"` +} + +var appConf *AppConf + +func init() { + readConfig() +} + +func readConfig() { + appConf = &AppConf{} + _, err := os.Stat("conf.json") + if os.IsNotExist(err) { + fmt.Println("创建conf.json") + file, err := os.Create("conf.json") + if err != nil { + panic(err) + } + defer file.Close() + } + file, err := os.ReadFile("conf.json") + if err != nil { + panic(err) + } + json.Unmarshal(file, appConf) + fmt.Println("读取配置文件成功") + fmt.Println(appConf) +} + +func GetConfig() *AppConf { + return appConf +} + +func SetPath(path string) { + appConf.Path = path + confJson, err := json.Marshal(appConf) + if err != nil { + panic(err) + } + os.WriteFile("conf.json", confJson, os.ModePerm) +} + +func SetWorkSpace(workspace string) { + appConf.LastWorkspace = workspace + confJson, err := json.Marshal(appConf) + if err != nil { + panic(err) + } + os.WriteFile("conf.json", confJson, os.ModePerm) +} + +type WorkspaceConf struct { + BrowserPath string `json:"browserPath"` + BrowserType string `json:"browserType"` + Workspace string `json:"workspace"` +} + +func readWorkspaceConf(workspace string) (*WorkspaceConf, error) { + currWorkConf := &WorkspaceConf{} + dataDir := GetDataDir() + workDir := filepath.Join(dataDir, workspace) + _, err := os.Stat(workDir) + if err != nil { + return nil, err + } + confJson, err := os.ReadFile(filepath.Join(workDir, "workspace.json")) + if err != nil { + return nil, err + } + err = json.Unmarshal(confJson, currWorkConf) + if err != nil { + return nil, err + } + return currWorkConf, nil +} + +func GetCurrWorkspaceConf() *WorkspaceConf { + conf, err := readWorkspaceConf(GetConfig().LastWorkspace) + if err != nil { + panic(err) + } + return conf +} + +func GetCurrWorkspace() string { + return GetConfig().LastWorkspace +} + +func SetBrowserPath(browserPath string) { + conf := GetCurrWorkspaceConf() + conf.BrowserPath = browserPath + conf.WriteToFile() +} + +func SetBrowserType(browserType string) { + conf := GetCurrWorkspaceConf() + conf.BrowserType = browserType + conf.WriteToFile() +} + +func (conf *WorkspaceConf) WriteToFile() { + confJson, _ := json.Marshal(conf) + jsonDir := filepath.Join(GetDataDir(), conf.Workspace, "workspace.json") + fmt.Printf("写出配置文件: %v -> %v\n", jsonDir, confJson) + err := os.WriteFile(jsonDir, confJson, os.ModePerm) + if err != nil { + fmt.Println(err) + } +} diff --git a/dto.go b/dto.go new file mode 100644 index 0000000..661eb22 --- /dev/null +++ b/dto.go @@ -0,0 +1,27 @@ +package main + +type Dto struct { + Code int `json:"code"` + Msg string `json:"msg"` + Data interface{} `json:"data"` +} + +func NewDto(code int, msg string, data interface{}) *Dto { + return &Dto{ + Code: code, + Msg: msg, + Data: data, + } +} + +func FailDto(msg string, data interface{}) *Dto { + return NewDto(1, msg, data) +} + +func SuccessDto(data interface{}) *Dto { + return NewDto(200, "success", data) +} + +func (d *Dto) IsSuccess() bool { + return d.Code == 200 +} diff --git a/event-home.go b/event-home.go new file mode 100644 index 0000000..939f8e3 --- /dev/null +++ b/event-home.go @@ -0,0 +1,219 @@ +package main + +import ( + "context" + "fmt" + "github.com/wailsapp/wails/v2/pkg/runtime" + "golang.org/x/sys/windows/registry" + "os" + "os/exec" + "path/filepath" + "strings" +) + +type HomeEvent struct { + ctx context.Context +} + +func NewHomeEvent() *HomeEvent { + return &HomeEvent{} +} + +func (a *HomeEvent) startup(ctx context.Context) { + a.ctx = ctx +} + +func (a *HomeEvent) ListWorkspace() *Dto { + dirs := GetWorkspaceDirs() + return SuccessDto(dirs) +} + +func (a *HomeEvent) AddWorkspace(name string) *Dto { + runtime.LogInfo(a.ctx, "创建工作空间: "+name) + dataDir := GetDataDir() + workspaceDir := filepath.Join(dataDir, name) + _, err := os.Stat(workspaceDir) + if os.IsExist(err) { + return FailDto("目录已存在", nil) + } + err = os.Mkdir(workspaceDir, os.ModePerm) + if err != nil { + return FailDto("创建目录失败", err) + } + runtime.LogInfo(a.ctx, "创建工作空间成功: "+name) + runtime.LogInfo(a.ctx, "创建默认配置文件: "+name) + newConf := &WorkspaceConf{ + BrowserPath: "", + BrowserType: "", + Workspace: name, + } + pathDto := a.GetDefaultBrowserPath() + if pathDto.IsSuccess() { + path := pathDto.Data.(string) + newConf.BrowserPath = path + // 通过路径是否为chrome.exe结尾 + if strings.HasSuffix(path, "chrome.exe") { + newConf.BrowserType = "chrome" + } else if strings.HasSuffix(path, "firefox.exe") { + newConf.BrowserType = "firefox" + } else if strings.HasSuffix(path, "msedge.exe") { + newConf.BrowserType = "edge" + } + } + newConfInfo := fmt.Sprintf("默认配置: BrowserPath -> %v, BrowserType -> %v, Workspace -> %v", newConf.BrowserPath, newConf.BrowserType, newConf.Workspace) + runtime.LogInfo(a.ctx, newConfInfo) + newConf.WriteToFile() + return SuccessDto(nil) +} + +func (a *HomeEvent) GetCurrWorkspace() *Dto { + config := GetConfig() + workspace := config.LastWorkspace + return SuccessDto(workspace) +} + +func (a *HomeEvent) SetCurrentWorkspace(workspace string) *Dto { + SetWorkSpace(workspace) + return SuccessDto("") +} + +func (a *HomeEvent) LoadCurrWorkspaceConf() *Dto { + currWorkConf := GetCurrWorkspaceConf() + return SuccessDto(currWorkConf) +} + +func (a *HomeEvent) LoadBrowserConf() *Dto { + config := GetConfig() + path := config.Path + if path != "" { + return SuccessDto(path) + } + dto := a.GetDefaultBrowserPath() + if !dto.IsSuccess() { + dto = a.SelectPath("") + } + if dto.IsSuccess() { + SetPath(dto.Data.(string)) + } + return dto +} + +func (a *HomeEvent) GetDefaultBrowserPath() *Dto { + keyPath := `Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.html\UserChoice` + key, err := registry.OpenKey(registry.CURRENT_USER, keyPath, registry.QUERY_VALUE) + if err != nil { + return FailDto("无法打开注册表项: "+keyPath, err) + } + defer key.Close() + progId, _, err := key.GetStringValue("Progid") + if err != nil { + return FailDto("无法获取注册表值: "+progId, err) + } + fmt.Println("获取注册表值成功, Progid -> {}", progId) + commandKeyPath := progId + `\shell\open\command` + commandKey, err := registry.OpenKey(registry.CLASSES_ROOT, commandKeyPath, registry.QUERY_VALUE) + if err != nil { + return FailDto("无法打开注册表项: "+commandKeyPath, err) + } + defer commandKey.Close() + command, _, err := commandKey.GetStringValue("") + if err != nil { + return FailDto("无法读取注册表值: "+command, err) + } + fmt.Printf("读取注册表成功: 默认浏览器命令: %v\n", command) + args := splitCommandLine(command) + fmt.Println("命令解析结果: {}", args) + command = args[0] + command = strings.Trim(command, "\"") + return SuccessDto(command) +} + +func (a *HomeEvent) SelectPath(curr string) *Dto { + currPath := "." + currName := "" + if curr != "" { + currPath = filepath.Dir(curr) + currName = filepath.Base(curr) + } + + path, err := runtime.OpenFileDialog(a.ctx, runtime.OpenDialogOptions{ + DefaultDirectory: currPath, + DefaultFilename: currName, + Filters: []runtime.FileFilter{ + { + DisplayName: "可执行程序", + Pattern: "*.exe", + }, + }, + }) + if err != nil { + return FailDto("选择文件失败", err) + } + SetBrowserPath(path) + return SuccessDto(path) +} + +func (a *HomeEvent) ChangeBrowserType(browserType string) *Dto { + SetBrowserType(browserType) + return SuccessDto("") +} + +func (a *HomeEvent) ListInstance() *Dto { + dirs := GetInstanceDirs() + return SuccessDto(dirs) +} + +func (a *HomeEvent) AddInstance(name string) *Dto { + dataDir := GetDataDir() + workspace := GetCurrWorkspace() + _, err := os.Stat(filepath.Join(dataDir, workspace, name)) + if os.IsExist(err) { + return FailDto("实例已存在", nil) + } + err = os.Mkdir(filepath.Join(dataDir, workspace, name), os.ModePerm) + if err != nil { + return FailDto("创建实例失败", err) + } + return SuccessDto(nil) +} + +func (a *HomeEvent) StartInstance(name string) *Dto { + conf := GetCurrWorkspaceConf() + browserPath := conf.BrowserPath + browserType := conf.BrowserType + if browserPath == "" { + return FailDto("请选择浏览器可执行路径", nil) + } + + _, err := os.Stat(browserPath) + if os.IsNotExist(err) { + return FailDto("可执行程序不存在", nil) + } + + dataDir := GetDataDir() + workspace := GetCurrWorkspace() + instancePath := filepath.Join(dataDir, workspace, name) + var arg []string + if browserType == "chrome" { + arg = append(arg, "--user-data-dir="+instancePath) + } else if browserType == "edge" { + arg = append(arg, "--user-data-dir="+instancePath) + } else if browserType == "firefox" { + arg = append(arg, "--profile", instancePath) + } else { + return FailDto("不支持的浏览器类型", nil) + } + runInfo := fmt.Sprintf("浏览器路径: %s, 启动参数: %s", browserPath, arg) + runtime.LogInfo(a.ctx, runInfo) + cmd := exec.Command(browserPath, arg...) + //cmd.Stdout = os.Stdout + //cmd.Stderr = os.Stderr + //cmd.Stdin = os.Stdin + err = cmd.Start() + if err != nil { + runtime.LogError(a.ctx, "启动浏览器失败: "+err.Error()) + return FailDto("启动浏览器失败", err) + } + runtime.LogInfo(a.ctx, "启动浏览器成功") + return SuccessDto(nil) +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..2c52cad --- /dev/null +++ b/go.mod @@ -0,0 +1,38 @@ +module chrome-multi + +go 1.23 + +require ( + github.com/wailsapp/wails/v2 v2.10.1 + golang.org/x/sys v0.30.0 +) + +require ( + github.com/bep/debounce v1.2.1 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect + github.com/godbus/dbus/v5 v5.1.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect + github.com/labstack/echo/v4 v4.13.3 // indirect + github.com/labstack/gommon v0.4.2 // indirect + github.com/leaanthony/go-ansi-parser v1.6.1 // indirect + github.com/leaanthony/gosod v1.0.4 // indirect + github.com/leaanthony/slicer v1.6.0 // indirect + github.com/leaanthony/u v1.1.1 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/rivo/uniseg v0.4.7 // indirect + github.com/samber/lo v1.49.1 // indirect + github.com/tkrajina/go-reflector v0.5.8 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasttemplate v1.2.2 // indirect + github.com/wailsapp/go-webview2 v1.0.19 // indirect + github.com/wailsapp/mimetype v1.4.1 // indirect + golang.org/x/crypto v0.33.0 // indirect + golang.org/x/net v0.35.0 // indirect + golang.org/x/text v0.22.0 // indirect +) + +// replace github.com/wailsapp/wails/v2 v2.10.1 => D:\Go\gopath\pkg\mod diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..0ad6722 --- /dev/null +++ b/go.sum @@ -0,0 +1,79 @@ +github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY= +github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= +github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= +github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= +github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck= +github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs= +github.com/labstack/echo/v4 v4.13.3 h1:pwhpCPrTl5qry5HRdM5FwdXnhXSLSY+WE+YQSeCaafY= +github.com/labstack/echo/v4 v4.13.3/go.mod h1:o90YNEeQWjDozo584l7AwhJMHN0bOC4tAfg+Xox9q5g= +github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= +github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= +github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc= +github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA= +github.com/leaanthony/go-ansi-parser v1.6.1 h1:xd8bzARK3dErqkPFtoF9F3/HgN8UQk0ed1YDKpEz01A= +github.com/leaanthony/go-ansi-parser v1.6.1/go.mod h1:+vva/2y4alzVmmIEpk9QDhA7vLC5zKDTRwfZGOp3IWU= +github.com/leaanthony/gosod v1.0.4 h1:YLAbVyd591MRffDgxUOU1NwLhT9T1/YiwjKZpkNFeaI= +github.com/leaanthony/gosod v1.0.4/go.mod h1:GKuIL0zzPj3O1SdWQOdgURSuhkF+Urizzxh26t9f1cw= +github.com/leaanthony/slicer v1.6.0 h1:1RFP5uiPJvT93TAHi+ipd3NACobkW53yUiBqZheE/Js= +github.com/leaanthony/slicer v1.6.0/go.mod h1:o/Iz29g7LN0GqH3aMjWAe90381nyZlDNquK+mtH2Fj8= +github.com/leaanthony/u v1.1.1 h1:TUFjwDGlNX+WuwVEzDqQwC2lOv0P4uhTQw7CMFdiK7M= +github.com/leaanthony/u v1.1.1/go.mod h1:9+o6hejoRljvZ3BzdYlVL0JYCwtnAsVuN9pVTQcaRfI= +github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= +github.com/matryer/is v1.4.1 h1:55ehd8zaGABKLXQUe2awZ99BD/PTc2ls+KV/dXphgEQ= +github.com/matryer/is v1.4.1/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/samber/lo v1.49.1 h1:4BIFyVfuQSEpluc7Fua+j1NolZHiEHEpaSEKdsH0tew= +github.com/samber/lo v1.49.1/go.mod h1:dO6KHFzUKXgP8LDhU0oI8d2hekjXnGOu0DB8Jecxd6o= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/tkrajina/go-reflector v0.5.8 h1:yPADHrwmUbMq4RGEyaOUpz2H90sRsETNVpjzo3DLVQQ= +github.com/tkrajina/go-reflector v0.5.8/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= +github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +github.com/wailsapp/go-webview2 v1.0.19 h1:7U3QcDj1PrBPaxJNCui2k1SkWml+Q5kvFUFyTImA6NU= +github.com/wailsapp/go-webview2 v1.0.19/go.mod h1:qJmWAmAmaniuKGZPWwne+uor3AHMB5PFhqiK0Bbj8kc= +github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs= +github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o= +github.com/wailsapp/wails/v2 v2.10.1 h1:QWHvWMXII2nI/nXz77gpPG8P3ehl6zKe+u4su5BWIns= +github.com/wailsapp/wails/v2 v2.10.1/go.mod h1:zrebnFV6MQf9kx8HI4iAv63vsR5v67oS7GTEZ7Pz1TY= +golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= +golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= +golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= +golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go new file mode 100644 index 0000000..e329306 --- /dev/null +++ b/main.go @@ -0,0 +1,40 @@ +package main + +import ( + "context" + "embed" + + "github.com/wailsapp/wails/v2" + "github.com/wailsapp/wails/v2/pkg/options" + "github.com/wailsapp/wails/v2/pkg/options/assetserver" +) + +//go:embed all:frontend/dist +var assets embed.FS + +func main() { + app := NewApp() + homeEvent := NewHomeEvent() + + err := wails.Run(&options.App{ + Title: "浏览器多开工具", + Width: 800, + Height: 500, + AssetServer: &assetserver.Options{ + Assets: assets, + }, + BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1}, + OnStartup: func(ctx context.Context) { + app.startup(ctx) + homeEvent.startup(ctx) + }, + Bind: []interface{}{ + app, + homeEvent, + }, + }) + + if err != nil { + println("Error:", err.Error()) + } +} diff --git a/util.go b/util.go new file mode 100644 index 0000000..dac0bba --- /dev/null +++ b/util.go @@ -0,0 +1,91 @@ +package main + +import ( + "fmt" + "os" + "path/filepath" + "strings" +) + +func splitCommandLine(commandLine string) []string { + var args []string + var currentArg strings.Builder + inQuotes := false + + for _, char := range commandLine { + if char == '"' { + inQuotes = !inQuotes // 切换引号状态 + continue + } + + if char == ' ' && !inQuotes { + // 如果不在引号内且遇到空格,表示参数结束 + if currentArg.Len() > 0 { + args = append(args, currentArg.String()) + currentArg.Reset() + } + continue + } + + // 否则继续添加到当前参数 + currentArg.WriteRune(char) + } + + // 添加最后一个参数(如果有) + if currentArg.Len() > 0 { + args = append(args, currentArg.String()) + } + + return args +} + +func GetWorkDir() string { + workDir, err := os.Getwd() + if err != nil { + fmt.Println(err) + os.Exit(1) + } + return workDir +} + +func GetDataDir() string { + dataDir := filepath.Join(GetWorkDir(), "data") + stat, err := os.Stat(dataDir) + if os.IsNotExist(err) || !stat.IsDir() { + err := os.Mkdir(dataDir, os.ModePerm) + if err != nil { + panic(err) + } + } + return dataDir +} + +func GetWorkspaceDirs() []string { + dataDir := GetDataDir() + entries, err := os.ReadDir(dataDir) + if err != nil { + panic(err) + } + var workspaceArr []string + for _, entry := range entries { + if entry.IsDir() { + workspaceArr = append(workspaceArr, entry.Name()) + } + } + return workspaceArr +} + +func GetInstanceDirs() []string { + workspaceDir := filepath.Join(GetDataDir(), GetCurrWorkspace()) + entries, err := os.ReadDir(workspaceDir) + if err != nil { + panic(err) + } + var instanceArr []string + for _, entry := range entries { + if entry.IsDir() { + instanceArr = append(instanceArr, entry.Name()) + } + } + return instanceArr +} diff --git a/wails.json b/wails.json new file mode 100644 index 0000000..f3c7283 --- /dev/null +++ b/wails.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://wails.io/schemas/config.v2.json", + "name": "chrome-multi", + "outputfilename": "chrome-multi", + "frontend:install": "npm install", + "frontend:build": "npm run build", + "frontend:dev:watcher": "npm run dev", + "frontend:dev:serverUrl": "auto", + "author": { + "name": "ZhuoQinghui", + "email": "1302344380@qq.com" + } +}