Skip to content

Commit 9454a54

Browse files
committed
Align translated client config and transport tests
1 parent 3f33dc4 commit 9454a54

29 files changed

Lines changed: 586 additions & 417 deletions

go/modcdp/client/CDPTypes.go

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -137,9 +137,18 @@ var modConfigureParamsSchema = map[string]any{
137137
},
138138
"additionalProperties": false,
139139
},
140-
"custom_commands": map[string]any{"type": "array", "items": modCommandRegistrationSchema},
141-
"custom_events": map[string]any{"type": "array", "items": modEventRegistrationSchema},
142-
"custom_middlewares": map[string]any{"type": "array", "items": modMiddlewareRegistrationSchema},
140+
"downstream": map[string]any{
141+
"type": "object",
142+
"properties": map[string]any{
143+
"downstream_client_timeout_ms": map[string]any{"type": "number"},
144+
"downstream_close_browser_on_disconnect": map[string]any{"type": "boolean"},
145+
},
146+
"additionalProperties": false,
147+
},
148+
"server_browser_token": map[string]any{"type": "string"},
149+
"custom_commands": map[string]any{"type": "array", "items": modCommandRegistrationSchema},
150+
"custom_events": map[string]any{"type": "array", "items": modEventRegistrationSchema},
151+
"custom_middlewares": map[string]any{"type": "array", "items": modMiddlewareRegistrationSchema},
143152
},
144153
"additionalProperties": false,
145154
}
@@ -540,22 +549,22 @@ func (types *CDPTypes) ParseCommandResult(method string, result any) (any, error
540549
return result, nil
541550
}
542551

543-
func (types *CDPTypes) ParseEventPayload(event string, payload any) (any, bool) {
552+
func (types *CDPTypes) ParseEventPayload(event string, payload any) (any, error) {
544553
schema, ok := types.EventPayloadSchema(event)
545554
if !ok {
546-
return payload, true
555+
return payload, nil
547556
}
548557
if err := abxjsonschema.Validate(schema, payload); err != nil {
549558
if payloadMap, ok := payload.(map[string]any); ok && len(payloadMap) == 1 {
550559
if value, exists := payloadMap["value"]; exists {
551560
if valueErr := abxjsonschema.Validate(schema, value); valueErr == nil {
552-
return payload, true
561+
return payload, nil
553562
}
554563
}
555564
}
556-
panic(fmt.Errorf("%s event did not match event_schema: %w", event, err))
565+
return nil, fmt.Errorf("%s event did not match event_schema: %w", event, err)
557566
}
558-
return payload, true
567+
return payload, nil
559568
}
560569

561570
func (types *CDPTypes) AddCustomCommand(command CustomCommand) (string, bool, error) {

go/modcdp/client/ModCDPClient.go

Lines changed: 99 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -169,13 +169,15 @@ type CDPTypesConfig struct {
169169
}
170170

171171
type ServerConfig struct {
172-
Upstream UpstreamTransportConfig `json:"upstream,omitempty"`
173-
Router RouterConfig `json:"router,omitempty"`
174-
ClientConfig ClientConfig `json:"client_config,omitempty"`
175-
CustomCommands []CustomCommand `json:"custom_commands,omitempty"`
176-
CustomEvents []CustomEvent `json:"custom_events,omitempty"`
177-
CustomMiddlewares []CustomMiddleware `json:"custom_middlewares,omitempty"`
178-
disabled bool
172+
Upstream UpstreamTransportConfig `json:"upstream,omitempty"`
173+
Router RouterConfig `json:"router,omitempty"`
174+
ClientConfig ClientConfig `json:"client_config,omitempty"`
175+
Downstream types.ModCDPDownstreamConfig `json:"downstream,omitempty"`
176+
ServerBrowserToken string `json:"server_browser_token,omitempty"`
177+
CustomCommands []CustomCommand `json:"custom_commands,omitempty"`
178+
CustomEvents []CustomEvent `json:"custom_events,omitempty"`
179+
CustomMiddlewares []CustomMiddleware `json:"custom_middlewares,omitempty"`
180+
disabled bool
179181
}
180182

181183
var ServerConfigNone = &ServerConfig{disabled: true}
@@ -222,10 +224,10 @@ func (o *Config) UnmarshalJSON(data []byte) error {
222224
return nil
223225
}
224226

225-
type Handler func(data any)
227+
type Handler any
226228

227229
type handlerEntry struct {
228-
handler Handler
230+
handler reflect.Value
229231
pointer uintptr
230232
}
231233

@@ -796,6 +798,19 @@ func (c *ModCDPClient) serverConfigureParams(customCommands []map[string]any, cu
796798
if c.Config.ServerConfig.ClientConfig.ClientCDPSendTimeoutMS != 0 {
797799
clientConfig["client_cdp_send_timeout_ms"] = c.Config.ServerConfig.ClientConfig.ClientCDPSendTimeoutMS
798800
}
801+
downstream := map[string]any{}
802+
if c.Config.ServerConfig.Downstream.DownstreamClientTimeoutMS != 0 {
803+
downstream["downstream_client_timeout_ms"] = c.Config.ServerConfig.Downstream.DownstreamClientTimeoutMS
804+
}
805+
if c.Config.ServerConfig.Downstream.DownstreamCloseBrowserOnDisconnect != nil {
806+
downstream["downstream_close_browser_on_disconnect"] = *c.Config.ServerConfig.Downstream.DownstreamCloseBrowserOnDisconnect
807+
}
808+
if len(downstream) > 0 {
809+
params["downstream"] = downstream
810+
}
811+
if c.Config.ServerConfig.ServerBrowserToken != "" {
812+
params["server_browser_token"] = c.Config.ServerConfig.ServerBrowserToken
813+
}
799814
}
800815
if hasUpstreamConfig {
801816
if _, ok := upstream["upstream_ws_connect_error_settle_timeout_ms"]; !ok {
@@ -1028,23 +1043,27 @@ func (c *ModCDPClient) sendCommand(method string, params map[string]any, cdpSess
10281043
}
10291044

10301045
func (c *ModCDPClient) On(event string, handler Handler) *ModCDPClient {
1046+
handlerValue := reflect.ValueOf(handler)
1047+
if handlerValue.Kind() != reflect.Func {
1048+
panic("handler must be a function")
1049+
}
10311050
c.handlersMu.Lock()
10321051
defer c.handlersMu.Unlock()
1033-
pointer := handlerPointer(handler)
1052+
pointer := handlerValue.Pointer()
10341053
for _, existing := range c.handlers[event] {
10351054
if existing.pointer == pointer {
10361055
return c
10371056
}
10381057
}
1039-
c.handlers[event] = append(c.handlers[event], handlerEntry{handler: handler, pointer: pointer})
1058+
c.handlers[event] = append(c.handlers[event], handlerEntry{handler: handlerValue, pointer: pointer})
10401059
return c
10411060
}
10421061

10431062
func (c *ModCDPClient) Once(event string, handler Handler) *ModCDPClient {
10441063
var wrapped Handler
1045-
wrapped = func(data any) {
1064+
wrapped = func(args ...any) {
10461065
c.Off(event, wrapped)
1047-
handler(data)
1066+
callHandler(reflect.ValueOf(handler), args...)
10481067
}
10491068
return c.On(event, wrapped)
10501069
}
@@ -1075,6 +1094,32 @@ func handlerPointer(handler Handler) uintptr {
10751094
return reflect.ValueOf(handler).Pointer()
10761095
}
10771096

1097+
func callHandler(handler reflect.Value, args ...any) {
1098+
handlerType := handler.Type()
1099+
inputs := make([]reflect.Value, 0, len(args))
1100+
if handlerType.IsVariadic() {
1101+
for _, arg := range args {
1102+
inputs = append(inputs, reflect.ValueOf(arg))
1103+
}
1104+
handler.Call(inputs)
1105+
return
1106+
}
1107+
for index := 0; index < handlerType.NumIn() && index < len(args); index++ {
1108+
input := reflect.ValueOf(args[index])
1109+
expected := handlerType.In(index)
1110+
if input.IsValid() && input.Type().AssignableTo(expected) {
1111+
inputs = append(inputs, input)
1112+
continue
1113+
}
1114+
if input.IsValid() && input.Type().ConvertibleTo(expected) {
1115+
inputs = append(inputs, input.Convert(expected))
1116+
continue
1117+
}
1118+
inputs = append(inputs, reflect.Zero(expected))
1119+
}
1120+
handler.Call(inputs)
1121+
}
1122+
10781123
func (c *ModCDPClient) Close() {
10791124
c.stopHeartbeat()
10801125
c.Router.Stop()
@@ -1258,6 +1303,27 @@ func (c *ModCDPClient) startPingLatencyMeasurement() {
12581303

12591304
func (c *ModCDPClient) startHeartbeat() {
12601305
c.stopHeartbeat()
1306+
if c.Config.ServerConfig == nil || c.Config.ServerConfig.Downstream.DownstreamCloseBrowserOnDisconnect == nil {
1307+
return
1308+
}
1309+
if !*c.Config.ServerConfig.Downstream.DownstreamCloseBrowserOnDisconnect {
1310+
return
1311+
}
1312+
stop := make(chan struct{})
1313+
c.heartbeatStop = stop
1314+
interval := time.Duration(c.Config.ClientConfig.ClientHeartbeatIntervalMS) * time.Millisecond
1315+
go func() {
1316+
ticker := time.NewTicker(interval)
1317+
defer ticker.Stop()
1318+
for {
1319+
select {
1320+
case <-stop:
1321+
return
1322+
case <-ticker.C:
1323+
_, _ = c.Send("Mod.ping", map[string]any{"sent_at": time.Now().UnixMilli()})
1324+
}
1325+
}
1326+
}()
12611327
}
12621328

12631329
func (c *ModCDPClient) stopHeartbeat() {
@@ -1294,29 +1360,41 @@ func (c *ModCDPClient) handleEventMessage(msg map[string]any) {
12941360
params, _ := msg["params"].(map[string]any)
12951361
if c.Injector != nil && c.Injector.SessionID != "" && sessionID == c.Injector.SessionID {
12961362
if unwrapped, ok := translate.UnwrapEventIfNeeded(method, params, sessionID, c.Injector.SessionID); ok {
1297-
validatedData, valid := c.Types.ParseEventPayload(unwrapped.Event, unwrapped.Data)
1298-
if !valid {
1299-
return
1363+
validatedData, err := c.Types.ParseEventPayload(unwrapped.Event, unwrapped.Data)
1364+
if err != nil {
1365+
panic(err)
13001366
}
13011367
c.handlersMu.Lock()
13021368
hs := append([]handlerEntry(nil), c.handlers[unwrapped.Event]...)
13031369
c.handlersMu.Unlock()
13041370
for _, h := range hs {
1305-
go h.handler(validatedData)
1371+
go callHandler(h.handler, validatedData, unwrapped.SessionID)
1372+
}
1373+
c.handlersMu.Lock()
1374+
wildcardHandlers := append([]handlerEntry(nil), c.handlers["*"]...)
1375+
c.handlersMu.Unlock()
1376+
for _, h := range wildcardHandlers {
1377+
go callHandler(h.handler, unwrapped.Event, validatedData, unwrapped.SessionID)
13061378
}
13071379
}
13081380
return
13091381
}
13101382
if method != "" {
1311-
validatedParams, valid := c.Types.ParseEventPayload(method, params)
1312-
if !valid {
1313-
return
1383+
validatedParams, err := c.Types.ParseEventPayload(method, params)
1384+
if err != nil {
1385+
panic(err)
13141386
}
13151387
c.handlersMu.Lock()
13161388
hs := append([]handlerEntry(nil), c.handlers[method]...)
13171389
c.handlersMu.Unlock()
13181390
for _, h := range hs {
1319-
go h.handler(validatedParams)
1391+
go callHandler(h.handler, validatedParams, sessionID)
1392+
}
1393+
c.handlersMu.Lock()
1394+
wildcardHandlers := append([]handlerEntry(nil), c.handlers["*"]...)
1395+
c.handlersMu.Unlock()
1396+
for _, h := range wildcardHandlers {
1397+
go callHandler(h.handler, method, validatedParams, sessionID)
13201398
}
13211399
}
13221400
}

go/modcdp/client/ModCDPClientCustomFlatNamespace_test.go

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -497,10 +497,12 @@ func TestServiceWorkerServerValidatesRegisteredCustomCommandAndEventSchemas(t *t
497497
} else {
498498
assertRegistration(t, result, "Custom.ready", "registered")
499499
}
500-
if _, ok := cdp.Types.ParseEventPayload("Custom.ready", map[string]any{"ok": true}); !ok {
501-
t.Fatal("expected Custom.ready event to validate")
500+
if _, err := cdp.Types.ParseEventPayload("Custom.ready", map[string]any{"ok": true}); err != nil {
501+
t.Fatalf("expected Custom.ready event to validate: %v", err)
502+
}
503+
if _, err := cdp.Types.ParseEventPayload("Custom.ready", map[string]any{"ok": "yes"}); err == nil {
504+
t.Fatal("expected Custom.ready event validation to reject string ok")
502505
}
503-
expectPanic(t, func() { cdp.Types.ParseEventPayload("Custom.ready", map[string]any{"ok": "yes"}) })
504506

505507
seen := make(chan bool, 1)
506508
cdp.On("Custom.ready", func(data any) {
@@ -623,16 +625,18 @@ func TestConstructorCustomCommandAndEventSchemasValidateNestedPayloads(t *testin
623625
if _, err := cdp.Types.ParseCommandParams("Custom.collect", map[string]any{"items": []any{}}); err == nil {
624626
t.Fatal("expected Custom.collect params to reject empty items")
625627
}
626-
if _, ok := cdp.Types.ParseEventPayload("Custom.ready", map[string]any{"url": "https://example.com", "ready": true}); !ok {
627-
t.Fatal("expected Custom.ready event to validate")
628+
if _, err := cdp.Types.ParseEventPayload("Custom.ready", map[string]any{"url": "https://example.com", "ready": true}); err != nil {
629+
t.Fatalf("expected Custom.ready event to validate: %v", err)
628630
}
629-
expectPanic(t, func() {
630-
cdp.Types.ParseEventPayload("Custom.ready", map[string]any{"url": "http://example.com", "ready": true})
631-
})
632-
if _, ok := cdp.Types.ParseEventPayload("Custom.count", map[string]any{"value": 3}); !ok {
633-
t.Fatal("expected Custom.count event to validate")
631+
if _, err := cdp.Types.ParseEventPayload("Custom.ready", map[string]any{"url": "http://example.com", "ready": true}); err == nil {
632+
t.Fatal("expected Custom.ready event validation to reject http url")
633+
}
634+
if _, err := cdp.Types.ParseEventPayload("Custom.count", map[string]any{"value": 3}); err != nil {
635+
t.Fatalf("expected Custom.count event to validate: %v", err)
636+
}
637+
if _, err := cdp.Types.ParseEventPayload("Custom.count", map[string]any{"value": 0}); err == nil {
638+
t.Fatal("expected Custom.count event validation to reject zero value")
634639
}
635-
expectPanic(t, func() { cdp.Types.ParseEventPayload("Custom.count", map[string]any{"value": 0}) })
636640
}
637641

638642
func TestAssignedTypeRegistryUpdatesRuntimeValidationAndAliases(t *testing.T) {
@@ -679,8 +683,8 @@ func TestAssignedTypeRegistryUpdatesRuntimeValidationAndAliases(t *testing.T) {
679683
if _, err := cdp.Types.ParseCommandResult("Custom.later", map[string]any{"ok": true}); err != nil {
680684
t.Fatalf("expected Custom.later result to validate: %v", err)
681685
}
682-
if _, ok := cdp.Types.ParseEventPayload("Custom.laterReady", map[string]any{"value": "ok"}); !ok {
683-
t.Fatal("expected Custom.laterReady event to validate")
686+
if _, err := cdp.Types.ParseEventPayload("Custom.laterReady", map[string]any{"value": "ok"}); err != nil {
687+
t.Fatalf("expected Custom.laterReady event to validate: %v", err)
684688
}
685689
}
686690

0 commit comments

Comments
 (0)