starpc 0.52.1 → 0.52.2
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/README.md +37 -8
- package/dist/srpc/client-rpc.d.ts +1 -0
- package/dist/srpc/client-rpc.js +9 -0
- package/dist/srpc/client-rpc.test.d.ts +1 -0
- package/dist/srpc/client-rpc.test.js +50 -0
- package/dist/srpc/common-rpc.d.ts +5 -0
- package/dist/srpc/common-rpc.js +37 -8
- package/dist/srpc/errors.d.ts +2 -0
- package/dist/srpc/errors.js +14 -0
- package/dist/srpc/index.d.ts +1 -1
- package/dist/srpc/index.js +1 -1
- package/echo/Cargo.toml +8 -0
- package/echo/echo_e2e_test.cpp +542 -985
- package/echo/echo_srpc.pb.cpp +3 -5
- package/echo/echo_srpc.pb.go +6 -9
- package/echo/echo_srpc.pb.hpp +23 -3
- package/echo/echo_srpc.pb.rs +61 -26
- package/echo/echo_srpc.py +4 -1
- package/echo/half_close_test.rs +178 -0
- package/echo/integration_server.rs +14 -21
- package/echo/main.rs +28 -48
- package/go.mod +1 -1
- package/go.sum +2 -18
- package/integration/cross-language/cpp-client.cpp +446 -402
- package/integration/cross-language/cpp-pipe-server.cpp +139 -0
- package/integration/cross-language/cpp-pipe_test.go +114 -0
- package/integration/cross-language/cpp-server.cpp +222 -186
- package/mock/mock_srpc.pb.cpp +1 -1
- package/mock/mock_srpc.pb.hpp +1 -1
- package/mock/mock_srpc.pb.rs +10 -9
- package/package.json +1 -1
- package/srpc/CMakeLists.txt +3 -58
- package/srpc/README-cpp.md +69 -0
- package/srpc/accept.go +10 -4
- package/srpc/accept_test.go +25 -0
- package/srpc/build.rs +129 -34
- package/srpc/client-half-close_test.go +152 -0
- package/srpc/client-invoker.go +32 -42
- package/srpc/client-invoker_test.go +53 -0
- package/srpc/client-rpc.cpp +65 -80
- package/srpc/client-rpc.go +32 -33
- package/srpc/client-rpc.hpp +52 -38
- package/srpc/client-rpc.test.ts +67 -0
- package/srpc/client-rpc.ts +10 -0
- package/srpc/client-rpc_test.go +76 -0
- package/srpc/client.cpp +99 -87
- package/srpc/client.hpp +46 -35
- package/srpc/client.rs +78 -38
- package/srpc/client_half_close_test.cc +331 -0
- package/srpc/client_invoker.rs +75 -0
- package/srpc/common-rpc.cpp +186 -146
- package/srpc/common-rpc.go +5 -4
- package/srpc/common-rpc.hpp +119 -89
- package/srpc/common-rpc.ts +43 -8
- package/srpc/common-rpc_test.go +23 -0
- package/srpc/error.rs +19 -2
- package/srpc/errors.hpp +80 -50
- package/srpc/errors.ts +16 -0
- package/srpc/handler.hpp +9 -7
- package/srpc/handler.rs +7 -45
- package/srpc/index.ts +2 -0
- package/srpc/invoker.hpp +82 -55
- package/srpc/invoker.rs +14 -52
- package/srpc/lib.rs +2 -0
- package/srpc/message.hpp +17 -12
- package/srpc/msg-stream.go +1 -0
- package/srpc/msg-stream.hpp +108 -61
- package/srpc/mux.cpp +84 -84
- package/srpc/mux.hpp +48 -38
- package/srpc/mux.rs +4 -4
- package/srpc/net.go +12 -3
- package/srpc/packet.cpp +60 -58
- package/srpc/packet.hpp +35 -20
- package/srpc/packet.rs +8 -27
- package/srpc/rpc.rs +332 -115
- package/srpc/rpc_lifecycle_test.cc +333 -0
- package/srpc/server-cancel_test.go +39 -0
- package/srpc/server-rpc.cpp +83 -73
- package/srpc/server-rpc.go +21 -19
- package/srpc/server-rpc.hpp +56 -37
- package/srpc/server.rs +76 -131
- package/srpc/starpc.hpp +4 -2
- package/srpc/stream.go +4 -0
- package/srpc/stream.hpp +95 -34
- package/srpc/stream.rs +7 -2
- package/srpc/testing.rs +11 -66
- package/srpc/transport.rs +21 -71
- package/srpc/websocket.rs +106 -57
- package/srpc/writer.hpp +46 -32
- package/srpc/yamux.rs +82 -26
- package/srpc/tests/integration_test.rs +0 -495
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
//go:build deps_only
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
/*
|
|
4
|
+
* C++ TCP integration server for cross-language testing: it listens on TCP
|
|
5
|
+
* and serves one RPC per connection over length-prefixed packets.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#include "echo/echo_srpc.pb.hpp"
|
|
9
|
+
#include "rpcstream/rpcstream.hpp"
|
|
10
|
+
#include "srpc/rpcproto.pb.h"
|
|
11
|
+
#include "srpc/starpc.hpp"
|
|
5
12
|
|
|
6
13
|
#include <arpa/inet.h>
|
|
7
14
|
#include <csignal>
|
|
@@ -13,209 +20,238 @@
|
|
|
13
20
|
#include <sys/socket.h>
|
|
14
21
|
#include <thread>
|
|
15
22
|
#include <unistd.h>
|
|
16
|
-
|
|
17
|
-
#include "echo/echo_srpc.pb.hpp"
|
|
18
|
-
#include "rpcstream/rpcstream.hpp"
|
|
19
|
-
#include "srpc/rpcproto.pb.h"
|
|
20
|
-
#include "srpc/starpc.hpp"
|
|
23
|
+
#include <vector>
|
|
21
24
|
|
|
22
25
|
namespace {
|
|
23
26
|
|
|
24
|
-
|
|
25
|
-
bool ReadFull(int fd, void *buf, size_t n)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
/* ReadFull reads exactly n bytes from fd, reporting short reads as false. */
|
|
28
|
+
bool ReadFull(int fd, void *buf, size_t n)
|
|
29
|
+
{
|
|
30
|
+
size_t total = 0;
|
|
31
|
+
while (total < n) {
|
|
32
|
+
ssize_t r =
|
|
33
|
+
read(fd, static_cast<char *>(buf) + total, n - total);
|
|
34
|
+
if (r <= 0)
|
|
35
|
+
return false;
|
|
36
|
+
total += r;
|
|
37
|
+
}
|
|
38
|
+
return true;
|
|
34
39
|
}
|
|
35
40
|
|
|
36
|
-
|
|
37
|
-
bool WriteFull(int fd, const void *buf, size_t n)
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
/* WriteFull writes exactly n bytes to fd, reporting short writes as false. */
|
|
42
|
+
bool WriteFull(int fd, const void *buf, size_t n)
|
|
43
|
+
{
|
|
44
|
+
size_t total = 0;
|
|
45
|
+
while (total < n) {
|
|
46
|
+
ssize_t w = write(fd, static_cast<const char *>(buf) + total,
|
|
47
|
+
n - total);
|
|
48
|
+
if (w <= 0)
|
|
49
|
+
return false;
|
|
50
|
+
total += w;
|
|
51
|
+
}
|
|
52
|
+
return true;
|
|
46
53
|
}
|
|
47
54
|
|
|
48
|
-
|
|
55
|
+
/*
|
|
56
|
+
* TcpPacketWriter writes length-prefixed packets to a TCP socket. The fd is
|
|
57
|
+
* borrowed and closed by the connection handler, not the writer.
|
|
58
|
+
*/
|
|
49
59
|
class TcpPacketWriter : public starpc::PacketWriter {
|
|
50
60
|
public:
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
61
|
+
explicit TcpPacketWriter(int fd)
|
|
62
|
+
: fd(fd)
|
|
63
|
+
{
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
starpc::Error WritePacket(const srpc::Packet &pkt) override
|
|
67
|
+
{
|
|
68
|
+
std::lock_guard<std::mutex> lock(mu);
|
|
69
|
+
|
|
70
|
+
std::string data;
|
|
71
|
+
if (!pkt.SerializeToString(&data))
|
|
72
|
+
return starpc::Error::InvalidMessage;
|
|
73
|
+
|
|
74
|
+
/* The length prefix is a little-endian uint32. */
|
|
75
|
+
uint32_t len = static_cast<uint32_t>(data.size());
|
|
76
|
+
if (!WriteFull(fd, &len, 4))
|
|
77
|
+
return starpc::Error::EOF_;
|
|
78
|
+
if (!WriteFull(fd, data.data(), data.size()))
|
|
79
|
+
return starpc::Error::EOF_;
|
|
80
|
+
return starpc::Error::OK;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
starpc::Error Close() override
|
|
84
|
+
{
|
|
85
|
+
shutdown(fd, SHUT_WR);
|
|
86
|
+
return starpc::Error::OK;
|
|
87
|
+
}
|
|
72
88
|
|
|
73
89
|
private:
|
|
74
|
-
|
|
75
|
-
|
|
90
|
+
int fd;
|
|
91
|
+
std::mutex mu;
|
|
76
92
|
};
|
|
77
93
|
|
|
78
|
-
|
|
94
|
+
/* EchoServerImpl implements the echo service under test. */
|
|
79
95
|
class EchoServerImpl : public echo::SRPCEchoerServer {
|
|
80
96
|
public:
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
97
|
+
starpc::Error Echo(const echo::EchoMsg &req,
|
|
98
|
+
echo::EchoMsg *resp) override
|
|
99
|
+
{
|
|
100
|
+
resp->set_body(req.body());
|
|
101
|
+
return starpc::Error::OK;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
starpc::Error
|
|
105
|
+
EchoServerStream(const echo::EchoMsg &req,
|
|
106
|
+
echo::SRPCEchoer_EchoServerStreamStream *strm) override
|
|
107
|
+
{
|
|
108
|
+
for (int i = 0; i < 5; i++) {
|
|
109
|
+
echo::EchoMsg msg;
|
|
110
|
+
msg.set_body(req.body());
|
|
111
|
+
starpc::Error err = strm->Send(msg);
|
|
112
|
+
if (err != starpc::Error::OK)
|
|
113
|
+
return err;
|
|
114
|
+
}
|
|
115
|
+
return starpc::Error::OK;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
starpc::Error
|
|
119
|
+
EchoClientStream(echo::SRPCEchoer_EchoClientStreamStream *strm,
|
|
120
|
+
echo::EchoMsg *resp) override
|
|
121
|
+
{
|
|
122
|
+
echo::EchoMsg msg;
|
|
123
|
+
starpc::Error err = strm->Recv(&msg);
|
|
124
|
+
if (err != starpc::Error::OK)
|
|
125
|
+
return err;
|
|
126
|
+
resp->set_body(msg.body());
|
|
127
|
+
return starpc::Error::OK;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
starpc::Error
|
|
131
|
+
EchoBidiStream(echo::SRPCEchoer_EchoBidiStreamStream *strm) override
|
|
132
|
+
{
|
|
133
|
+
/* Send the initial message the other clients expect. */
|
|
134
|
+
echo::EchoMsg init;
|
|
135
|
+
init.set_body("hello from server");
|
|
136
|
+
starpc::Error err = strm->Send(init);
|
|
137
|
+
if (err != starpc::Error::OK)
|
|
138
|
+
return err;
|
|
139
|
+
|
|
140
|
+
while (true) {
|
|
141
|
+
echo::EchoMsg msg;
|
|
142
|
+
err = strm->Recv(&msg);
|
|
143
|
+
if (err == starpc::Error::EOF_)
|
|
144
|
+
break;
|
|
145
|
+
if (err != starpc::Error::OK)
|
|
146
|
+
return err;
|
|
147
|
+
err = strm->Send(msg);
|
|
148
|
+
if (err != starpc::Error::OK)
|
|
149
|
+
return err;
|
|
150
|
+
}
|
|
151
|
+
return starpc::Error::OK;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
starpc::Error RpcStream(echo::SRPCEchoer_RpcStreamStream *) override
|
|
155
|
+
{
|
|
156
|
+
return starpc::Error::Unimplemented;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
starpc::Error DoNothing(const google::protobuf::Empty &,
|
|
160
|
+
google::protobuf::Empty *) override
|
|
161
|
+
{
|
|
162
|
+
return starpc::Error::OK;
|
|
163
|
+
}
|
|
140
164
|
};
|
|
141
165
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
166
|
+
/*
|
|
167
|
+
* HandleConnection serves one TCP connection: it reads length-prefixed
|
|
168
|
+
* packets until the socket ends, then closes the fd.
|
|
169
|
+
*/
|
|
170
|
+
void HandleConnection(int fd, starpc::Mux *mux)
|
|
171
|
+
{
|
|
172
|
+
auto writer = std::make_unique<TcpPacketWriter>(fd);
|
|
173
|
+
auto server_rpc = starpc::NewServerRPC(mux, writer.get());
|
|
174
|
+
|
|
175
|
+
while (true) {
|
|
176
|
+
/* The length prefix is a little-endian uint32. */
|
|
177
|
+
uint32_t len = 0;
|
|
178
|
+
if (!ReadFull(fd, &len, 4))
|
|
179
|
+
break;
|
|
180
|
+
|
|
181
|
+
std::string data(len, '\0');
|
|
182
|
+
if (!ReadFull(fd, data.data(), len))
|
|
183
|
+
break;
|
|
184
|
+
|
|
185
|
+
starpc::Error err = server_rpc->HandlePacketData(data);
|
|
186
|
+
if (err != starpc::Error::OK && err != starpc::Error::Completed)
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
close(fd);
|
|
164
191
|
}
|
|
165
192
|
|
|
166
193
|
} // namespace
|
|
167
194
|
|
|
168
|
-
int main()
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
195
|
+
int main()
|
|
196
|
+
{
|
|
197
|
+
signal(SIGPIPE, SIG_IGN);
|
|
198
|
+
|
|
199
|
+
auto mux = starpc::NewMux();
|
|
200
|
+
EchoServerImpl server;
|
|
201
|
+
auto [handler, err] = echo::SRPCRegisterEchoer(mux.get(), &server);
|
|
202
|
+
(void)handler;
|
|
203
|
+
if (err != starpc::Error::OK) {
|
|
204
|
+
std::cerr << "register error: " << starpc::ErrorString(err)
|
|
205
|
+
<< std::endl;
|
|
206
|
+
return 1;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
|
210
|
+
if (sockfd < 0) {
|
|
211
|
+
std::cerr << "socket error" << std::endl;
|
|
212
|
+
return 1;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
int opt = 1;
|
|
216
|
+
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
|
|
217
|
+
|
|
218
|
+
struct sockaddr_in addr{};
|
|
219
|
+
addr.sin_family = AF_INET;
|
|
220
|
+
addr.sin_port = 0; /* OS-assigned port. */
|
|
221
|
+
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
|
222
|
+
|
|
223
|
+
if (bind(sockfd, reinterpret_cast<struct sockaddr *>(&addr),
|
|
224
|
+
sizeof(addr)) < 0) {
|
|
225
|
+
std::cerr << "bind error" << std::endl;
|
|
226
|
+
close(sockfd);
|
|
227
|
+
return 1;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (listen(sockfd, 10) < 0) {
|
|
231
|
+
std::cerr << "listen error" << std::endl;
|
|
232
|
+
close(sockfd);
|
|
233
|
+
return 1;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/* Report the assigned port so the test driver can connect. */
|
|
237
|
+
socklen_t addr_len = sizeof(addr);
|
|
238
|
+
getsockname(sockfd, reinterpret_cast<struct sockaddr *>(&addr),
|
|
239
|
+
&addr_len);
|
|
240
|
+
std::cout << "LISTENING 127.0.0.1:" << ntohs(addr.sin_port)
|
|
241
|
+
<< std::endl;
|
|
242
|
+
|
|
243
|
+
/* Connection threads borrow mux, so join them before it ends. */
|
|
244
|
+
std::vector<std::thread> connections;
|
|
245
|
+
while (true) {
|
|
246
|
+
int client_fd = accept(sockfd, nullptr, nullptr);
|
|
247
|
+
if (client_fd < 0)
|
|
248
|
+
break;
|
|
249
|
+
connections.emplace_back(HandleConnection, client_fd,
|
|
250
|
+
mux.get());
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
close(sockfd);
|
|
254
|
+
for (auto &connection : connections)
|
|
255
|
+
connection.join();
|
|
256
|
+
return 0;
|
|
221
257
|
}
|
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.52.2-0.20260903015026-8f335488f9dc+dirty
|
|
5
5
|
// source: github.com/aperturerobotics/starpc/mock/mock.proto
|
|
6
6
|
|
|
7
7
|
#include "mock_srpc.pb.hpp"
|
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.52.2-0.20260903015026-8f335488f9dc+dirty
|
|
5
5
|
// source: github.com/aperturerobotics/starpc/mock/mock.proto
|
|
6
6
|
|
|
7
7
|
#pragma once
|
package/mock/mock_srpc.pb.rs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// Code generated by protoc-gen-starpc-rust. DO NOT EDIT.
|
|
2
|
-
// protoc-gen-starpc-rust version:
|
|
2
|
+
// protoc-gen-starpc-rust version: (devel)
|
|
3
3
|
// source: github.com/aperturerobotics/starpc/mock/mock.proto
|
|
4
4
|
|
|
5
5
|
#[allow(unused_imports)]
|
|
6
|
-
use starpc::StreamExt;
|
|
6
|
+
use starpc::StreamExt as _;
|
|
7
7
|
|
|
8
8
|
/// Service ID for Mock.
|
|
9
9
|
pub const MOCK_SERVICE_ID: &str = "e2e.mock.Mock";
|
|
@@ -30,7 +30,9 @@ impl<C: starpc::Client> MockClientImpl<C> {
|
|
|
30
30
|
#[starpc::async_trait]
|
|
31
31
|
impl<C: starpc::Client + 'static> MockClient for MockClientImpl<C> {
|
|
32
32
|
async fn mock_request(&self, request: &MockMsg) -> starpc::Result<MockMsg> {
|
|
33
|
-
self.client
|
|
33
|
+
self.client
|
|
34
|
+
.exec_call("e2e.mock.Mock", "MockRequest", request)
|
|
35
|
+
.await
|
|
34
36
|
}
|
|
35
37
|
}
|
|
36
38
|
|
|
@@ -41,9 +43,7 @@ pub trait MockServer: Send + Sync {
|
|
|
41
43
|
async fn mock_request(&self, request: MockMsg) -> starpc::Result<MockMsg>;
|
|
42
44
|
}
|
|
43
45
|
|
|
44
|
-
const MOCK_METHOD_IDS: &[&str] = &[
|
|
45
|
-
"MockRequest",
|
|
46
|
-
];
|
|
46
|
+
const MOCK_METHOD_IDS: &[&str] = &["MockRequest"];
|
|
47
47
|
|
|
48
48
|
/// Handler for Mock.
|
|
49
49
|
pub struct MockHandler<S: MockServer> {
|
|
@@ -53,7 +53,9 @@ pub struct MockHandler<S: MockServer> {
|
|
|
53
53
|
impl<S: MockServer + 'static> MockHandler<S> {
|
|
54
54
|
/// Creates a new handler wrapping the server implementation.
|
|
55
55
|
pub fn new(server: S) -> Self {
|
|
56
|
-
Self {
|
|
56
|
+
Self {
|
|
57
|
+
server: std::sync::Arc::new(server),
|
|
58
|
+
}
|
|
57
59
|
}
|
|
58
60
|
|
|
59
61
|
/// Creates a new handler with a shared server.
|
|
@@ -76,7 +78,7 @@ impl<S: MockServer + 'static> starpc::Invoker for MockHandler<S> {
|
|
|
76
78
|
Ok(r) => r,
|
|
77
79
|
Err(e) => return (true, Err(e)),
|
|
78
80
|
};
|
|
79
|
-
match self.server.
|
|
81
|
+
match <S as MockServer>::mock_request(self.server.as_ref(), request).await {
|
|
80
82
|
Ok(response) => {
|
|
81
83
|
if let Err(e) = stream.msg_send(&response).await {
|
|
82
84
|
return (true, Err(e));
|
|
@@ -100,4 +102,3 @@ impl<S: MockServer + 'static> starpc::Handler for MockHandler<S> {
|
|
|
100
102
|
MOCK_METHOD_IDS
|
|
101
103
|
}
|
|
102
104
|
}
|
|
103
|
-
|
package/package.json
CHANGED
package/srpc/CMakeLists.txt
CHANGED
|
@@ -1,59 +1,4 @@
|
|
|
1
|
-
cmake_minimum_required(VERSION 3.
|
|
1
|
+
cmake_minimum_required(VERSION 3.24)
|
|
2
2
|
|
|
3
|
-
#
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
set(STARPC_SOURCES
|
|
7
|
-
packet.cpp
|
|
8
|
-
common-rpc.cpp
|
|
9
|
-
client-rpc.cpp
|
|
10
|
-
server-rpc.cpp
|
|
11
|
-
mux.cpp
|
|
12
|
-
client.cpp
|
|
13
|
-
rpcproto.pb.cc
|
|
14
|
-
)
|
|
15
|
-
|
|
16
|
-
set(STARPC_HEADERS
|
|
17
|
-
starpc.hpp
|
|
18
|
-
errors.hpp
|
|
19
|
-
message.hpp
|
|
20
|
-
writer.hpp
|
|
21
|
-
packet.hpp
|
|
22
|
-
stream.hpp
|
|
23
|
-
msg-stream.hpp
|
|
24
|
-
common-rpc.hpp
|
|
25
|
-
client-rpc.hpp
|
|
26
|
-
server-rpc.hpp
|
|
27
|
-
invoker.hpp
|
|
28
|
-
handler.hpp
|
|
29
|
-
mux.hpp
|
|
30
|
-
client.hpp
|
|
31
|
-
rpcproto.pb.h
|
|
32
|
-
)
|
|
33
|
-
|
|
34
|
-
add_library(starpc ${STARPC_SOURCES})
|
|
35
|
-
|
|
36
|
-
target_include_directories(starpc PUBLIC
|
|
37
|
-
${CMAKE_CURRENT_SOURCE_DIR}/..
|
|
38
|
-
${CMAKE_CURRENT_SOURCE_DIR}
|
|
39
|
-
)
|
|
40
|
-
|
|
41
|
-
target_compile_features(starpc PUBLIC cxx_std_17)
|
|
42
|
-
|
|
43
|
-
# Link protobuf
|
|
44
|
-
find_package(Protobuf REQUIRED)
|
|
45
|
-
target_link_libraries(starpc PUBLIC protobuf::libprotobuf)
|
|
46
|
-
|
|
47
|
-
# Link threads
|
|
48
|
-
find_package(Threads REQUIRED)
|
|
49
|
-
target_link_libraries(starpc PUBLIC Threads::Threads)
|
|
50
|
-
|
|
51
|
-
# Install targets
|
|
52
|
-
install(TARGETS starpc
|
|
53
|
-
ARCHIVE DESTINATION lib
|
|
54
|
-
LIBRARY DESTINATION lib
|
|
55
|
-
)
|
|
56
|
-
|
|
57
|
-
install(FILES ${STARPC_HEADERS}
|
|
58
|
-
DESTINATION include/srpc
|
|
59
|
-
)
|
|
3
|
+
# Keep the historical subdirectory entry point on the same complete target.
|
|
4
|
+
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR}/starpc)
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Starpc C++
|
|
2
|
+
|
|
3
|
+
Starpc provides generated C++ clients and handlers for unary and streaming
|
|
4
|
+
protobuf RPCs. It uses the same packets as the Go, TypeScript, Rust, and Python
|
|
5
|
+
implementations. C++20 and the protobuf runtime matching the generated headers
|
|
6
|
+
are required.
|
|
7
|
+
|
|
8
|
+
## Build
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
go mod vendor
|
|
12
|
+
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
|
|
13
|
+
cmake --build build --parallel
|
|
14
|
+
ctest --test-dir build --output-on-failure --timeout 60
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
A parent project can use `add_subdirectory(path/to/starpc)` and link
|
|
18
|
+
`starpc::starpc`. An existing `protobuf::libprotobuf` target is reused, including
|
|
19
|
+
its include paths and compile definitions. Otherwise, set
|
|
20
|
+
`STARPC_USE_SYSTEM_PROTOBUF=ON` to find an installed protobuf package, or vendor
|
|
21
|
+
Go dependencies before configuring. Tests and examples default to off when
|
|
22
|
+
Starpc is a subdirectory. The library includes the nested RPC messages even
|
|
23
|
+
when examples are disabled.
|
|
24
|
+
|
|
25
|
+
Generate service bindings with `protoc-gen-starpc-cpp`. The generated streaming
|
|
26
|
+
wrappers expose `Send`, `Recv`, `Close`, `CloseSend`, and `StopToken` as applicable.
|
|
27
|
+
See `echo/echo.proto` and its generated bindings for each RPC shape.
|
|
28
|
+
|
|
29
|
+
## Connect a transport
|
|
30
|
+
|
|
31
|
+
One Starpc call uses one ordered, bidirectional packet stream. A streaming RPC
|
|
32
|
+
can carry successive commands and events over a single process connection.
|
|
33
|
+
Independent concurrent calls require separate streams from the transport.
|
|
34
|
+
|
|
35
|
+
A C++ server lends an `Invoker` and `PacketWriter` to `ServerRPC`, then feeds
|
|
36
|
+
received packets to `HandlePacketData`. Call `HandleStreamClose` when input ends,
|
|
37
|
+
including errors. Serialize those input callbacks. Destruction cancels the call
|
|
38
|
+
and joins its handler before the borrowed objects can be released.
|
|
39
|
+
|
|
40
|
+
For a client, supply an `OpenStreamFunc` to `NewClient`. Its returned writer must
|
|
41
|
+
keep receive callbacks alive until destruction. `Close` must interrupt blocked
|
|
42
|
+
transport reads and writes without waiting for those callbacks; destruction must
|
|
43
|
+
join any receive thread. This permits a callback to close its own transport.
|
|
44
|
+
|
|
45
|
+
Packet writers serialize their writes and allow `Close` concurrently with a
|
|
46
|
+
write. Close is idempotent. A byte-stream transport uses a four-byte unsigned
|
|
47
|
+
little-endian length followed by the serialized `srpc.Packet`, matching Go's
|
|
48
|
+
`PacketReadWriter`. Reject empty frames and frames larger than 10,000,000 bytes
|
|
49
|
+
before allocating their bodies. The process-pipe integration test demonstrates
|
|
50
|
+
this framing with a Go client and a C++ child process.
|
|
51
|
+
|
|
52
|
+
## Cancellation and completion
|
|
53
|
+
|
|
54
|
+
`CloseSend` ends outgoing messages while allowing incoming replies. Once the
|
|
55
|
+
request is written, the half-close is only a notice: it fails when the call
|
|
56
|
+
already ended, so generated callers ignore its error and read the outcome with
|
|
57
|
+
`MsgRecv`. Explicit remote completion becomes EOF after queued messages are
|
|
58
|
+
read. A disconnected
|
|
59
|
+
transport without completion returns `ClosedBeforeCompletion`. Remote errors
|
|
60
|
+
return `RemoteError`; `CommonRPC::RemoteErrorMessage` retains the peer's text.
|
|
61
|
+
|
|
62
|
+
Handlers performing work outside `Recv` must observe their stream's `StopToken`.
|
|
63
|
+
Destroying a server waits for its handler to return; it cannot forcibly terminate
|
|
64
|
+
application code that ignores cancellation. Dropping a client stream closes its
|
|
65
|
+
transport and releases its receive thread. Nested RPCs release their service
|
|
66
|
+
only after the nested handler returns.
|
|
67
|
+
|
|
68
|
+
An unread C++ call is limited to 4 MiB or 1,024 queued messages, including empty
|
|
69
|
+
messages. Exceeding either bound ends the call with `ResourceExhausted`.
|