+11
-10
examples/batch-pipelining/go.mod
+11
-10
examples/batch-pipelining/go.mod
···
1
1
module github.com/gocapnweb/examples/batch-pipelining
2
2
3
-
go 1.21
3
+
go 1.23.0
4
+
5
+
toolchain go1.24.2
4
6
5
7
replace github.com/gocapnweb => ../..
6
8
7
-
require (
8
-
github.com/gocapnweb v0.0.0-00010101000000-000000000000
9
-
github.com/labstack/echo/v4 v4.11.4
10
-
)
9
+
require github.com/gocapnweb v0.0.0-00010101000000-000000000000
11
10
12
11
require (
13
12
github.com/gorilla/websocket v1.5.0 // indirect
13
+
github.com/labstack/echo/v4 v4.13.4 // indirect
14
14
github.com/labstack/gommon v0.4.2 // indirect
15
-
github.com/mattn/go-colorable v0.1.13 // indirect
15
+
github.com/mattn/go-colorable v0.1.14 // indirect
16
16
github.com/mattn/go-isatty v0.0.20 // indirect
17
17
github.com/valyala/bytebufferpool v1.0.0 // indirect
18
18
github.com/valyala/fasttemplate v1.2.2 // indirect
19
-
golang.org/x/crypto v0.17.0 // indirect
20
-
golang.org/x/net v0.19.0 // indirect
21
-
golang.org/x/sys v0.15.0 // indirect
22
-
golang.org/x/text v0.14.0 // indirect
19
+
golang.org/x/crypto v0.38.0 // indirect
20
+
golang.org/x/net v0.40.0 // indirect
21
+
golang.org/x/sys v0.33.0 // indirect
22
+
golang.org/x/text v0.25.0 // indirect
23
+
golang.org/x/time v0.11.0 // indirect
23
24
)
+31
-2
examples/batch-pipelining/go.sum
+31
-2
examples/batch-pipelining/go.sum
···
1
-
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
2
-
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
1
+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
2
+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3
3
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
4
4
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
5
+
github.com/labstack/echo/v4 v4.13.4 h1:oTZZW+T3s9gAu5L8vmzihV7/lkXGZuITzTQkTEhcXEA=
6
+
github.com/labstack/echo/v4 v4.13.4/go.mod h1:g63b33BZ5vZzcIUF8AtRH40DrTlXnx4UMC8rBdndmjQ=
7
+
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
8
+
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
9
+
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
10
+
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
11
+
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
12
+
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
13
+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
14
+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
15
+
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
16
+
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
17
+
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
18
+
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
19
+
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
20
+
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
21
+
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
22
+
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
23
+
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
24
+
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
25
+
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
26
+
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
27
+
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
28
+
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
29
+
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
30
+
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
31
+
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
32
+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
33
+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-1
examples/batch-pipelining/main.go
-1
examples/batch-pipelining/main.go
+46
-9
rpc.go
+46
-9
rpc.go
···
248
248
return nil, err
249
249
}
250
250
251
-
// Cache the result
251
+
// Normalize the result for pipeline traversal
252
+
normalizedResult, err := s.normalizeResult(result)
253
+
if err != nil {
254
+
return nil, err
255
+
}
256
+
257
+
// Cache the normalized result
252
258
sessionData.mu.Lock()
253
-
sessionData.PendingResults[refExportID] = result
259
+
sessionData.PendingResults[refExportID] = normalizedResult
254
260
delete(sessionData.PendingOperations, refExportID)
255
261
sessionData.mu.Unlock()
256
262
257
263
// If there's a path, traverse it
258
264
if len(v) >= 3 {
259
265
if pathArray, ok := v[2].([]interface{}); ok {
260
-
return s.traversePath(result, pathArray)
266
+
return s.traversePath(normalizedResult, pathArray)
261
267
}
262
268
}
263
-
return result, nil
269
+
return normalizedResult, nil
264
270
}
265
271
sessionData.mu.RUnlock()
266
272
···
384
390
return s.createErrorResponse(exportID, "MethodError", err.Error()), nil
385
391
}
386
392
387
-
// Store the result for future reference
393
+
// Normalize the result to ensure it's JSON-compatible for pipeline traversal
394
+
normalizedResult, err := s.normalizeResult(result)
395
+
if err != nil {
396
+
return s.createErrorResponse(exportID, "SerializationError", err.Error()), nil
397
+
}
398
+
399
+
// Store the normalized result for future reference
388
400
sessionData.mu.Lock()
389
-
sessionData.PendingResults[exportID] = result
401
+
sessionData.PendingResults[exportID] = normalizedResult
390
402
sessionData.mu.Unlock()
391
403
392
404
// Send as resolve
393
-
if _, ok := result.([]interface{}); ok {
394
-
return []interface{}{"resolve", exportID, []interface{}{result}}, nil
405
+
if _, ok := normalizedResult.([]interface{}); ok {
406
+
return []interface{}{"resolve", exportID, []interface{}{normalizedResult}}, nil
395
407
}
396
-
return []interface{}{"resolve", exportID, result}, nil
408
+
return []interface{}{"resolve", exportID, normalizedResult}, nil
397
409
}
398
410
sessionData.mu.RUnlock()
399
411
···
417
429
errorBytes, _ := json.Marshal(errorData)
418
430
log.Printf("Abort received: %s", string(errorBytes))
419
431
}
432
+
433
+
// normalizeResult ensures that Go structs are converted to map[string]interface{}
434
+
// for proper pipeline traversal. This is necessary because Go structs need to be
435
+
// JSON-marshaled and then unmarshaled to become navigable objects.
436
+
func (s *RpcSession) normalizeResult(result interface{}) (interface{}, error) {
437
+
// If it's already a map[string]interface{} or basic type, return as-is
438
+
switch result.(type) {
439
+
case map[string]interface{}, []interface{}, string, float64, bool, nil:
440
+
return result, nil
441
+
}
442
+
443
+
// For other types (like structs), marshal to JSON and unmarshal to interface{}
444
+
// This converts structs to map[string]interface{} which can be traversed
445
+
jsonBytes, err := json.Marshal(result)
446
+
if err != nil {
447
+
return nil, fmt.Errorf("failed to marshal result: %w", err)
448
+
}
449
+
450
+
var normalized interface{}
451
+
if err := json.Unmarshal(jsonBytes, &normalized); err != nil {
452
+
return nil, fmt.Errorf("failed to unmarshal result: %w", err)
453
+
}
454
+
455
+
return normalized, nil
456
+
}