-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathprocessor.cpp
166 lines (148 loc) · 4.05 KB
/
processor.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
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
#include "processor.h"
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <sstream>
#include <utility>
namespace ptree = boost::property_tree;
namespace json = boost::property_tree::json_parser;
namespace {
/**
* Abstract action.
*/
class Action {
public:
/**
* Creates specific command.
* @param input - input data about command.
* @return pointer to specific command.
*/
static std::unique_ptr<Action> create(ptree::ptree input);
Action(ptree::ptree input): input_{move(input)} {}
virtual ~Action() = default;
/**
* Executes command.
* @param graph - the graph to run the command on it.
* @return result of the command.
*/
ptree::ptree execute(Graph& graph);
protected:
/**
* Runs command.
* @param graph - the graph to run the command on it.
* @return result of the command.
*/
virtual ptree::ptree run(Graph& graph) = 0;
ptree::ptree input_;
};
class AddVertex: public Action {
public:
using Action::Action;
ptree::ptree run(Graph& graph) {
ptree::ptree output;
output.put("id", graph.addVertex());
return output;
}
};
class RemoveVertex: public Action {
public:
using Action::Action;
ptree::ptree run(Graph& graph) {
auto id = input_.get_optional<Id>("id");
if (!id) {
throw std::invalid_argument{"Not enough data"};
}
graph.removeVertex(*id);
return {};
}
};
class AddEdge: public Action {
public:
using Action::Action;
ptree::ptree run(Graph& graph) {
auto from = input_.get_optional<Id>("from");
auto to = input_.get_optional<Id>("to");
auto weight = input_.get_optional<Distance>("weight");
if (!from || !to || !weight) {
throw std::invalid_argument{"Not enough data"};
}
graph.setEdge(*from, *to, *weight);
return {};
}
};
class RemoveEdge: public Action {
public:
using Action::Action;
ptree::ptree run(Graph& graph) {
auto from = input_.get_optional<Id>("from");
auto to = input_.get_optional<Id>("to");
if (!from || !to) {
throw std::invalid_argument{"Not enough data"};
}
graph.removeEdge(*from, *to);
return {};
}
};
class GetPath: public Action {
public:
using Action::Action;
ptree::ptree run(Graph& graph) {
auto from = input_.get_optional<Id>("from");
auto to = input_.get_optional<Id>("to");
if (!from || !to) {
throw std::invalid_argument{"Not enough data"};
}
ptree::ptree output;
ptree::ptree array;
auto ids = graph.path(*from, *to);
for (auto id: ids) {
ptree::ptree item;
item.put("", id);
array.push_back(std::make_pair("", item));
}
output.put_child("ids", array);
return output;
}
};
class Unknown: public Action {
public:
using Action::Action;
ptree::ptree run(Graph&) {
throw std::invalid_argument{"Unknown action"};
}
};
std::unique_ptr<Action> Action::create(ptree::ptree input) {
auto action = input.get<std::string>("action", "unknown");
if (action == "AddVertex") {
return std::make_unique<AddVertex>(move(input));
} else if (action == "RemoveVertex") {
return std::make_unique<RemoveVertex>(move(input));
} else if (action == "AddEdge") {
return std::make_unique<AddEdge>(move(input));
} else if (action == "RemoveEdge") {
return std::make_unique<RemoveEdge>(move(input));
} else if (action == "GetPath") {
return std::make_unique<GetPath>(move(input));
}
return std::make_unique<Unknown>(move(input));
}
ptree::ptree Action::execute(Graph& graph) try {
return run(graph);
} catch (std::exception const& e) {
ptree::ptree error;
error.put("error", e.what());
return error;
}
} // namespace
std::string Processor::serve(std::string request) try {
std::istringstream iss{request};
ptree::ptree input;
json::read_json(iss, input);
std::ostringstream oss;
auto output = Action::create(move(input))->execute(graph_);
json::write_json_helper(oss, output, 0, false);
return oss.str();
} catch (ptree::json_parser_error const& e) {
return R"({"error":"Invalid JSON"})";
} catch (...) {
return R"({"error":"Internal error"})";
}