• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 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
16 // 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 resource ID.
18 
19 #include <cstddef>
20 #include <filesystem>
21 #include <string>
22 #include <thread>
23 #include <variant>
24 #include <vector>
25 
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"
30 #include "pw_stream/std_file_stream.h"
31 #include "pw_thread/detached_thread.h"
32 #include "pw_thread_stl/options.h"
33 #include "pw_transfer/atomic_file_transfer_handler.h"
34 #include "pw_transfer/transfer.h"
35 #include "pw_transfer_test/test_server.raw_rpc.pb.h"
36 
37 namespace pw::transfer {
38 namespace {
39 class TestServerService
40     : public pw_rpc::raw::TestServer::Service<TestServerService> {
41  public:
TestServerService(TransferService & transfer_service)42   TestServerService(TransferService& transfer_service)
43       : transfer_service_(transfer_service) {}
44 
~TestServerService()45   ~TestServerService() { UnregisterHandlers(); }
46 
UnregisterHandlers()47   void UnregisterHandlers() {
48     for (auto handler : file_transfer_handlers_) {
49       transfer_service_.UnregisterHandler(*handler);
50     }
51   }
52 
set_directory(const char * directory)53   void set_directory(const char* directory) { directory_ = directory; }
54 
ReloadTransferFiles(ConstByteSpan,rpc::RawUnaryResponder &)55   void ReloadTransferFiles(ConstByteSpan, rpc::RawUnaryResponder&) {
56     LoadFileHandlers();
57   }
58 
LoadFileHandlers()59   void LoadFileHandlers() {
60     PW_LOG_INFO("Reloading file handlers from %s", directory_.c_str());
61     UnregisterHandlers();
62     file_transfer_handlers_.clear();
63 
64     for (const auto& entry : std::filesystem::directory_iterator(directory_)) {
65       if (!entry.is_regular_file()) {
66         continue;
67       }
68 
69       int resource_id = std::atoi(entry.path().filename().c_str());
70       if (resource_id > 0) {
71         PW_LOG_DEBUG("Found transfer file %d", resource_id);
72         auto handler = std::make_shared<AtomicFileTransferHandler>(
73             resource_id, entry.path().c_str());
74         transfer_service_.RegisterHandler(*handler);
75         file_transfer_handlers_.emplace_back(handler);
76       }
77     }
78   }
79 
80  private:
81   TransferService& transfer_service_;
82   std::string directory_;
83   std::vector<std::shared_ptr<AtomicFileTransferHandler>>
84       file_transfer_handlers_;
85 };
86 
87 constexpr size_t kChunkSizeBytes = 256;
88 constexpr size_t kMaxReceiveSizeBytes = 1024;
89 
90 std::array<std::byte, kChunkSizeBytes> chunk_buffer;
91 std::array<std::byte, kChunkSizeBytes> encode_buffer;
92 transfer::Thread<4, 4> transfer_thread(chunk_buffer, encode_buffer);
93 TransferService transfer_service(transfer_thread, kMaxReceiveSizeBytes);
94 TestServerService test_server_service(transfer_service);
95 
RunServer(int socket_port,const char * directory)96 void RunServer(int socket_port, const char* directory) {
97   rpc::system_server::set_socket_port(socket_port);
98 
99   test_server_service.set_directory(directory);
100   test_server_service.LoadFileHandlers();
101 
102   rpc::system_server::Init();
103   rpc::system_server::Server().RegisterService(test_server_service,
104                                                transfer_service);
105 
106   thread::DetachedThread(thread::stl::Options(), transfer_thread);
107 
108   PW_LOG_INFO("Starting pw_rpc server");
109   PW_CHECK_OK(rpc::system_server::Start());
110 }
111 
112 }  // namespace
113 }  // namespace pw::transfer
114 
main(int argc,char * argv[])115 int main(int argc, char* argv[]) {
116   if (argc != 3) {
117     PW_LOG_ERROR("Usage: %s PORT DIR", argv[0]);
118     return 1;
119   }
120 
121   pw::transfer::RunServer(std::atoi(argv[1]), argv[2]);
122   return 0;
123 }
124