-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.cpp
132 lines (120 loc) · 5.23 KB
/
main.cpp
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
#include <iostream>
#include <boost/program_options.hpp>
#include <boost/filesystem.hpp>
#include "core/file_watcher.h"
#include "communication/message.h"
#include "core/connection.h"
namespace fs = boost::filesystem;
namespace po = boost::program_options;
po::variables_map parse_options(int argc, char const *const argv[]) {
try {
po::options_description desc("Backup client options");
desc.add_options()
("help,h",
"produce help message")
("path-to-watch,P",
po::value<fs::path>()->default_value(
fs::path{"."}
), "set path to watch")
("hostname,H",
po::value<std::string>()->required(),
"set backup server hostname")
("service,S",
po::value<std::string>()->required(),
"set backup server service name/port number")
("threads,T",
po::value<size_t>()->default_value(8),
"set worker thread pool size")
("delay,D",
po::value<size_t>()->default_value(5000),
"set file watcher refresh rate in milliseconds");
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);
if (vm.count("help")) {
std::cout << desc << std::endl;
std::exit(EXIT_SUCCESS);
}
po::notify(vm);
// canonical returns the absolute path resolving symbolic link, dot and dot-dot
// it also checks the existence
vm.at("path-to-watch").value() = fs::canonical(vm["path-to-watch"].as<fs::path>());
auto watched_dir = vm["path-to-watch"];
auto watched_dir_path = watched_dir.as<fs::path>();
if (!fs::is_directory(watched_dir_path)) {
std::cerr << watched_dir_path.generic_path().string() << " is not a directory" << std::endl;
std::exit(EXIT_FAILURE);
}
if (watched_dir.defaulted()) {
std::cout << "--path-to-watch option set to default value: "
<< watched_dir_path.generic_path().string() << std::endl;
}
if (vm["threads"].defaulted()) {
std::cout << "--threads option set to default value: "
<< vm["threads"].as<size_t>() << std::endl;
}
if (vm["delay"].defaulted()) {
std::cout << "--delay option set to default value: "
<< vm["delay"].as<size_t>() << std::endl;
}
return vm;
}
catch (std::exception &ex) {
std::cout << "Error during options parsing: " << ex.what() << std::endl;
std::exit(EXIT_FAILURE);
}
}
int main(int argc, char const *const argv[]) {
// Parsing program options
po::variables_map vm = parse_options(argc, argv);
try {
// Destructuring program options
fs::path path_to_watch = vm["path-to-watch"].as<fs::path>();
std::string hostname = vm["hostname"].as<std::string>();
std::string service = vm["service"].as<std::string>();
size_t thread_pool_size = vm["threads"].as<size_t>();
size_t delay = vm["delay"].as<size_t>();
// Constructing an abstraction for the watched directory
auto watched_dir_ptr = directory::dir::get_instance(path_to_watch, true);
boost::asio::io_context io_context;
// Allowing generic SSL/TLS version
boost::asio::ssl::context ctx{boost::asio::ssl::context::sslv23};
ctx.load_verify_file("../certs/ca.pem");
// Constructing an abstraction for handling SSL connection task
auto connection_ptr = connection::get_instance(io_context, ctx);
// Constructing an abstraction for scheduling async task and managing communication
// with server through the connection
auto scheduler_ptr = scheduler::get_instance(io_context, watched_dir_ptr, connection_ptr, thread_pool_size);
// Constructing an abstraction for monitoring the filesystem and scheduling
// server synchronizations through bind_scheduler
file_watcher fw{watched_dir_ptr, scheduler_ptr, std::chrono::milliseconds{delay}};
connection_ptr->set_reconnection_handler([scheduler_ptr](){
scheduler_ptr->reconnect();
});
// Performing server connection
connection_ptr->resolve(hostname, service);
connection_ptr->connect();
// Starting login procedure
if (!scheduler_ptr->login()) {
std::cerr << "Authentication failed" << std::endl;
std::exit(EXIT_FAILURE);
}
// Starting specified directory local file watching
fw.start();
io_context.stop();
scheduler_ptr->join_threads();
connection_ptr->join_thread();
}
catch (fs::filesystem_error &e) {
std::cerr << "Filesystem error from " << e.what() << std::endl;
std::exit(EXIT_FAILURE);
}
catch (boost::system::system_error &e) {
std::cerr << "System error with code " << e.code() << ": " << e.what() << std::endl;
std::exit(EXIT_FAILURE);
}
catch (std::exception &e) {
std::cerr << "Error: " << e.what() << std::endl;
std::exit(EXIT_FAILURE);
}
std::exit(EXIT_SUCCESS);
}