summaryrefslogtreecommitdiffstats
path: root/server/src/rwgps.cppm
diff options
context:
space:
mode:
Diffstat (limited to 'server/src/rwgps.cppm')
-rw-r--r--server/src/rwgps.cppm112
1 files changed, 4 insertions, 108 deletions
diff --git a/server/src/rwgps.cppm b/server/src/rwgps.cppm
index 3b01e6c..2ed124e 100644
--- a/server/src/rwgps.cppm
+++ b/server/src/rwgps.cppm
@@ -1,8 +1,6 @@
1module; 1module;
2 2
3#include <boost/beast/core.hpp> 3#include <boost/asio/io_context.hpp>
4#include <boost/beast/http.hpp>
5#include <boost/json.hpp>
6 4
7export module routemon:rwgps; 5export module routemon:rwgps;
8 6
@@ -10,10 +8,7 @@ import std;
10import :http.client; 8import :http.client;
11import :log; 9import :log;
12 10
13namespace beast = boost::beast;
14namespace bhttp = beast::http;
15namespace net = boost::asio; 11namespace net = boost::asio;
16namespace json = boost::json;
17 12
18namespace routemon::rwgps { 13namespace routemon::rwgps {
19 14
@@ -45,55 +40,6 @@ struct get_routes_response
45 get_routes_meta meta; 40 get_routes_meta meta;
46}; 41};
47 42
48auto tag_invoke(json::value_to_tag<route_summary> const&, json::value const& jv)
49 -> route_summary
50{
51 return {
52 .id = json::value_to<std::int64_t>(jv.at("id")),
53 .user_id = json::value_to<std::int64_t>(jv.at("user_id")),
54 .url = json::value_to<std::string>(jv.at("url")),
55 .name = json::value_to<std::string>(jv.at("name")),
56 .description = json::value_to<std::string>(jv.at("description")),
57 };
58}
59
60auto tag_invoke(json::value_to_tag<pagination> const&, json::value const& jv)
61 -> pagination
62{
63 return {
64 .record_count = json::value_to<std::size_t>(jv.at("record_count")),
65 .page_count = json::value_to<std::size_t>(jv.at("page_count")),
66 .page_size = json::value_to<std::size_t>(jv.at("page_size")),
67 .next_page_url =
68 json::value_to<std::optional<std::string>>(jv.at("next_page_url")),
69 };
70}
71
72auto tag_invoke(
73 json::value_to_tag<get_routes_meta> const&, json::value const& jv)
74 -> get_routes_meta
75{
76 return {
77 .pagination = json::value_to<pagination>(jv.at("pagination")),
78 };
79}
80
81auto tag_invoke(
82 json::value_to_tag<get_routes_response> const&, json::value const& jv)
83 -> get_routes_response
84{
85 return {
86 .routes = json::value_to<std::vector<route_summary>>(jv.at("routes")),
87 .meta = json::value_to<get_routes_meta>(jv.at("meta")),
88 };
89}
90
91auto json_value_to_get_routes_response(json::value const& jv)
92 -> get_routes_response
93{
94 return json::value_to<get_routes_response>(jv);
95}
96
97export class client 43export class client
98{ 44{
99 log::logger l_; 45 log::logger l_;
@@ -101,64 +47,14 @@ export class client
101 std::string api_key_; 47 std::string api_key_;
102 std::string auth_token_; 48 std::string auth_token_;
103 49
104 static constexpr std::string host = "ridewithgps.com"; 50 auto get_routes_page(std::size_t page) -> get_routes_response;
105
106 // TODO: handle failure appropriately
107 auto get_routes_page(std::size_t page) -> get_routes_response
108 {
109 auto req = bhttp::request<bhttp::string_body>{
110 bhttp::verb::get,
111 std::format("/api/v1/routes.json?page_size=200?page={}", page),
112 11, // HTTP 1.1
113 };
114 req.set(bhttp::field::host, host);
115 req.set("x-rwgps-api-key", api_key_);
116 req.set("x-rwgps-auth-token", auth_token_);
117
118 auto rsp = hc_.do_request(req);
119 auto p = json::stream_parser{};
120 for (auto const frag : rsp.body().cdata())
121 {
122 p.write(static_cast<char const*>(frag.data()), frag.size());
123 }
124 assert(p.done());
125 return json_value_to_get_routes_response(p.release());
126 }
127 51
128public: 52public:
129 explicit client( 53 explicit client(
130 net::io_context& ioc, log::logger const& l, std::string api_key, 54 net::io_context& ioc, log::logger const& l, std::string api_key,
131 std::string auth_token) 55 std::string auth_token);
132 : l_{l.sub("rwgps-client")}, hc_{ioc}, api_key_{std::move(api_key)},
133 auth_token_{std::move(auth_token)}
134 {
135 }
136
137 auto get_all_routes() -> std::vector<route_summary>
138 {
139 // TODO: make sure that there are no duplicates here.
140 // What does RWGPS sort on, by default?
141 // Consider using an associative container instead of a vector.
142 auto record_count = 0uz;
143 auto current_page = 0uz;
144 auto routes = std::vector<route_summary>{};
145
146 while (true)
147 {
148 auto rsp = get_routes_page(current_page);
149 if (rsp.meta.pagination.next_page_url)
150 l_.debug("Next page URL: {}", *rsp.meta.pagination.next_page_url);
151 routes.append_range(rsp.routes);
152 if (rsp.meta.pagination.record_count > 0)
153 record_count = rsp.meta.pagination.record_count;
154 if (rsp.routes.empty() || routes.size() >= record_count)
155 {
156 break;
157 }
158 }
159 56
160 return routes; 57 auto get_all_routes() -> std::vector<route_summary>;
161 }
162}; 58};
163 59
164} // namespace routemon::rwgps 60} // namespace routemon::rwgps