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