feat: add preferred debug port planning
This commit is contained in:
+39
-2
@@ -164,7 +164,7 @@ func runWindow(logger *slog.Logger) {
|
||||
shell.SetProxies(proxyOptions(saved.Proxies))
|
||||
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: browserLabel(item.Launch.Kind), UserDataDir: item.Launch.UserDataDir, TargetURL: item.Launch.TargetURL, ProxyID: item.ProxyID, 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, ProxyID: item.ProxyID, PreferredRemoteDebugPort: item.PreferredRemoteDebugPort, Status: "已退出"})
|
||||
}
|
||||
shell.SetInstances(rows)
|
||||
shell.OnSave(func(value ui.SettingsState) {
|
||||
@@ -493,7 +493,11 @@ func (s instanceStarter) Start(ctx context.Context, row ui.InstanceRow, settings
|
||||
if err != nil {
|
||||
return ui.InstanceStartOutcome{}, fmt.Errorf("无法找到%s可执行文件:%w", browserLabel(kind), err)
|
||||
}
|
||||
port, err := s.portAllocator.FindAvailableRemoteDebugPort(ctx, settings.RemoteDebugStartPort)
|
||||
startPort := row.PreferredRemoteDebugPort
|
||||
if !domain.ValidRemoteDebugPort(startPort) {
|
||||
startPort = settings.RemoteDebugStartPort
|
||||
}
|
||||
port, err := findAvailableUnreservedRemoteDebugPort(ctx, s.portAllocator, startPort, settings.ReservedRemoteDebugPorts)
|
||||
if err != nil {
|
||||
return ui.InstanceStartOutcome{}, fmt.Errorf("无法分配本地调试端口:%w", err)
|
||||
}
|
||||
@@ -556,6 +560,7 @@ func mergeInstanceConfig(existing []config.Instance, rows []ui.InstanceRow) []co
|
||||
item.Launch.UserDataDir = row.UserDataDir
|
||||
item.Launch.TargetURL = row.TargetURL
|
||||
item.ProxyID = row.ProxyID
|
||||
item.PreferredRemoteDebugPort = row.PreferredRemoteDebugPort
|
||||
if item.ProxyID != "" {
|
||||
item.Launch.ProxyServer = ""
|
||||
}
|
||||
@@ -565,6 +570,38 @@ func mergeInstanceConfig(existing []config.Instance, rows []ui.InstanceRow) []co
|
||||
return updated
|
||||
}
|
||||
|
||||
func findAvailableUnreservedRemoteDebugPort(ctx context.Context, allocator browser.RemoteDebugPortAllocator, start int, reserved []int) (int, error) {
|
||||
if allocator == nil {
|
||||
return 0, errors.New("remote debug port allocator is required")
|
||||
}
|
||||
if !domain.ValidRemoteDebugPort(start) {
|
||||
return 0, fmt.Errorf("invalid remote debug start port %d", start)
|
||||
}
|
||||
reservedSet := make(map[int]struct{}, len(reserved))
|
||||
for _, port := range reserved {
|
||||
if domain.ValidRemoteDebugPort(port) {
|
||||
reservedSet[port] = struct{}{}
|
||||
}
|
||||
}
|
||||
for candidate := start; candidate <= domain.MaxRemoteDebugPort; {
|
||||
port, err := allocator.FindAvailableRemoteDebugPort(ctx, candidate)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if !domain.ValidRemoteDebugPort(port) || port < candidate {
|
||||
return 0, fmt.Errorf("port allocator returned invalid port %d", port)
|
||||
}
|
||||
if _, reservedByOtherInstance := reservedSet[port]; !reservedByOtherInstance {
|
||||
return port, nil
|
||||
}
|
||||
if port == domain.MaxRemoteDebugPort {
|
||||
break
|
||||
}
|
||||
candidate = port + 1
|
||||
}
|
||||
return 0, errors.New("no unreserved local remote debug port is available")
|
||||
}
|
||||
|
||||
func mergeProxyConfig(existing []config.ProxyProfile, options []ui.ProxyOption) []config.ProxyProfile {
|
||||
byID := make(map[string]config.ProxyProfile, len(existing))
|
||||
for _, profile := range existing {
|
||||
|
||||
+36
-4
@@ -38,6 +38,30 @@ func TestInstanceStarterBuildsLaunchSpecFromInstanceAndSettings(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestInstanceStarterUsesPreferredPortAndSkipsOtherInstancesReservations(t *testing.T) {
|
||||
launcher := &fakeProcessLauncher{handle: fakeProcessHandle{pid: 4242}}
|
||||
remote := &fakeRemoteDebugInspector{
|
||||
endpoint: browser.RemoteDebugEndpoint{Port: 9668},
|
||||
inspectErr: browser.ErrRemoteDebugEndpointUnavailable,
|
||||
allocatedPorts: []int{9667, 9668},
|
||||
}
|
||||
starter := instanceStarter{
|
||||
launcher: launcher,
|
||||
resolver: &fakeExecutableResolver{path: `C:\Browser\chrome.exe`},
|
||||
managedProfiles: fakeManagedProfileInspector{},
|
||||
externalProfiles: fakeExternalProfileInspector{},
|
||||
remoteDebug: remote,
|
||||
portAllocator: remote,
|
||||
}
|
||||
outcome, err := starter.Start(context.Background(), ui.InstanceRow{ID: "chrome-a", Browser: "Chrome", UserDataDir: `C:\profiles\chrome-a`, PreferredRemoteDebugPort: 9666}, ui.SettingsState{RemoteDebugStartPort: 9777, ReservedRemoteDebugPorts: []int{9667}}, 1)
|
||||
if err != nil || outcome.RemoteDebugPort != 9668 || launcher.spec.RemoteDebugPort != 9668 {
|
||||
t.Fatalf("Start() = %#v, launch = %#v, error = %v", outcome, launcher.spec, err)
|
||||
}
|
||||
if len(remote.allocationStarts) != 2 || remote.allocationStarts[0] != 9666 || remote.allocationStarts[1] != 9668 {
|
||||
t.Fatalf("allocator starts = %#v", remote.allocationStarts)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInstanceStarterResolvesSelectedProxyAtLaunch(t *testing.T) {
|
||||
launcher := &fakeProcessLauncher{handle: fakeProcessHandle{pid: 4242}}
|
||||
resolver := &fakeExecutableResolver{path: `C:\Browser\chrome.exe`}
|
||||
@@ -341,10 +365,12 @@ func (i fakeExternalProfileInspector) InspectProfile(context.Context, domain.Bro
|
||||
}
|
||||
|
||||
type fakeRemoteDebugInspector struct {
|
||||
endpoint browser.RemoteDebugEndpoint
|
||||
inspectErr error
|
||||
waitErr error
|
||||
port int
|
||||
endpoint browser.RemoteDebugEndpoint
|
||||
inspectErr error
|
||||
waitErr error
|
||||
port int
|
||||
allocatedPorts []int
|
||||
allocationStarts []int
|
||||
}
|
||||
|
||||
func (i *fakeRemoteDebugInspector) InspectRemoteDebugEndpoint(context.Context, domain.BrowserKind, string) (browser.RemoteDebugEndpoint, error) {
|
||||
@@ -364,6 +390,12 @@ func (i *fakeRemoteDebugInspector) WaitForRemoteDebugPort(context.Context, domai
|
||||
}
|
||||
|
||||
func (i *fakeRemoteDebugInspector) FindAvailableRemoteDebugPort(_ context.Context, start int) (int, error) {
|
||||
i.allocationStarts = append(i.allocationStarts, start)
|
||||
if len(i.allocatedPorts) > 0 {
|
||||
port := i.allocatedPorts[0]
|
||||
i.allocatedPorts = i.allocatedPorts[1:]
|
||||
return port, nil
|
||||
}
|
||||
if i.port != 0 {
|
||||
return i.port, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user