blob: e0f8e6788f007ffd61469e611586611c124a473a [file] [log] [blame]
Wyatt Hepler22530402021-07-30 23:40:40 -07001// Copyright 2021 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14
15// Simple RPC server with the transfer service registered. Reads HDLC frames
Alexei Frolovfad8e852021-08-16 13:58:51 -070016// with RPC packets through a socket. The transfer service reads and writes to
17// files within a given directory. The name of a file is its transfer ID.
Wyatt Hepler22530402021-07-30 23:40:40 -070018
19#include <cstddef>
Alexei Frolovfad8e852021-08-16 13:58:51 -070020#include <filesystem>
21#include <string>
Wyatt Hepler22530402021-07-30 23:40:40 -070022#include <thread>
23#include <variant>
Alexei Frolovfad8e852021-08-16 13:58:51 -070024#include <vector>
Wyatt Hepler22530402021-07-30 23:40:40 -070025
26#include "pw_assert/check.h"
27#include "pw_log/log.h"
28#include "pw_rpc_system_server/rpc_server.h"
29#include "pw_rpc_system_server/socket.h"
Alexei Frolovfad8e852021-08-16 13:58:51 -070030#include "pw_stream/std_file_stream.h"
Alexei Frolov4fd8c802021-11-09 09:49:25 -080031#include "pw_thread/detached_thread.h"
32#include "pw_thread_stl/options.h"
Wyatt Hepler22530402021-07-30 23:40:40 -070033#include "pw_transfer/transfer.h"
Alexei Frolovfad8e852021-08-16 13:58:51 -070034#include "pw_transfer_test/test_server.raw_rpc.pb.h"
Wyatt Hepler22530402021-07-30 23:40:40 -070035
36namespace pw::transfer {
37namespace {
38
Alexei Frolovfad8e852021-08-16 13:58:51 -070039class FileTransferHandler final : public ReadWriteHandler {
Wyatt Hepler22530402021-07-30 23:40:40 -070040 public:
Alexei Frolovfad8e852021-08-16 13:58:51 -070041 FileTransferHandler(TransferService& service,
42 uint32_t transfer_id,
43 const char* path)
44 : ReadWriteHandler(transfer_id), service_(service), path_(path) {
45 service_.RegisterHandler(*this);
46 }
Wyatt Hepler22530402021-07-30 23:40:40 -070047
Alexei Frolovfad8e852021-08-16 13:58:51 -070048 ~FileTransferHandler() { service_.UnregisterHandler(*this); }
49
50 Status PrepareRead() final {
51 PW_LOG_DEBUG("Preparing read for file %s", path_.c_str());
52 set_reader(stream_.emplace<stream::StdFileReader>(path_.c_str()));
Wyatt Hepler22530402021-07-30 23:40:40 -070053 return OkStatus();
54 }
55
Alexei Frolovfad8e852021-08-16 13:58:51 -070056 void FinalizeRead(Status) final {
57 std::get<stream::StdFileReader>(stream_).Close();
58 }
59
60 Status PrepareWrite() final {
61 PW_LOG_DEBUG("Preparing write for file %s", path_.c_str());
62 set_writer(stream_.emplace<stream::StdFileWriter>(path_.c_str()));
Wyatt Hepler22530402021-07-30 23:40:40 -070063 return OkStatus();
64 }
65
Alexei Frolovfad8e852021-08-16 13:58:51 -070066 Status FinalizeWrite(Status) final {
67 std::get<stream::StdFileWriter>(stream_).Close();
Wyatt Hepler22530402021-07-30 23:40:40 -070068 return OkStatus();
69 }
70
Wyatt Hepler22530402021-07-30 23:40:40 -070071 private:
Alexei Frolovfad8e852021-08-16 13:58:51 -070072 TransferService& service_;
73 std::string path_;
74 std::variant<std::monostate, stream::StdFileReader, stream::StdFileWriter>
Wyatt Hepler22530402021-07-30 23:40:40 -070075 stream_;
Alexei Frolovfad8e852021-08-16 13:58:51 -070076};
77
Alexei Frolov39d8c5c2021-11-24 10:16:31 -080078class TestServerService
79 : public pw_rpc::raw::TestServer::Service<TestServerService> {
Alexei Frolovfad8e852021-08-16 13:58:51 -070080 public:
81 TestServerService(TransferService& transfer_service)
82 : transfer_service_(transfer_service) {}
83
84 void set_directory(const char* directory) { directory_ = directory; }
85
Wyatt Heplerb15c55b2022-02-11 09:26:05 -080086 void ReloadTransferFiles(ConstByteSpan, rpc::RawUnaryResponder&) {
Alexei Frolovfad8e852021-08-16 13:58:51 -070087 LoadFileHandlers();
Alexei Frolovfad8e852021-08-16 13:58:51 -070088 }
89
90 void LoadFileHandlers() {
91 PW_LOG_INFO("Reloading file handlers from %s", directory_.c_str());
92 file_transfer_handlers_.clear();
93
94 for (const auto& entry : std::filesystem::directory_iterator(directory_)) {
95 if (!entry.is_regular_file()) {
96 continue;
97 }
98
99 int transfer_id = std::atoi(entry.path().filename().c_str());
100 if (transfer_id > 0) {
101 PW_LOG_DEBUG("Found transfer file %d", transfer_id);
102 file_transfer_handlers_.emplace_back(
103 std::make_shared<FileTransferHandler>(
104 transfer_service_, transfer_id, entry.path().c_str()));
105 }
106 }
107 }
108
109 private:
110 TransferService& transfer_service_;
111 std::string directory_;
112 std::vector<std::shared_ptr<FileTransferHandler>> file_transfer_handlers_;
Wyatt Hepler22530402021-07-30 23:40:40 -0700113};
114
Alexei Frolov563946f2021-08-05 18:58:48 -0700115constexpr size_t kChunkSizeBytes = 256;
116constexpr size_t kMaxReceiveSizeBytes = 1024;
117
Alexei Frolov22ee1142022-02-03 13:59:01 -0800118std::array<std::byte, kChunkSizeBytes> chunk_buffer;
119std::array<std::byte, kChunkSizeBytes> encode_buffer;
120transfer::Thread<4, 4> transfer_thread(chunk_buffer, encode_buffer);
121TransferService transfer_service(transfer_thread, kMaxReceiveSizeBytes);
Alexei Frolovfad8e852021-08-16 13:58:51 -0700122TestServerService test_server_service(transfer_service);
Wyatt Hepler22530402021-07-30 23:40:40 -0700123
Alexei Frolovfad8e852021-08-16 13:58:51 -0700124void RunServer(int socket_port, const char* directory) {
Wyatt Hepler82d499b2021-08-23 09:13:16 -0700125 rpc::system_server::set_socket_port(socket_port);
Wyatt Hepler22530402021-07-30 23:40:40 -0700126
Alexei Frolovfad8e852021-08-16 13:58:51 -0700127 test_server_service.set_directory(directory);
128 test_server_service.LoadFileHandlers();
Wyatt Hepler22530402021-07-30 23:40:40 -0700129
130 rpc::system_server::Init();
Wyatt Hepler7566bc82022-02-15 15:09:00 -0800131 rpc::system_server::Server().RegisterService(test_server_service,
132 transfer_service);
Wyatt Hepler22530402021-07-30 23:40:40 -0700133
Alexei Frolov22ee1142022-02-03 13:59:01 -0800134 thread::DetachedThread(thread::stl::Options(), transfer_thread);
Alexei Frolov4fd8c802021-11-09 09:49:25 -0800135
Wyatt Hepler22530402021-07-30 23:40:40 -0700136 PW_LOG_INFO("Starting pw_rpc server");
Wyatt Hepler82d499b2021-08-23 09:13:16 -0700137 PW_CHECK_OK(rpc::system_server::Start());
Wyatt Hepler22530402021-07-30 23:40:40 -0700138}
139
140} // namespace
141} // namespace pw::transfer
142
Wyatt Hepler82d499b2021-08-23 09:13:16 -0700143int main(int argc, char* argv[]) {
Alexei Frolovfad8e852021-08-16 13:58:51 -0700144 if (argc != 3) {
145 PW_LOG_ERROR("Usage: %s PORT DIR", argv[0]);
Wyatt Hepler82d499b2021-08-23 09:13:16 -0700146 return 1;
147 }
Alexei Frolovfad8e852021-08-16 13:58:51 -0700148
149 pw::transfer::RunServer(std::atoi(argv[1]), argv[2]);
Wyatt Hepler22530402021-07-30 23:40:40 -0700150 return 0;
151}