pw_rpc: Update protocol for server streams
Update the server-to-client RPC packet types so that the packet type
unambiguously indicates whether it is the first or last packet. This is
already the case for client-to-server RPC packet types.
- Have RESPONSE always be the last packet in the stream. For RPCs
without a server stream, it includes a payload. Remove
SERVER_STREAM_END.
- Introduce the SERVER_STREAM packet, to parallel the CLIENT_STREAM
packet.
- Update the server and client code and tests. Test that old-style
streaming RPCs still work correctly.
- Refactor the duplicate MessageOutput class into a FakeChannelOutput
used by both Nanopb and raw RPCs.
- In C++, don't encode default-valued payload and status fields.
Change-Id: I218772dad6c2981dda5f032f298ea43ee5e08b4d
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/49822
Commit-Queue: Wyatt Hepler <hepler@google.com>
Pigweed-Auto-Submit: Wyatt Hepler <hepler@google.com>
Reviewed-by: Alexei Frolov <frolv@google.com>
diff --git a/pw_rpc/fake_channel_output.cc b/pw_rpc/fake_channel_output.cc
new file mode 100644
index 0000000..e68a879
--- /dev/null
+++ b/pw_rpc/fake_channel_output.cc
@@ -0,0 +1,62 @@
+// Copyright 2021 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#include "pw_rpc_private/fake_channel_output.h"
+
+#include "pw_assert/check.h"
+#include "pw_result/result.h"
+#include "pw_rpc/internal/packet.h"
+
+namespace pw::rpc::internal::test {
+
+void FakeChannelOutput::clear() {
+ ClearResponses();
+ total_responses_ = 0;
+ last_status_ = Status::Unknown();
+ done_ = false;
+}
+
+Status FakeChannelOutput::SendAndReleaseBuffer(
+ std::span<const std::byte> buffer) {
+ PW_CHECK(!done_);
+ PW_CHECK_PTR_EQ(buffer.data(), packet_buffer_.data());
+
+ if (buffer.empty()) {
+ return OkStatus();
+ }
+
+ Result<Packet> result = Packet::FromBuffer(buffer);
+ PW_CHECK_OK(result.status());
+
+ last_status_ = result.value().status();
+
+ switch (result.value().type()) {
+ case PacketType::RESPONSE:
+ // Server streaming RPCs don't have a payload in their response packet.
+ if (!server_streaming_) {
+ ProcessResponse(result.value().payload());
+ }
+ done_ = true;
+ break;
+ case PacketType::SERVER_STREAM:
+ ProcessResponse(result.value().payload());
+ break;
+ default:
+ PW_CRASH("Unhandled PacketType %d",
+ static_cast<int>(result.value().type()));
+ }
+ return OkStatus();
+}
+
+} // namespace pw::rpc::internal::test