feat: add read-only CDP target viewing
This commit is contained in:
@@ -130,6 +130,7 @@ func runWindow(logger *slog.Logger) {
|
||||
externalProfiles: externalProfiles,
|
||||
remoteDebug: cdp,
|
||||
}.Refresh, window.Invalidate)
|
||||
shell.OnInspectTabs(instanceTabsInspector{remoteDebug: cdp}.Inspect, window.Invalidate)
|
||||
shell.OnPathSearch(func(ctx context.Context, field ui.PathField, current string) (string, error) {
|
||||
switch field {
|
||||
case ui.PathChromeExecutable:
|
||||
@@ -362,6 +363,37 @@ type instanceStatusRefresher struct {
|
||||
remoteDebug browser.RemoteDebugEndpointInspector
|
||||
}
|
||||
|
||||
// instanceTabsInspector is a read-only adapter. It accepts only a UI row that
|
||||
// already has a verified runtime port and maps platform targets into UI DTOs.
|
||||
type instanceTabsInspector struct {
|
||||
remoteDebug browser.RemoteDebugTargetInspector
|
||||
}
|
||||
|
||||
func (i instanceTabsInspector) Inspect(ctx context.Context, row ui.InstanceRow) ([]ui.CDPTarget, error) {
|
||||
if i.remoteDebug == nil {
|
||||
return nil, errors.New("CDP 页面目标服务尚未准备好")
|
||||
}
|
||||
if row.Status != "运行中" && row.Status != "外部已关联" {
|
||||
return nil, errors.New("实例需要处于已验证的运行或外部关联状态")
|
||||
}
|
||||
if !domain.ValidRemoteDebugPort(row.RemoteDebugPort) {
|
||||
return nil, errors.New("实例没有可验证的本地调试端口")
|
||||
}
|
||||
kind, err := browserKind(row.Browser)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
targets, err := i.remoteDebug.ListRemoteDebugTargets(ctx, kind, row.RemoteDebugPort)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("读取 CDP 页面目标失败:%w", err)
|
||||
}
|
||||
result := make([]ui.CDPTarget, 0, len(targets))
|
||||
for _, target := range targets {
|
||||
result = append(result, ui.CDPTarget{ID: target.ID, Type: target.Type, Title: target.Title, URL: target.URL})
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s instanceStatusRefresher) Refresh(ctx context.Context, rows []ui.InstanceRow) ([]ui.InstanceRefreshResult, error) {
|
||||
results := make([]ui.InstanceRefreshResult, 0, len(rows))
|
||||
for _, row := range rows {
|
||||
|
||||
@@ -248,6 +248,24 @@ func TestInstanceStatusRefresherAssociatesExternalWithoutLifecycleControl(t *tes
|
||||
}
|
||||
}
|
||||
|
||||
func TestInstanceTabsInspectorReadsOnlyVerifiedRuntimeRows(t *testing.T) {
|
||||
remote := &fakeRemoteDebugInspector{targets: []browser.RemoteDebugTarget{{ID: "page-1", Type: "page", Title: "运营后台", URL: "https://example.com/orders"}}}
|
||||
inspector := instanceTabsInspector{remoteDebug: remote}
|
||||
targets, err := inspector.Inspect(context.Background(), ui.InstanceRow{ID: "chrome-a", Browser: "Chrome", Status: "运行中", RemoteDebugPort: 9666})
|
||||
if err != nil || len(targets) != 1 || targets[0].ID != "page-1" || targets[0].URL != "https://example.com/orders" {
|
||||
t.Fatalf("Inspect() = %#v, %v", targets, err)
|
||||
}
|
||||
if remote.targetCalls != 1 || remote.targetKind != domain.BrowserChrome || remote.targetPort != 9666 {
|
||||
t.Fatalf("target inspector invocation = %#v", remote)
|
||||
}
|
||||
if _, err := inspector.Inspect(context.Background(), ui.InstanceRow{ID: "stopped", Browser: "Chrome", Status: "已退出", RemoteDebugPort: 9666}); err == nil {
|
||||
t.Fatal("Inspect() accepted a non-running instance")
|
||||
}
|
||||
if remote.targetCalls != 1 {
|
||||
t.Fatalf("non-running instance reached CDP target inspector %d times", remote.targetCalls)
|
||||
}
|
||||
}
|
||||
|
||||
type fakeExecutableResolver struct {
|
||||
path string
|
||||
kind domain.BrowserKind
|
||||
@@ -371,6 +389,11 @@ type fakeRemoteDebugInspector struct {
|
||||
port int
|
||||
allocatedPorts []int
|
||||
allocationStarts []int
|
||||
targets []browser.RemoteDebugTarget
|
||||
targetErr error
|
||||
targetKind domain.BrowserKind
|
||||
targetPort int
|
||||
targetCalls int
|
||||
}
|
||||
|
||||
func (i *fakeRemoteDebugInspector) InspectRemoteDebugEndpoint(context.Context, domain.BrowserKind, string) (browser.RemoteDebugEndpoint, error) {
|
||||
@@ -401,3 +424,10 @@ func (i *fakeRemoteDebugInspector) FindAvailableRemoteDebugPort(_ context.Contex
|
||||
}
|
||||
return start, nil
|
||||
}
|
||||
|
||||
func (i *fakeRemoteDebugInspector) ListRemoteDebugTargets(_ context.Context, kind domain.BrowserKind, port int) ([]browser.RemoteDebugTarget, error) {
|
||||
i.targetCalls++
|
||||
i.targetKind = kind
|
||||
i.targetPort = port
|
||||
return append([]browser.RemoteDebugTarget(nil), i.targets...), i.targetErr
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user