-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtransfer_server.cpp
More file actions
179 lines (137 loc) · 3.93 KB
/
transfer_server.cpp
File metadata and controls
179 lines (137 loc) · 3.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
//
// Copyright (c) 2023-present DeepGrace (complex dot invoke at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/deepgrace/arpc
//
#define BOOST_ASIO_HAS_IO_URING
#define BOOST_ASIO_DISABLE_EPOLL
#include <fstream>
#include <iostream>
#include <filesystem>
#include <arpc.hpp>
#include <transfer.pb.h>
namespace net = boost::asio;
namespace fs = std::filesystem;
namespace gp = google::protobuf;
std::string on_transfer(const fs::path& path, bool pre_transfer)
{
std::string file = path;
if (pre_transfer)
{
if (file.back() == '/')
{
file.pop_back();
std::cout << "begin receiving directory " << file << std::endl;
}
else
std::cout << "begin receiving file " << file << std::endl;
}
else
{
if (fs::is_directory(file))
std::cout << "after receiving directory " << file << std::endl;
else if (fs::is_regular_file(file))
std::cout << "after receiving file " << file << std::endl;
}
return file;
}
void done()
{
}
class service : public pb::service
{
public:
service(const fs::path& path)
{
fs::create_directories(path);
chdir(path.c_str());
}
template <typename T, typename U>
void set_res(const T* req, U* res, gp::Closure* done, bool result)
{
res->set_success(result);
res->set_id(req->id());
done->Run();
}
constexpr decltype(auto) upon_transfer(const std::string& name, bool b)
{
auto p = name.find_first_of('/');
if (p == std::string::npos)
p = name.size() - b;
return on_transfer(name.substr(0, p + b), b);
}
void data_transfer(gp::RpcController* controller, const pb::data_req* req, pb::data_res* res, gp::Closure* done)
{
std::string name = req->name();
size_t size = name.size();
set_res(req, res, done, size);
if (!size)
return;
if (req->id() == 1)
upon_transfer(name, true);
bool set_perms = false;
bool is_dir = name.back() == '/';
if (is_dir)
name.pop_back();
if (name != last)
{
last = name;
set_perms = true;
std::cout << "receiving " << name << std::endl;
}
if (is_dir)
fs::create_directories(name);
else
{
if (set_perms)
{
if (auto parent = fs::path(name).parent_path(); !parent.empty())
fs::create_directories(parent);
if (fout.is_open())
fout.close();
fout.open(name, std::ios_base::app | std::ios_base::binary);
}
auto& data = req->data();
fout.write(data.c_str(), data.size());
}
if (set_perms)
fs::permissions(name, fs::perms(req->perms()));
}
void done_transfer(gp::RpcController* controller, const pb::done_req* req, pb::done_res* res, gp::Closure* done)
{
std::string name = req->name();
size_t size = name.size();
set_res(req, res, done, size);
if (!size)
return;
if (fout.is_open())
fout.close();
upon_transfer(name, false);
}
~service()
{
}
std::string last;
std::ofstream fout;
};
int main(int argc, char* argv[])
{
if (argc != 4)
{
std::cout << "Usage: " << argv[0] << " <host> <port> <path>" << std::endl;
return 1;
}
std::string host(argv[1]);
std::string port(argv[2]);
std::string path(argv[3]);
net::io_context ioc;
service s(path);
arpc::server server(ioc, host, port);
server.register_service(&s, gp::NewPermanentCallback(&done));
server.run();
ioc.run();
return 0;
}