starpc 0.48.0 → 0.49.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/echo/echo_srpc.pb.cpp +1 -1
- package/echo/echo_srpc.pb.go +1 -1
- package/echo/echo_srpc.pb.hpp +1 -1
- package/echo/echo_srpc.pb.rs +1 -1
- package/go.mod +7 -7
- package/go.sum +14 -14
- package/mock/mock_srpc.pb.cpp +1 -1
- package/mock/mock_srpc.pb.go +1 -1
- package/mock/mock_srpc.pb.hpp +1 -1
- package/mock/mock_srpc.pb.rs +1 -1
- package/package.json +6 -5
- package/srpc/rwc-conn.go +132 -99
- package/srpc/rwc-conn_test.go +51 -0
- package/srpc/Cargo.toml +0 -25
package/echo/echo_srpc.pb.cpp
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
//go:build deps_only
|
|
2
2
|
|
|
3
3
|
// Code generated by protoc-gen-starpc-cpp. DO NOT EDIT.
|
|
4
|
-
// protoc-gen-starpc-cpp version: v0.
|
|
4
|
+
// protoc-gen-starpc-cpp version: v0.46.1
|
|
5
5
|
// source: github.com/aperturerobotics/starpc/echo/echo.proto
|
|
6
6
|
|
|
7
7
|
#include "echo_srpc.pb.hpp"
|
package/echo/echo_srpc.pb.go
CHANGED
package/echo/echo_srpc.pb.hpp
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
//go:build deps_only && cgo
|
|
2
2
|
|
|
3
3
|
// Code generated by protoc-gen-starpc-cpp. DO NOT EDIT.
|
|
4
|
-
// protoc-gen-starpc-cpp version: v0.
|
|
4
|
+
// protoc-gen-starpc-cpp version: v0.46.1
|
|
5
5
|
// source: github.com/aperturerobotics/starpc/echo/echo.proto
|
|
6
6
|
|
|
7
7
|
#pragma once
|
package/echo/echo_srpc.pb.rs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Code generated by protoc-gen-starpc-rust. DO NOT EDIT.
|
|
2
|
-
// protoc-gen-starpc-rust version: v0.
|
|
2
|
+
// protoc-gen-starpc-rust version: v0.46.1
|
|
3
3
|
// source: github.com/aperturerobotics/starpc/echo/echo.proto
|
|
4
4
|
|
|
5
5
|
#[allow(unused_imports)]
|
package/go.mod
CHANGED
|
@@ -3,32 +3,32 @@ module github.com/aperturerobotics/starpc
|
|
|
3
3
|
go 1.25
|
|
4
4
|
|
|
5
5
|
require (
|
|
6
|
-
github.com/aperturerobotics/common v0.
|
|
6
|
+
github.com/aperturerobotics/common v0.32.0 // latest
|
|
7
7
|
github.com/aperturerobotics/protobuf-go-lite v0.12.2 // latest
|
|
8
|
-
github.com/aperturerobotics/util v1.32.
|
|
8
|
+
github.com/aperturerobotics/util v1.32.5 // latest
|
|
9
9
|
)
|
|
10
10
|
|
|
11
11
|
require (
|
|
12
12
|
github.com/aperturerobotics/abseil-cpp v0.0.0-20260131110040-4bb56e2f9017 // aperture-2
|
|
13
13
|
github.com/aperturerobotics/cli v1.1.0 // indirect
|
|
14
|
-
github.com/aperturerobotics/go-protoc-wasi v0.0.0-
|
|
14
|
+
github.com/aperturerobotics/go-protoc-wasi v0.0.0-20260219012250-c573f70e4509 // indirect
|
|
15
15
|
github.com/aperturerobotics/json-iterator-lite v1.0.1-0.20251104042408-0c9eb8a3f726 // indirect
|
|
16
16
|
github.com/aperturerobotics/protobuf v0.0.0-20260203024654-8201686529c4 // wasi
|
|
17
17
|
)
|
|
18
18
|
|
|
19
19
|
require (
|
|
20
|
-
github.com/aperturerobotics/go-websocket v1.8.15-0.
|
|
20
|
+
github.com/aperturerobotics/go-websocket v1.8.15-0.20260228132212-c5f88237fdf8 // master
|
|
21
21
|
github.com/libp2p/go-yamux/v4 v4.0.2 // latest
|
|
22
22
|
github.com/pkg/errors v0.9.1 // latest
|
|
23
|
-
github.com/sirupsen/logrus v1.9.5-0.
|
|
23
|
+
github.com/sirupsen/logrus v1.9.5-0.20260309202648-9f0600962f75 // latest
|
|
24
24
|
google.golang.org/protobuf v1.36.11 // latest
|
|
25
25
|
)
|
|
26
26
|
|
|
27
27
|
require (
|
|
28
|
-
github.com/aperturerobotics/go-protoc-gen-prost v0.0.0-
|
|
28
|
+
github.com/aperturerobotics/go-protoc-gen-prost v0.0.0-20260219012250-e75aa9f430a2 // indirect
|
|
29
29
|
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
|
|
30
30
|
github.com/tetratelabs/wazero v1.11.0 // indirect
|
|
31
31
|
github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342 // indirect
|
|
32
32
|
golang.org/x/mod v0.33.0 // indirect
|
|
33
|
-
golang.org/x/sys v0.
|
|
33
|
+
golang.org/x/sys v0.41.0 // indirect
|
|
34
34
|
)
|
package/go.sum
CHANGED
|
@@ -2,22 +2,22 @@ github.com/aperturerobotics/abseil-cpp v0.0.0-20260131110040-4bb56e2f9017 h1:3U7
|
|
|
2
2
|
github.com/aperturerobotics/abseil-cpp v0.0.0-20260131110040-4bb56e2f9017/go.mod h1:lNSJTKECIUFAnfeSqy01kXYTYe1BHubW7198jNX3nEw=
|
|
3
3
|
github.com/aperturerobotics/cli v1.1.0 h1:7a+YRC+EY3npAnTzhHV5gLCiw91KS0Ts3XwLILGOsT8=
|
|
4
4
|
github.com/aperturerobotics/cli v1.1.0/go.mod h1:M7BFP9wow5ytTzMyJQOOO991fGfsUqdTI7gGEsHfTQ8=
|
|
5
|
-
github.com/aperturerobotics/common v0.
|
|
6
|
-
github.com/aperturerobotics/common v0.
|
|
7
|
-
github.com/aperturerobotics/go-protoc-gen-prost v0.0.0-
|
|
8
|
-
github.com/aperturerobotics/go-protoc-gen-prost v0.0.0-
|
|
9
|
-
github.com/aperturerobotics/go-protoc-wasi v0.0.0-
|
|
10
|
-
github.com/aperturerobotics/go-protoc-wasi v0.0.0-
|
|
11
|
-
github.com/aperturerobotics/go-websocket v1.8.15-0.
|
|
12
|
-
github.com/aperturerobotics/go-websocket v1.8.15-0.
|
|
5
|
+
github.com/aperturerobotics/common v0.32.0 h1:wKKKUMGs8HZC2exPGVNtj81zqW687mf/rhSbme45CFs=
|
|
6
|
+
github.com/aperturerobotics/common v0.32.0/go.mod h1:m46OxaMDdhPjsWBSdIwkPPCmuFVMuJiRc8/DvC0wStM=
|
|
7
|
+
github.com/aperturerobotics/go-protoc-gen-prost v0.0.0-20260219012250-e75aa9f430a2 h1:DbLHhYu2wdFvwQ02KE3rxBE1vSc+ecMxLEyTwv8Ci00=
|
|
8
|
+
github.com/aperturerobotics/go-protoc-gen-prost v0.0.0-20260219012250-e75aa9f430a2/go.mod h1:OBb/beWmr/pDIZAUfi86j/4tBh2v5ctTxKMqSnh9c/4=
|
|
9
|
+
github.com/aperturerobotics/go-protoc-wasi v0.0.0-20260219012250-c573f70e4509 h1:2O8djle14ujtze1xQb9MVXAdEepumxhoBJPEdf+kNnA=
|
|
10
|
+
github.com/aperturerobotics/go-protoc-wasi v0.0.0-20260219012250-c573f70e4509/go.mod h1:vEq8i7EKb32+KXGtIEZjjhNns+BdsL2dUMw4uhy3578=
|
|
11
|
+
github.com/aperturerobotics/go-websocket v1.8.15-0.20260228132212-c5f88237fdf8 h1:OWYqCKoDoPGXgkD1y465qb8L5odv3nGabeN9wF50GxU=
|
|
12
|
+
github.com/aperturerobotics/go-websocket v1.8.15-0.20260228132212-c5f88237fdf8/go.mod h1:9KnSGuqxSXbdB/Oi0I6vvfPLkclfJwMGAQaDDGVgGow=
|
|
13
13
|
github.com/aperturerobotics/json-iterator-lite v1.0.1-0.20251104042408-0c9eb8a3f726 h1:4B1F0DzuqPzb6WqgCjWaqDD7JU9RDsevQG5OP0DFBgs=
|
|
14
14
|
github.com/aperturerobotics/json-iterator-lite v1.0.1-0.20251104042408-0c9eb8a3f726/go.mod h1:SvGGBv3OVxUyqO0ZxA/nvs6z3cg7NIbZ64TnbV2OISo=
|
|
15
15
|
github.com/aperturerobotics/protobuf v0.0.0-20260203024654-8201686529c4 h1:4Dy3BAHh2kgVdHAqtlwcFsgY0kAwUe2m3rfFcaGwGQg=
|
|
16
16
|
github.com/aperturerobotics/protobuf v0.0.0-20260203024654-8201686529c4/go.mod h1:tMgO7y6SJo/d9ZcvrpNqIQtdYT9de+QmYaHOZ4KnhOg=
|
|
17
17
|
github.com/aperturerobotics/protobuf-go-lite v0.12.2 h1:ujwTKgpIYAVsv8VljB6PPMY5SI8i8m/NlIHAkkuxQcU=
|
|
18
18
|
github.com/aperturerobotics/protobuf-go-lite v0.12.2/go.mod h1:lGH3s5ArCTXKI4wJdlNpaybUtwSjfAG0vdWjxOfMcF8=
|
|
19
|
-
github.com/aperturerobotics/util v1.32.
|
|
20
|
-
github.com/aperturerobotics/util v1.32.
|
|
19
|
+
github.com/aperturerobotics/util v1.32.5 h1:5gr2Ft1rYGFA5yrSm3n18Ghu5Al2uyg7DTtljh1wLHI=
|
|
20
|
+
github.com/aperturerobotics/util v1.32.5/go.mod h1:jXVTz1OQqM3VSrjy06qiCmJLaUm80NxVuKgweaRs5dg=
|
|
21
21
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
|
22
22
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
23
23
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
|
@@ -30,8 +30,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
|
|
30
30
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
31
31
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
|
32
32
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
|
33
|
-
github.com/sirupsen/logrus v1.9.5-0.
|
|
34
|
-
github.com/sirupsen/logrus v1.9.5-0.
|
|
33
|
+
github.com/sirupsen/logrus v1.9.5-0.20260309202648-9f0600962f75 h1:JeSpp4dH/b6DwynjIVL8YDlOSNrEtfhhPajrT3CUUTI=
|
|
34
|
+
github.com/sirupsen/logrus v1.9.5-0.20260309202648-9f0600962f75/go.mod h1:FXZFonkDAnFozmO+5hGAFvB0Yg9/j2SIhA/QuIkP180=
|
|
35
35
|
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
|
36
36
|
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
|
37
37
|
github.com/tetratelabs/wazero v1.11.0 h1:+gKemEuKCTevU4d7ZTzlsvgd1uaToIDtlQlmNbwqYhA=
|
|
@@ -40,8 +40,8 @@ github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342 h1:FnBeRrxr7OU4VvAz
|
|
|
40
40
|
github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
|
|
41
41
|
golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8=
|
|
42
42
|
golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w=
|
|
43
|
-
golang.org/x/sys v0.
|
|
44
|
-
golang.org/x/sys v0.
|
|
43
|
+
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
|
|
44
|
+
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
|
45
45
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
|
46
46
|
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
|
47
47
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
package/mock/mock_srpc.pb.cpp
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
//go:build deps_only
|
|
2
2
|
|
|
3
3
|
// Code generated by protoc-gen-starpc-cpp. DO NOT EDIT.
|
|
4
|
-
// protoc-gen-starpc-cpp version: v0.
|
|
4
|
+
// protoc-gen-starpc-cpp version: v0.46.1
|
|
5
5
|
// source: github.com/aperturerobotics/starpc/mock/mock.proto
|
|
6
6
|
|
|
7
7
|
#include "mock_srpc.pb.hpp"
|
package/mock/mock_srpc.pb.go
CHANGED
package/mock/mock_srpc.pb.hpp
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
//go:build deps_only && cgo
|
|
2
2
|
|
|
3
3
|
// Code generated by protoc-gen-starpc-cpp. DO NOT EDIT.
|
|
4
|
-
// protoc-gen-starpc-cpp version: v0.
|
|
4
|
+
// protoc-gen-starpc-cpp version: v0.46.1
|
|
5
5
|
// source: github.com/aperturerobotics/starpc/mock/mock.proto
|
|
6
6
|
|
|
7
7
|
#pragma once
|
package/mock/mock_srpc.pb.rs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Code generated by protoc-gen-starpc-rust. DO NOT EDIT.
|
|
2
|
-
// protoc-gen-starpc-rust version: v0.
|
|
2
|
+
// protoc-gen-starpc-rust version: v0.46.1
|
|
3
3
|
// source: github.com/aperturerobotics/starpc/mock/mock.proto
|
|
4
4
|
|
|
5
5
|
#[allow(unused_imports)]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "starpc",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.49.1",
|
|
4
4
|
"description": "Streaming protobuf RPC service protocol over any two-way channel.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -96,9 +96,10 @@
|
|
|
96
96
|
"precommit": "lint-staged",
|
|
97
97
|
"release": "npm run release:version && npm run release:commit",
|
|
98
98
|
"release:minor": "npm run release:version:minor && npm run release:commit",
|
|
99
|
-
"release:version": "npm version patch -m \"release: v%s\" --no-git-tag-version",
|
|
100
|
-
"release:version:minor": "npm version minor -m \"release: v%s\" --no-git-tag-version",
|
|
101
|
-
"release:
|
|
99
|
+
"release:version": "npm version patch -m \"release: v%s\" --no-git-tag-version && npm run release:sync-cargo",
|
|
100
|
+
"release:version:minor": "npm version minor -m \"release: v%s\" --no-git-tag-version && npm run release:sync-cargo",
|
|
101
|
+
"release:sync-cargo": "node -e \"const v=require('./package.json').version,f='Cargo.toml',c=require('fs').readFileSync(f,'utf8');require('fs').writeFileSync(f,c.replace(/^version = \\\".*?\\\"/m,'version = \\\"'+v+'\\\"'))\"",
|
|
102
|
+
"release:commit": "git reset && git add package.json Cargo.toml && git commit -s -m \"release: v$(node -p \"require('./package.json').version\")\" && git tag v$(node -p \"require('./package.json').version\")",
|
|
102
103
|
"release:publish": "git push && git push --tags"
|
|
103
104
|
},
|
|
104
105
|
"preferUnplugged": true,
|
|
@@ -141,6 +142,6 @@
|
|
|
141
142
|
"ws": "^8.18.1"
|
|
142
143
|
},
|
|
143
144
|
"resolutions": {
|
|
144
|
-
"@aptre/protobuf-es-lite": "1.0.
|
|
145
|
+
"@aptre/protobuf-es-lite": "1.0.2"
|
|
145
146
|
}
|
|
146
147
|
}
|
package/srpc/rwc-conn.go
CHANGED
|
@@ -12,27 +12,56 @@ import (
|
|
|
12
12
|
// connPktSize is the size of the buffers to use for packets for the RwcConn.
|
|
13
13
|
const connPktSize = 2048
|
|
14
14
|
|
|
15
|
-
//
|
|
15
|
+
// bufPool is a channel-based buffer pool with predictable reuse behavior.
|
|
16
|
+
type bufPool struct {
|
|
17
|
+
ch chan []byte
|
|
18
|
+
size int
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
func newBufPool(poolSize, bufSize int) *bufPool {
|
|
22
|
+
return &bufPool{
|
|
23
|
+
ch: make(chan []byte, poolSize),
|
|
24
|
+
size: bufSize,
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
func (p *bufPool) get() []byte {
|
|
29
|
+
select {
|
|
30
|
+
case b := <-p.ch:
|
|
31
|
+
return b[:p.size]
|
|
32
|
+
default:
|
|
33
|
+
return make([]byte, p.size)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
func (p *bufPool) put(b []byte) {
|
|
38
|
+
select {
|
|
39
|
+
case p.ch <- b:
|
|
40
|
+
default:
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// RwcConn implements a net.Conn with a buffered ReadWriteCloser.
|
|
16
45
|
type RwcConn struct {
|
|
17
|
-
|
|
18
|
-
ctx context.Context
|
|
19
|
-
// ctxCancel is the context canceler
|
|
46
|
+
ctx context.Context
|
|
20
47
|
ctxCancel context.CancelFunc
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
rd time.Time
|
|
30
|
-
wd time.Time
|
|
31
|
-
packetCh chan []byte // packet ch
|
|
48
|
+
rwc io.ReadWriteCloser
|
|
49
|
+
laddr net.Addr
|
|
50
|
+
raddr net.Addr
|
|
51
|
+
|
|
52
|
+
pool *bufPool
|
|
53
|
+
packetCh chan []byte
|
|
54
|
+
|
|
55
|
+
mu sync.Mutex
|
|
56
|
+
rd time.Time
|
|
57
|
+
wd time.Time
|
|
32
58
|
closeErr error
|
|
59
|
+
|
|
60
|
+
pendingMu sync.Mutex
|
|
61
|
+
pending []byte
|
|
33
62
|
}
|
|
34
63
|
|
|
35
|
-
// NewRwcConn constructs a new
|
|
64
|
+
// NewRwcConn constructs a new RwcConn and starts the rx pump.
|
|
36
65
|
func NewRwcConn(
|
|
37
66
|
ctx context.Context,
|
|
38
67
|
rwc io.ReadWriteCloser,
|
|
@@ -50,11 +79,10 @@ func NewRwcConn(
|
|
|
50
79
|
rwc: rwc,
|
|
51
80
|
laddr: laddr,
|
|
52
81
|
raddr: raddr,
|
|
82
|
+
pool: newBufPool(bufferPacketN, connPktSize),
|
|
53
83
|
packetCh: make(chan []byte, bufferPacketN),
|
|
54
84
|
}
|
|
55
|
-
go
|
|
56
|
-
_ = c.rxPump()
|
|
57
|
-
}()
|
|
85
|
+
go c.rxPump()
|
|
58
86
|
return c
|
|
59
87
|
}
|
|
60
88
|
|
|
@@ -68,54 +96,91 @@ func (p *RwcConn) RemoteAddr() net.Addr {
|
|
|
68
96
|
return p.raddr
|
|
69
97
|
}
|
|
70
98
|
|
|
99
|
+
// readDeadline returns the current read deadline under the mutex.
|
|
100
|
+
func (p *RwcConn) readDeadline() time.Time {
|
|
101
|
+
p.mu.Lock()
|
|
102
|
+
defer p.mu.Unlock()
|
|
103
|
+
return p.rd
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// getCloseErr returns the close error under the mutex.
|
|
107
|
+
func (p *RwcConn) getCloseErr() error {
|
|
108
|
+
p.mu.Lock()
|
|
109
|
+
defer p.mu.Unlock()
|
|
110
|
+
return p.closeErr
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// setCloseErr stores the close error under the mutex.
|
|
114
|
+
func (p *RwcConn) setCloseErr(err error) {
|
|
115
|
+
p.mu.Lock()
|
|
116
|
+
defer p.mu.Unlock()
|
|
117
|
+
p.closeErr = err
|
|
118
|
+
}
|
|
119
|
+
|
|
71
120
|
// Read reads data from the connection.
|
|
72
121
|
// Read can be made to time out and return an error after a fixed
|
|
73
122
|
// time limit; see SetDeadline and SetReadDeadline.
|
|
74
|
-
func (p *RwcConn) Read(b []byte) (
|
|
75
|
-
|
|
123
|
+
func (p *RwcConn) Read(b []byte) (int, error) {
|
|
124
|
+
// Drain pending data from a previous partial read first.
|
|
125
|
+
p.pendingMu.Lock()
|
|
126
|
+
if len(p.pending) > 0 {
|
|
127
|
+
n := copy(b, p.pending)
|
|
128
|
+
if n < len(p.pending) {
|
|
129
|
+
p.pending = p.pending[n:]
|
|
130
|
+
} else {
|
|
131
|
+
p.pending = nil
|
|
132
|
+
}
|
|
133
|
+
p.pendingMu.Unlock()
|
|
134
|
+
return n, nil
|
|
135
|
+
}
|
|
136
|
+
p.pendingMu.Unlock()
|
|
137
|
+
|
|
138
|
+
// Build a context with the read deadline if one is set.
|
|
76
139
|
ctx := p.ctx
|
|
140
|
+
deadline := p.readDeadline()
|
|
77
141
|
if !deadline.IsZero() {
|
|
78
|
-
var
|
|
79
|
-
ctx,
|
|
80
|
-
defer
|
|
142
|
+
var cancel context.CancelFunc
|
|
143
|
+
ctx, cancel = context.WithDeadline(ctx, deadline)
|
|
144
|
+
defer cancel()
|
|
81
145
|
}
|
|
82
146
|
|
|
83
|
-
var pkt []byte
|
|
84
|
-
var ok bool
|
|
85
147
|
select {
|
|
86
148
|
case <-ctx.Done():
|
|
87
149
|
if !deadline.IsZero() {
|
|
88
150
|
return 0, os.ErrDeadlineExceeded
|
|
89
151
|
}
|
|
90
152
|
return 0, context.Canceled
|
|
91
|
-
case pkt, ok
|
|
153
|
+
case pkt, ok := <-p.packetCh:
|
|
92
154
|
if !ok {
|
|
93
|
-
err
|
|
155
|
+
err := p.getCloseErr()
|
|
94
156
|
if err == nil {
|
|
95
157
|
err = io.EOF
|
|
96
158
|
}
|
|
97
159
|
return 0, err
|
|
98
160
|
}
|
|
99
|
-
}
|
|
100
161
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
162
|
+
n := copy(b, pkt)
|
|
163
|
+
if n < len(pkt) {
|
|
164
|
+
// Buffer the remaining bytes for the next Read call.
|
|
165
|
+
// Explicitly copy so the pool buffer is not aliased.
|
|
166
|
+
p.pendingMu.Lock()
|
|
167
|
+
p.pending = append(p.pending[:0], pkt[n:]...)
|
|
168
|
+
p.pendingMu.Unlock()
|
|
169
|
+
}
|
|
170
|
+
p.pool.put(pkt)
|
|
171
|
+
return n, nil
|
|
106
172
|
}
|
|
107
|
-
return pl, nil
|
|
108
173
|
}
|
|
109
174
|
|
|
110
175
|
// Write writes data to the connection.
|
|
111
|
-
func (p *RwcConn) Write(pkt []byte) (
|
|
176
|
+
func (p *RwcConn) Write(pkt []byte) (int, error) {
|
|
112
177
|
if len(pkt) == 0 {
|
|
113
178
|
return 0, nil
|
|
114
179
|
}
|
|
115
180
|
|
|
116
181
|
written := 0
|
|
117
182
|
for written < len(pkt) {
|
|
118
|
-
n, err
|
|
183
|
+
n, err := p.rwc.Write(pkt[written:])
|
|
119
184
|
written += n
|
|
120
185
|
if err != nil {
|
|
121
186
|
return written, err
|
|
@@ -124,106 +189,74 @@ func (p *RwcConn) Write(pkt []byte) (n int, err error) {
|
|
|
124
189
|
return written, nil
|
|
125
190
|
}
|
|
126
191
|
|
|
127
|
-
// SetDeadline sets the read and write deadlines associated
|
|
128
|
-
//
|
|
129
|
-
//
|
|
130
|
-
//
|
|
131
|
-
// A deadline is an absolute time after which I/O operations
|
|
132
|
-
// fail instead of blocking. The deadline applies to all future
|
|
133
|
-
// and pending I/O, not just the immediately following call to
|
|
134
|
-
// Read or Write. After a deadline has been exceeded, the
|
|
135
|
-
// connection can be refreshed by setting a deadline in the future.
|
|
136
|
-
//
|
|
137
|
-
// If the deadline is exceeded a call to Read or Write or to other
|
|
138
|
-
// I/O methods will return an error that wraps os.ErrDeadlineExceeded.
|
|
139
|
-
// This can be tested using errors.Is(err, os.ErrDeadlineExceeded).
|
|
140
|
-
// The error's Timeout method will return true, but note that there
|
|
141
|
-
// are other possible errors for which the Timeout method will
|
|
142
|
-
// return true even if the deadline has not been exceeded.
|
|
143
|
-
//
|
|
144
|
-
// An idle timeout can be implemented by repeatedly extending
|
|
145
|
-
// the deadline after successful ReadFrom or WriteTo calls.
|
|
192
|
+
// SetDeadline sets the read and write deadlines associated with the
|
|
193
|
+
// connection. It is equivalent to calling both SetReadDeadline and
|
|
194
|
+
// SetWriteDeadline.
|
|
146
195
|
//
|
|
147
196
|
// A zero value for t means I/O operations will not time out.
|
|
148
197
|
func (p *RwcConn) SetDeadline(t time.Time) error {
|
|
198
|
+
p.mu.Lock()
|
|
199
|
+
defer p.mu.Unlock()
|
|
149
200
|
p.rd = t
|
|
150
201
|
p.wd = t
|
|
151
202
|
return nil
|
|
152
203
|
}
|
|
153
204
|
|
|
154
|
-
// SetReadDeadline sets the deadline for future
|
|
155
|
-
//
|
|
156
|
-
// A zero value for t means
|
|
205
|
+
// SetReadDeadline sets the deadline for future Read calls and any
|
|
206
|
+
// currently-blocked Read call.
|
|
207
|
+
// A zero value for t means Read will not time out.
|
|
157
208
|
func (p *RwcConn) SetReadDeadline(t time.Time) error {
|
|
209
|
+
p.mu.Lock()
|
|
210
|
+
defer p.mu.Unlock()
|
|
158
211
|
p.rd = t
|
|
159
212
|
return nil
|
|
160
213
|
}
|
|
161
214
|
|
|
162
|
-
// SetWriteDeadline sets the deadline for future
|
|
163
|
-
//
|
|
164
|
-
//
|
|
165
|
-
// some of the data was successfully written.
|
|
166
|
-
// A zero value for t means WriteTo will not time out.
|
|
215
|
+
// SetWriteDeadline sets the deadline for future Write calls and any
|
|
216
|
+
// currently-blocked Write call.
|
|
217
|
+
// A zero value for t means Write will not time out.
|
|
167
218
|
func (p *RwcConn) SetWriteDeadline(t time.Time) error {
|
|
219
|
+
p.mu.Lock()
|
|
220
|
+
defer p.mu.Unlock()
|
|
168
221
|
p.wd = t
|
|
169
222
|
return nil
|
|
170
223
|
}
|
|
171
224
|
|
|
172
225
|
// Close closes the connection.
|
|
173
|
-
// Any blocked
|
|
226
|
+
// Any blocked Read or Write operations will be unblocked and return errors.
|
|
174
227
|
func (p *RwcConn) Close() error {
|
|
228
|
+
p.ctxCancel()
|
|
175
229
|
return p.rwc.Close()
|
|
176
230
|
}
|
|
177
231
|
|
|
178
|
-
// getArenaBuf returns a buf from the packet arena with at least the given size
|
|
179
|
-
func (p *RwcConn) getArenaBuf(size int) []byte {
|
|
180
|
-
var buf []byte
|
|
181
|
-
bufp := p.ar.Get()
|
|
182
|
-
if bufp != nil {
|
|
183
|
-
buf = *bufp.(*[]byte)
|
|
184
|
-
}
|
|
185
|
-
if size != 0 {
|
|
186
|
-
if cap(buf) < size {
|
|
187
|
-
buf = make([]byte, size)
|
|
188
|
-
} else {
|
|
189
|
-
buf = buf[:size]
|
|
190
|
-
}
|
|
191
|
-
} else {
|
|
192
|
-
buf = buf[:cap(buf)]
|
|
193
|
-
}
|
|
194
|
-
return buf
|
|
195
|
-
}
|
|
196
|
-
|
|
197
232
|
// rxPump receives messages from the underlying connection.
|
|
198
|
-
func (p *RwcConn) rxPump()
|
|
233
|
+
func (p *RwcConn) rxPump() {
|
|
234
|
+
var rerr error
|
|
199
235
|
defer func() {
|
|
200
|
-
p.
|
|
236
|
+
p.setCloseErr(rerr)
|
|
201
237
|
close(p.packetCh)
|
|
202
238
|
}()
|
|
203
239
|
|
|
204
240
|
for {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
return p.ctx.Err()
|
|
208
|
-
default:
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
pktBuf := p.getArenaBuf(int(connPktSize))
|
|
212
|
-
n, err := p.rwc.Read(pktBuf)
|
|
241
|
+
buf := p.pool.get()
|
|
242
|
+
n, err := p.rwc.Read(buf)
|
|
213
243
|
if n == 0 {
|
|
214
|
-
p.
|
|
244
|
+
p.pool.put(buf)
|
|
215
245
|
} else {
|
|
216
246
|
select {
|
|
217
247
|
case <-p.ctx.Done():
|
|
218
|
-
|
|
219
|
-
|
|
248
|
+
p.pool.put(buf)
|
|
249
|
+
rerr = context.Canceled
|
|
250
|
+
return
|
|
251
|
+
case p.packetCh <- buf[:n]:
|
|
220
252
|
}
|
|
221
253
|
}
|
|
222
254
|
if err != nil {
|
|
223
|
-
|
|
255
|
+
rerr = err
|
|
256
|
+
return
|
|
224
257
|
}
|
|
225
258
|
}
|
|
226
259
|
}
|
|
227
260
|
|
|
228
261
|
// _ is a type assertion
|
|
229
|
-
var _ net.Conn = (
|
|
262
|
+
var _ net.Conn = (*RwcConn)(nil)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
package srpc
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"bytes"
|
|
5
|
+
"context"
|
|
6
|
+
"io"
|
|
7
|
+
"testing"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
// blockingRWC wraps a pipe for testing RwcConn.
|
|
11
|
+
type blockingRWC struct {
|
|
12
|
+
r io.Reader
|
|
13
|
+
w io.Writer
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
func (b *blockingRWC) Read(p []byte) (int, error) { return b.r.Read(p) }
|
|
17
|
+
func (b *blockingRWC) Write(p []byte) (int, error) { return b.w.Write(p) }
|
|
18
|
+
func (b *blockingRWC) Close() error { return nil }
|
|
19
|
+
|
|
20
|
+
// TestRwcConnReadBuffering verifies that RwcConn.Read does not drop data
|
|
21
|
+
// when the caller's buffer is smaller than the received packet.
|
|
22
|
+
func TestRwcConnReadBuffering(t *testing.T) {
|
|
23
|
+
pr, pw := io.Pipe()
|
|
24
|
+
rwc := &blockingRWC{r: pr, w: pw}
|
|
25
|
+
|
|
26
|
+
ctx, cancel := context.WithCancel(t.Context())
|
|
27
|
+
defer cancel()
|
|
28
|
+
|
|
29
|
+
conn := NewRwcConn(ctx, rwc, nil, nil, 10)
|
|
30
|
+
|
|
31
|
+
// Write a 100-byte message through the pipe.
|
|
32
|
+
msg := bytes.Repeat([]byte("abcdefghij"), 10) // 100 bytes
|
|
33
|
+
go func() {
|
|
34
|
+
_, _ = pw.Write(msg)
|
|
35
|
+
}()
|
|
36
|
+
|
|
37
|
+
// Read in small chunks (16 bytes at a time) to simulate bufio.Reader.
|
|
38
|
+
var got []byte
|
|
39
|
+
buf := make([]byte, 16)
|
|
40
|
+
for len(got) < len(msg) {
|
|
41
|
+
n, err := conn.Read(buf)
|
|
42
|
+
if err != nil {
|
|
43
|
+
t.Fatalf("Read error after %d bytes: %v", len(got), err)
|
|
44
|
+
}
|
|
45
|
+
got = append(got, buf[:n]...)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if !bytes.Equal(got, msg) {
|
|
49
|
+
t.Fatalf("data mismatch: got %d bytes, want %d bytes\ngot: %q\nwant: %q", len(got), len(msg), got, msg)
|
|
50
|
+
}
|
|
51
|
+
}
|
package/srpc/Cargo.toml
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
[package]
|
|
2
|
-
name = "starpc"
|
|
3
|
-
version.workspace = true
|
|
4
|
-
edition.workspace = true
|
|
5
|
-
rust-version.workspace = true
|
|
6
|
-
license.workspace = true
|
|
7
|
-
repository.workspace = true
|
|
8
|
-
description.workspace = true
|
|
9
|
-
keywords.workspace = true
|
|
10
|
-
categories.workspace = true
|
|
11
|
-
|
|
12
|
-
[lib]
|
|
13
|
-
path = "lib.rs"
|
|
14
|
-
|
|
15
|
-
[dependencies]
|
|
16
|
-
prost = { workspace = true }
|
|
17
|
-
bytes = { workspace = true }
|
|
18
|
-
tokio = { workspace = true }
|
|
19
|
-
tokio-util = { workspace = true }
|
|
20
|
-
futures = { workspace = true }
|
|
21
|
-
thiserror = { workspace = true }
|
|
22
|
-
async-trait = { workspace = true }
|
|
23
|
-
pin-project-lite = { workspace = true }
|
|
24
|
-
scopeguard = { workspace = true }
|
|
25
|
-
|