-
Notifications
You must be signed in to change notification settings - Fork 5
/
file_exchange_client.cc
156 lines (136 loc) · 4.5 KB
/
file_exchange_client.cc
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
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstdint>
#include <utility>
#include <cassert>
#include <sysexits.h>
#include <grpc/grpc.h>
#include <grpc++/channel.h>
#include <grpc++/client_context.h>
#include <grpc++/create_channel.h>
#include <grpc++/security/credentials.h>
#include "utils.h"
#include "sequential_file_writer.h"
#include "file_reader_into_stream.h"
using grpc::Channel;
using grpc::ClientContext;
using grpc::ClientReader;
using grpc::ClientReaderWriter;
using grpc::ClientWriter;
using grpc::Status;
using fileexchange::FileId;
using fileexchange::FileContent;
using fileexchange::FileExchange;
class FileExchangeClient {
public:
FileExchangeClient(std::shared_ptr<Channel> channel)
: m_stub(FileExchange::NewStub(channel))
{
}
bool PutFile(std::int32_t id, const std::string& filename)
{
FileId returnedId;
ClientContext context;
std::unique_ptr<ClientWriter<FileContent>> writer(m_stub->PutFile(&context, &returnedId));
try {
FileReaderIntoStream< ClientWriter<FileContent> > reader(filename, id, *writer);
// TODO: Make the chunk size configurable
const size_t chunk_size = 1UL << 20; // Hardcoded to 1MB, which seems to be recommended from experience.
reader.Read(chunk_size);
}
catch (const std::exception& ex) {
std::cerr << "Failed to send the file " << filename << ": " << ex.what() << std::endl;
// FIXME: Indicate to the server that something went wrong and that the trasfer should be aborted.
}
writer->WritesDone();
Status status = writer->Finish();
if (!status.ok()) {
std::cerr << "File Exchange rpc failed: " << status.error_message() << std::endl;
return false;
}
else {
std::cout << "Finished sending file with id " << returnedId.id() << std::endl;
}
return true;
}
bool GetFileContent(std::int32_t id)
{
FileId requestedId;
FileContent contentPart;
ClientContext context;
SequentialFileWriter writer;
std::string filename;
requestedId.set_id(id);
std::unique_ptr<ClientReader<FileContent> > reader(m_stub->GetFileContent(&context, requestedId));
try {
while (reader->Read(&contentPart)) {
assert(contentPart.id() == id);
filename = contentPart.name();
writer.OpenIfNecessary(contentPart.name());
auto* const data = contentPart.mutable_content();
writer.Write(*data);
};
const auto status = reader->Finish();
if (! status.ok()) {
std::cerr << "Failed to get the file ";
if (! filename.empty()) {
std::cerr << filename << ' ';
}
std::cerr << "with id " << id << ": " << status.error_message() << std::endl;
return false;
}
std::cout << "Finished receiving the file " << filename << " id: " << id << std::endl;
}
catch (const std::system_error& ex) {
std::cerr << "Failed to receive " << filename << ": " << ex.what();
return false;
}
return true;
}
private:
std::unique_ptr<fileexchange::FileExchange::Stub> m_stub;
};
void usage [[ noreturn ]] (const char* prog_name)
{
std::cerr << "USAGE: " << prog_name << " [put|get] num_id [filename]" << std::endl;
std::exit(EX_USAGE);
}
int main(int argc, char** argv)
{
if (argc < 3) {
usage(argv[0]);
}
const std::string verb = argv[1];
std::int32_t id = -1;
try {
id = std::atoi(argv[2]);
}
catch (std::invalid_argument) {
std::cerr << "Invalid Id " << argv[2] << std::endl;
usage(argv[0]);
}
bool succeeded = false;
FileExchangeClient client(grpc::CreateChannel("localhost:50051", grpc::InsecureChannelCredentials()));
if ("put" == verb) {
if (4 != argc) {
usage(argv[0]);
}
const std::string filename = argv[3];
succeeded = client.PutFile(id, filename);
}
else if ("get" == verb) {
if (3 != argc) {
usage(argv[0]);
}
succeeded = client.GetFileContent(id);
}
else {
std::cerr << "Unknown verb " << verb << std::endl;
usage(argv[0]);
}
return succeeded ? EX_OK : EX_IOERR;
}