starpc 0.43.1 → 0.45.0

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/srpc/mux.hpp ADDED
@@ -0,0 +1,64 @@
1
+ #pragma once
2
+
3
+ #include <shared_mutex>
4
+ #include <string>
5
+ #include <unordered_map>
6
+ #include <vector>
7
+
8
+ #include "errors.hpp"
9
+ #include "handler.hpp"
10
+ #include "invoker.hpp"
11
+
12
+ namespace starpc {
13
+
14
+ // Mux contains a set of <service, method> handlers.
15
+ // Matches Go Mux interface in mux.go
16
+ class Mux : public Invoker, public QueryableInvoker {
17
+ public:
18
+ // Constructor matching NewMux in Go
19
+ explicit Mux(std::vector<Invoker *> fallback_invokers = {});
20
+ ~Mux() override = default;
21
+
22
+ // Register registers a new RPC method handler (service).
23
+ // Matches Go Register in mux.go
24
+ Error Register(Handler *handler);
25
+
26
+ // InvokeMethod invokes the method matching the service & method ID.
27
+ // Returns {found, error} - found is false if method not found.
28
+ // If service string is empty, ignore it.
29
+ // Matches Go InvokeMethod in mux.go
30
+ std::pair<bool, Error> InvokeMethod(const std::string &service_id,
31
+ const std::string &method_id,
32
+ Stream *strm) override;
33
+
34
+ // HasService checks if the service ID exists in the handlers.
35
+ // Matches Go HasService in mux.go
36
+ bool HasService(const std::string &service_id) const override;
37
+
38
+ // HasServiceMethod checks if <service-id, method-id> exists in the handlers.
39
+ // Matches Go HasServiceMethod in mux.go
40
+ bool HasServiceMethod(const std::string &service_id,
41
+ const std::string &method_id) const override;
42
+
43
+ private:
44
+ // Mapping from method id to handler
45
+ using MuxMethods = std::unordered_map<std::string, Handler *>;
46
+
47
+ // Fallback invokers
48
+ std::vector<Invoker *> fallback_;
49
+
50
+ // Read-write mutex guards services_
51
+ mutable std::shared_mutex mtx_;
52
+
53
+ // Services contains a mapping from services to handlers
54
+ std::unordered_map<std::string, MuxMethods> services_;
55
+ };
56
+
57
+ // NewMux constructs a new Mux.
58
+ // Matches Go NewMux function in mux.go
59
+ inline std::unique_ptr<Mux>
60
+ NewMux(std::vector<Invoker *> fallback_invokers = {}) {
61
+ return std::make_unique<Mux>(std::move(fallback_invokers));
62
+ }
63
+
64
+ } // namespace starpc
@@ -0,0 +1,83 @@
1
+ // go:build deps_only
2
+
3
+ #include "packet.hpp"
4
+
5
+ #include "rpcproto.pb.h"
6
+
7
+ namespace starpc {
8
+
9
+ PacketDataHandler NewPacketDataHandler(PacketHandler handler) {
10
+ return [handler](const std::string &data) -> Error {
11
+ srpc::Packet pkt;
12
+ if (!pkt.ParseFromString(data)) {
13
+ return Error::InvalidMessage;
14
+ }
15
+ return handler(pkt);
16
+ };
17
+ }
18
+
19
+ Error ValidatePacket(const srpc::Packet &pkt) {
20
+ switch (pkt.body_case()) {
21
+ case srpc::Packet::kCallStart:
22
+ return ValidateCallStart(pkt.call_start());
23
+ case srpc::Packet::kCallData:
24
+ return ValidateCallData(pkt.call_data());
25
+ case srpc::Packet::kCallCancel:
26
+ return Error::OK;
27
+ default:
28
+ return Error::UnrecognizedPacket;
29
+ }
30
+ }
31
+
32
+ Error ValidateCallStart(const srpc::CallStart &pkt) {
33
+ if (pkt.rpc_method().empty()) {
34
+ return Error::EmptyMethodID;
35
+ }
36
+ if (pkt.rpc_service().empty()) {
37
+ return Error::EmptyServiceID;
38
+ }
39
+ return Error::OK;
40
+ }
41
+
42
+ Error ValidateCallData(const srpc::CallData &pkt) {
43
+ if (pkt.data().empty() && !pkt.complete() && pkt.error().empty() &&
44
+ !pkt.data_is_zero()) {
45
+ return Error::EmptyPacket;
46
+ }
47
+ return Error::OK;
48
+ }
49
+
50
+ std::unique_ptr<srpc::Packet> NewCallStartPacket(const std::string &service,
51
+ const std::string &method,
52
+ const std::string &data,
53
+ bool data_is_zero) {
54
+ auto pkt = std::make_unique<srpc::Packet>();
55
+ auto *call_start = pkt->mutable_call_start();
56
+ call_start->set_rpc_service(service);
57
+ call_start->set_rpc_method(method);
58
+ call_start->set_data(data);
59
+ call_start->set_data_is_zero(data_is_zero);
60
+ return pkt;
61
+ }
62
+
63
+ std::unique_ptr<srpc::Packet> NewCallDataPacket(const std::string &data,
64
+ bool data_is_zero,
65
+ bool complete, Error err) {
66
+ auto pkt = std::make_unique<srpc::Packet>();
67
+ auto *call_data = pkt->mutable_call_data();
68
+ call_data->set_data(data);
69
+ call_data->set_data_is_zero(data_is_zero);
70
+ call_data->set_complete(err != Error::OK || complete);
71
+ if (err != Error::OK) {
72
+ call_data->set_error(ErrorString(err));
73
+ }
74
+ return pkt;
75
+ }
76
+
77
+ std::unique_ptr<srpc::Packet> NewCallCancelPacket() {
78
+ auto pkt = std::make_unique<srpc::Packet>();
79
+ pkt->set_call_cancel(true);
80
+ return pkt;
81
+ }
82
+
83
+ } // namespace starpc
@@ -0,0 +1,56 @@
1
+ #pragma once
2
+
3
+ #include <cstdint>
4
+ #include <functional>
5
+ #include <memory>
6
+ #include <string>
7
+
8
+ #include "errors.hpp"
9
+
10
+ namespace srpc {
11
+ class Packet;
12
+ class CallStart;
13
+ class CallData;
14
+ } // namespace srpc
15
+
16
+ namespace starpc {
17
+
18
+ // CloseHandler handles the stream closing with an optional error.
19
+ // Matches Go CloseHandler in packet.go
20
+ using CloseHandler = std::function<void(Error close_err)>;
21
+
22
+ // PacketHandler handles a packet.
23
+ // Matches Go PacketHandler in packet.go
24
+ using PacketHandler = std::function<Error(const srpc::Packet &pkt)>;
25
+
26
+ // PacketDataHandler handles a packet before it is parsed.
27
+ // Matches Go PacketDataHandler in packet.go
28
+ using PacketDataHandler = std::function<Error(const std::string &data)>;
29
+
30
+ // NewPacketDataHandler wraps a PacketHandler with a decoding step.
31
+ PacketDataHandler NewPacketDataHandler(PacketHandler handler);
32
+
33
+ // Validate performs cursory validation of a Packet.
34
+ Error ValidatePacket(const srpc::Packet &pkt);
35
+
36
+ // Validate performs cursory validation of a CallStart.
37
+ Error ValidateCallStart(const srpc::CallStart &pkt);
38
+
39
+ // Validate performs cursory validation of a CallData.
40
+ Error ValidateCallData(const srpc::CallData &pkt);
41
+
42
+ // NewCallStartPacket constructs a new CallStart packet.
43
+ std::unique_ptr<srpc::Packet> NewCallStartPacket(const std::string &service,
44
+ const std::string &method,
45
+ const std::string &data,
46
+ bool data_is_zero);
47
+
48
+ // NewCallDataPacket constructs a new CallData packet.
49
+ std::unique_ptr<srpc::Packet> NewCallDataPacket(const std::string &data,
50
+ bool data_is_zero,
51
+ bool complete, Error err);
52
+
53
+ // NewCallCancelPacket constructs a new CallCancel packet with cancel.
54
+ std::unique_ptr<srpc::Packet> NewCallCancelPacket();
55
+
56
+ } // namespace starpc
@@ -1,4 +1,4 @@
1
- // @generated by protoc-gen-es-lite unknown with parameter "target=ts,ts_nocheck=false"
1
+ // @generated by protoc-gen-es-lite unknown with parameter "ts_nocheck=false,target=ts"
2
2
  // @generated from file github.com/aperturerobotics/starpc/srpc/rpcproto.proto (package srpc, syntax proto3)
3
3
  /* eslint-disable */
4
4
 
@@ -0,0 +1,97 @@
1
+ // go:build deps_only
2
+
3
+ #include "server-rpc.hpp"
4
+
5
+ #include "packet.hpp"
6
+ #include "rpcproto.pb.h"
7
+
8
+ namespace starpc {
9
+
10
+ ServerRPC::ServerRPC(Invoker *invoker, PacketWriter *writer)
11
+ : invoker_(invoker) {
12
+ Init();
13
+ writer_ = writer;
14
+ }
15
+
16
+ ServerRPC::~ServerRPC() {
17
+ if (invoke_thread_.joinable()) {
18
+ invoke_thread_.join();
19
+ }
20
+ }
21
+
22
+ Error ServerRPC::HandlePacketData(const std::string &data) {
23
+ srpc::Packet msg;
24
+ if (!msg.ParseFromString(data)) {
25
+ return Error::InvalidMessage;
26
+ }
27
+ return HandlePacket(msg);
28
+ }
29
+
30
+ Error ServerRPC::HandlePacket(const srpc::Packet &msg) {
31
+ Error err = ValidatePacket(msg);
32
+ if (err != Error::OK) {
33
+ return err;
34
+ }
35
+
36
+ switch (msg.body_case()) {
37
+ case srpc::Packet::kCallStart:
38
+ return HandleCallStart(msg.call_start());
39
+ case srpc::Packet::kCallData:
40
+ return HandleCallData(msg.call_data());
41
+ case srpc::Packet::kCallCancel:
42
+ if (msg.call_cancel()) {
43
+ return HandleCallCancel();
44
+ }
45
+ return Error::OK;
46
+ default:
47
+ return Error::OK;
48
+ }
49
+ }
50
+
51
+ Error ServerRPC::HandleCallStart(const srpc::CallStart &pkt) {
52
+ std::lock_guard<std::mutex> lock(mtx_);
53
+
54
+ // process start: method and service
55
+ if (!method_.empty() || !service_.empty()) {
56
+ return Error::Completed; // call start must be sent only once
57
+ }
58
+ if (data_closed_) {
59
+ return Error::Completed;
60
+ }
61
+
62
+ service_ = pkt.rpc_service();
63
+ method_ = pkt.rpc_method();
64
+
65
+ // process first data packet, if included
66
+ if (!pkt.data().empty() || pkt.data_is_zero()) {
67
+ data_queue_.push_back(pkt.data());
68
+ }
69
+
70
+ // invoke the rpc in a separate thread (matches Go goroutine)
71
+ std::string service_id = service_;
72
+ std::string method_id = method_;
73
+ cv_.notify_all();
74
+
75
+ invoke_thread_ = std::thread(
76
+ [this, service_id, method_id]() { InvokeRPC(service_id, method_id); });
77
+
78
+ return Error::OK;
79
+ }
80
+
81
+ void ServerRPC::InvokeRPC(const std::string &service_id,
82
+ const std::string &method_id) {
83
+ // On the server side, the writer is closed by invokeRPC.
84
+ auto strm = NewMsgStream(this, [this]() { Cancel(); });
85
+
86
+ auto [ok, err] = invoker_->InvokeMethod(service_id, method_id, strm.get());
87
+ if (err == Error::OK && !ok) {
88
+ err = Error::Unimplemented;
89
+ }
90
+
91
+ auto out_pkt = NewCallDataPacket("", false, true, err);
92
+ writer_->WritePacket(*out_pkt);
93
+ writer_->Close();
94
+ Cancel();
95
+ }
96
+
97
+ } // namespace starpc
@@ -0,0 +1,63 @@
1
+ #pragma once
2
+
3
+ #include <string>
4
+ #include <thread>
5
+
6
+ #include "common-rpc.hpp"
7
+ #include "errors.hpp"
8
+ #include "invoker.hpp"
9
+ #include "msg-stream.hpp"
10
+ #include "writer.hpp"
11
+
12
+ namespace srpc {
13
+ class Packet;
14
+ class CallStart;
15
+ } // namespace srpc
16
+
17
+ namespace starpc {
18
+
19
+ // ServerRPC represents the server side of an on-going RPC call message stream.
20
+ // Matches Go ServerRPC struct in server-rpc.go
21
+ class ServerRPC : public CommonRPC, public MsgStreamRw {
22
+ public:
23
+ // Constructor matching NewServerRPC in Go
24
+ ServerRPC(Invoker *invoker, PacketWriter *writer);
25
+ ~ServerRPC() override;
26
+
27
+ // HandlePacketData handles an incoming unparsed message packet.
28
+ // Matches Go HandlePacketData in server-rpc.go
29
+ Error HandlePacketData(const std::string &data);
30
+
31
+ // HandlePacket handles an incoming parsed message packet.
32
+ // Matches Go HandlePacket in server-rpc.go
33
+ Error HandlePacket(const srpc::Packet &msg);
34
+
35
+ // HandleCallStart handles the call start packet.
36
+ // Matches Go HandleCallStart in server-rpc.go
37
+ Error HandleCallStart(const srpc::CallStart &pkt);
38
+
39
+ // MsgStreamRw interface implementation
40
+ Error ReadOne(std::string *out) override { return CommonRPC::ReadOne(out); }
41
+ Error WriteCallData(const std::string &data, bool data_is_zero, bool complete,
42
+ Error err) override {
43
+ return CommonRPC::WriteCallData(data, data_is_zero, complete, err);
44
+ }
45
+ Error WriteCallCancel() override { return CommonRPC::WriteCallCancel(); }
46
+
47
+ private:
48
+ // InvokeRPC invokes the RPC after CallStart is received.
49
+ // Matches Go invokeRPC in server-rpc.go
50
+ void InvokeRPC(const std::string &service_id, const std::string &method_id);
51
+
52
+ Invoker *invoker_;
53
+ std::thread invoke_thread_;
54
+ };
55
+
56
+ // NewServerRPC constructs a new ServerRPC session.
57
+ // Matches Go NewServerRPC function in server-rpc.go
58
+ inline std::unique_ptr<ServerRPC> NewServerRPC(Invoker *invoker,
59
+ PacketWriter *writer) {
60
+ return std::make_unique<ServerRPC>(invoker, writer);
61
+ }
62
+
63
+ } // namespace starpc
@@ -0,0 +1,18 @@
1
+ #pragma once
2
+
3
+ // Main header for starpc C++ library
4
+ // Include this to get all starpc functionality
5
+
6
+ #include "client-rpc.hpp"
7
+ #include "client.hpp"
8
+ #include "common-rpc.hpp"
9
+ #include "errors.hpp"
10
+ #include "handler.hpp"
11
+ #include "invoker.hpp"
12
+ #include "message.hpp"
13
+ #include "msg-stream.hpp"
14
+ #include "mux.hpp"
15
+ #include "packet.hpp"
16
+ #include "server-rpc.hpp"
17
+ #include "stream.hpp"
18
+ #include "writer.hpp"
@@ -0,0 +1,61 @@
1
+ #pragma once
2
+
3
+ #include <functional>
4
+ #include <memory>
5
+
6
+ #include "errors.hpp"
7
+ #include "message.hpp"
8
+
9
+ namespace starpc {
10
+
11
+ // Stream is a handle to an on-going bi-directional or one-directional stream
12
+ // RPC handle. Matches Go Stream interface in stream.go
13
+ class Stream {
14
+ public:
15
+ virtual ~Stream() = default;
16
+
17
+ // MsgSend sends the message to the remote.
18
+ virtual Error MsgSend(const Message &msg) = 0;
19
+
20
+ // MsgRecv receives an incoming message from the remote.
21
+ // Parses the message into the object at msg.
22
+ virtual Error MsgRecv(Message *msg) = 0;
23
+
24
+ // CloseSend signals to the remote that we will no longer send any messages.
25
+ virtual Error CloseSend() = 0;
26
+
27
+ // Close closes the stream for reading and writing.
28
+ virtual Error Close() = 0;
29
+ };
30
+
31
+ // StreamWithClose wraps a Stream with a close function to call when Close is
32
+ // called. Matches streamWithClose in stream.go
33
+ class StreamWithClose : public Stream {
34
+ public:
35
+ StreamWithClose(Stream *inner, std::function<Error()> close_fn)
36
+ : inner_(inner), close_fn_(std::move(close_fn)) {}
37
+
38
+ Error MsgSend(const Message &msg) override { return inner_->MsgSend(msg); }
39
+ Error MsgRecv(Message *msg) override { return inner_->MsgRecv(msg); }
40
+ Error CloseSend() override { return inner_->CloseSend(); }
41
+
42
+ Error Close() override {
43
+ Error err = inner_->Close();
44
+ Error err2 = close_fn_();
45
+ if (err != Error::OK)
46
+ return err;
47
+ return err2;
48
+ }
49
+
50
+ private:
51
+ Stream *inner_;
52
+ std::function<Error()> close_fn_;
53
+ };
54
+
55
+ // NewStreamWithClose wraps a Stream with a close function.
56
+ inline std::unique_ptr<Stream>
57
+ NewStreamWithClose(Stream *strm, std::function<Error()> close_fn) {
58
+ return std::make_unique<StreamWithClose>(strm, std::move(close_fn));
59
+ }
60
+
61
+ } // namespace starpc
@@ -0,0 +1,60 @@
1
+ #pragma once
2
+
3
+ #include <functional>
4
+ #include <memory>
5
+
6
+ #include "errors.hpp"
7
+
8
+ namespace srpc {
9
+ class Packet;
10
+ }
11
+
12
+ namespace starpc {
13
+
14
+ // PacketWriter is the interface used to write messages to a PacketStream.
15
+ // Matches Go interface in writer.go
16
+ class PacketWriter {
17
+ public:
18
+ virtual ~PacketWriter() = default;
19
+
20
+ // WritePacket writes a packet to the remote.
21
+ virtual Error WritePacket(const srpc::Packet &pkt) = 0;
22
+
23
+ // Close closes the writer.
24
+ virtual Error Close() = 0;
25
+ };
26
+
27
+ // PacketWriterWithClose wraps a PacketWriter with an additional close function.
28
+ // Matches packetWriterWithClose in writer.go
29
+ class PacketWriterWithClose : public PacketWriter {
30
+ public:
31
+ PacketWriterWithClose(std::unique_ptr<PacketWriter> inner,
32
+ std::function<Error()> close_fn)
33
+ : inner_(std::move(inner)), close_fn_(std::move(close_fn)) {}
34
+
35
+ Error WritePacket(const srpc::Packet &pkt) override {
36
+ return inner_->WritePacket(pkt);
37
+ }
38
+
39
+ Error Close() override {
40
+ Error err = inner_->Close();
41
+ Error err2 = close_fn_();
42
+ if (err != Error::OK)
43
+ return err;
44
+ return err2;
45
+ }
46
+
47
+ private:
48
+ std::unique_ptr<PacketWriter> inner_;
49
+ std::function<Error()> close_fn_;
50
+ };
51
+
52
+ // NewPacketWriterWithClose wraps a PacketWriter with a close function.
53
+ inline std::unique_ptr<PacketWriter>
54
+ NewPacketWriterWithClose(std::unique_ptr<PacketWriter> prw,
55
+ std::function<Error()> close_fn) {
56
+ return std::make_unique<PacketWriterWithClose>(std::move(prw),
57
+ std::move(close_fn));
58
+ }
59
+
60
+ } // namespace starpc