feat: wire gui instance start and delete confirmation
This commit is contained in:
+99
-2
@@ -10,6 +10,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"chub/internal/domain"
|
||||
"chub/internal/platform/browser"
|
||||
@@ -106,6 +107,7 @@ func runWindow(logger *slog.Logger) {
|
||||
directoryPicker := files.NewDirectoryPicker()
|
||||
shell.OnChooseDirectory(directoryPicker.ChooseDirectory, window.Invalidate)
|
||||
discoverer := browser.NewDiscoverer()
|
||||
shell.OnStartInstance(instanceStarter{launcher: browser.NewOSLauncher(), resolver: discoverer}.Start, window.Invalidate)
|
||||
shell.OnPathSearch(func(ctx context.Context, field ui.PathField, current string) (string, error) {
|
||||
switch field {
|
||||
case ui.PathChromeExecutable:
|
||||
@@ -138,12 +140,16 @@ func runWindow(logger *slog.Logger) {
|
||||
shell.SetSettings(ui.SettingsState{ChromePath: saved.Settings.ChromePath, EdgePath: saved.Settings.EdgePath, DefaultDir: saved.Settings.DefaultDir, LogDir: saved.Settings.LogDir, CloseOnExit: saved.Settings.CloseOnExit})
|
||||
rows := make([]ui.InstanceRow, 0, len(saved.Instances))
|
||||
for _, item := range saved.Instances {
|
||||
rows = append(rows, ui.InstanceRow{ID: item.ID, Name: item.Name, Browser: string(item.Launch.Kind), UserDataDir: item.Launch.UserDataDir, Status: "已退出"})
|
||||
rows = append(rows, ui.InstanceRow{ID: item.ID, Name: item.Name, Browser: browserLabel(item.Launch.Kind), UserDataDir: item.Launch.UserDataDir, TargetURL: item.Launch.TargetURL, Status: "已退出"})
|
||||
}
|
||||
shell.SetInstances(rows)
|
||||
shell.OnSave(func(value ui.SettingsState) {
|
||||
saved.Settings = config.Settings{ChromePath: value.ChromePath, EdgePath: value.EdgePath, DefaultDir: value.DefaultDir, LogDir: value.LogDir, CloseOnExit: value.CloseOnExit}
|
||||
go saveSettings(logger, store, saved)
|
||||
go saveSettings(logger, store, configSnapshot(saved))
|
||||
})
|
||||
shell.OnInstancesChanged(func(rows []ui.InstanceRow) {
|
||||
saved.Instances = mergeInstanceConfig(saved.Instances, rows)
|
||||
go saveSettings(logger, store, configSnapshot(saved))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -170,3 +176,94 @@ func saveSettings(logger *slog.Logger, store *config.Store, value config.File) {
|
||||
logger.Error("save settings", "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
type executableResolver interface {
|
||||
Resolve(context.Context, domain.BrowserKind, string) (string, error)
|
||||
}
|
||||
|
||||
type processLauncher interface {
|
||||
Start(context.Context, domain.LaunchSpec) (browser.ProcessHandle, error)
|
||||
}
|
||||
|
||||
type instanceStarter struct {
|
||||
launcher processLauncher
|
||||
resolver executableResolver
|
||||
}
|
||||
|
||||
func (s instanceStarter) Start(ctx context.Context, row ui.InstanceRow, settings ui.SettingsState) (int, error) {
|
||||
kind, err := browserKind(row.Browser)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if s.launcher == nil || s.resolver == nil {
|
||||
return 0, errors.New("浏览器启动服务尚未准备好")
|
||||
}
|
||||
configuredExecutable := settings.ChromePath
|
||||
if kind == domain.BrowserEdge {
|
||||
configuredExecutable = settings.EdgePath
|
||||
}
|
||||
executable, err := s.resolver.Resolve(ctx, kind, configuredExecutable)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("无法找到%s可执行文件:%w", browserLabel(kind), err)
|
||||
}
|
||||
handle, err := s.launcher.Start(ctx, domain.LaunchSpec{
|
||||
Kind: kind,
|
||||
Executable: executable,
|
||||
UserDataDir: row.UserDataDir,
|
||||
TargetURL: row.TargetURL,
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return handle.PID(), nil
|
||||
}
|
||||
|
||||
func browserKind(value string) (domain.BrowserKind, error) {
|
||||
switch strings.ToLower(strings.TrimSpace(value)) {
|
||||
case "chrome":
|
||||
return domain.BrowserChrome, nil
|
||||
case "edge":
|
||||
return domain.BrowserEdge, nil
|
||||
default:
|
||||
return "", fmt.Errorf("不支持的浏览器类型:%s", value)
|
||||
}
|
||||
}
|
||||
|
||||
func browserLabel(kind domain.BrowserKind) string {
|
||||
if kind == domain.BrowserEdge {
|
||||
return "Edge"
|
||||
}
|
||||
return "Chrome"
|
||||
}
|
||||
|
||||
func mergeInstanceConfig(existing []config.Instance, rows []ui.InstanceRow) []config.Instance {
|
||||
byID := make(map[string]config.Instance, len(existing))
|
||||
for _, item := range existing {
|
||||
byID[item.ID] = item
|
||||
}
|
||||
updated := make([]config.Instance, 0, len(rows))
|
||||
for _, row := range rows {
|
||||
kind, err := browserKind(row.Browser)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
item := byID[row.ID]
|
||||
item.ID = row.ID
|
||||
item.Name = row.Name
|
||||
item.Launch.Kind = kind
|
||||
item.Launch.UserDataDir = row.UserDataDir
|
||||
item.Launch.TargetURL = row.TargetURL
|
||||
item.UpdatedAt = time.Now()
|
||||
updated = append(updated, item)
|
||||
}
|
||||
return updated
|
||||
}
|
||||
|
||||
func configSnapshot(value config.File) config.File {
|
||||
clone := value
|
||||
clone.Instances = append([]config.Instance(nil), value.Instances...)
|
||||
for i := range clone.Instances {
|
||||
clone.Instances[i].Launch.ExtraArgs = append([]string(nil), clone.Instances[i].Launch.ExtraArgs...)
|
||||
}
|
||||
return clone
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user