#include "okapi.h" #include "cache.h" #include "debug.h" #include #include #include #include using json = nlohmann::json; static const std::string OKAPI_logs = "services/logs/userlogs"; static const std::string OKAPI_cache = "services/caches/geocache"; static const std::string OKAPI_caches = "services/caches/geocaches"; static const std::string OKAPI_username = "services/users/by_username"; size_t Okapi::write_cb(char* ptr, size_t size, size_t nmemb, void* userdata) { std::string* str = reinterpret_cast(userdata); str->append(ptr, nmemb); return nmemb; } std::string Okapi::curl_post(std::string url, std::string post) { CURL* curl; CURLcode res; std::string output; Debug(5) << "API query: " << post; curl = curl_easy_init(); if (!curl) { curl_global_cleanup(); throw 0; } curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post.c_str()); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&output); res = curl_easy_perform(curl); if (res != CURLE_OK) { Debug(1) << "curl_easy_perform() failed: " << curl_easy_strerror(res) << '\n'; curl_easy_cleanup(curl); std::exit(EXIT_FAILURE); } curl_easy_cleanup(curl); Debug(5) << "API query result: " << output; if (output.starts_with("{\"error\"")) { json j = json::parse(output); Debug(1) << "OKAPI error: " << j["error"]["developer_message"]; std::exit(EXIT_FAILURE); } return output; } std::string Okapi::get_user_caches_json(std::string uuid, int count, int offset) { std::string service = url + OKAPI_logs; std::string query = "consumer_key=" + key + "&user_uuid=" + uuid + "&fields=cache_code|type&limit=" + std::to_string(count) + "&offset=" + std::to_string(offset); return curl_post(service, query); } // std::string Okapi::get_cache_json(std::string code) { // std::string service = url + OKAPI_cache; // std::string query = "consumer_key=" + key + "&cache_code=" + code + "&fields=code|name|location|type|status|difficulty|terrain"; // return curl_post(service, query); // } std::string Okapi::get_caches_json(std::string codes) { std::string service = url + OKAPI_caches; std::string query = "consumer_key=" + key + "&cache_codes=" + codes + "&fields=code|name|location|type|status|difficulty|terrain"; return curl_post(service, query); } // Cache Okapi::get_cache(std::string code) { // std::string output = get_cache_json(code); // json j = json::parse(output); // // Cache c; // c.code = code; // c.name = j["name"]; // c.type = j["type"]; // c.diff = j["difficulty"].get(); // c.terr = j["terrain"].get(); // // std::cout << j["difficulty"] << '\n'; // // std::cout << j["difficulty"].get() << '\n'; // // std::cout << j["difficulty"].get() << '\n'; // // std::cout << j["difficulty"].get() << '\n'; // // std::string loc = j["location"]; // int pos = loc.find("|"); // c.pos.lat = stof(loc.substr(0, pos)); // c.pos.lon = stof(loc.substr(pos + 1)); // // return c; // } Caches Okapi::get_caches(std::vector codes) { Caches cc; Cache c; while (codes.size() > 0) { std::string codes_list; int n = (codes.size() > 500) ? 500 : codes.size(); for (int i = 0; i < n; i++) { codes_list += codes.back(); codes_list += '|'; codes.pop_back(); } codes_list.pop_back(); // remove trailing '|' std::string output = get_caches_json(codes_list); json j = json::parse(output); for (auto& el : j.items()) { c.code = el.value()["code"]; c.name = el.value()["name"]; c.type = el.value()["type"]; c.diff = el.value()["difficulty"]; c.terr = el.value()["terrain"]; ; std::string loc = el.value()["location"]; int pos = loc.find("|"); c.pos.lat = stof(loc.substr(0, pos)); c.pos.lon = stof(loc.substr(pos + 1)); c.origin = ocpl; cc.insert(c); } } return cc; } Caches Okapi::get_user_caches(std::string uuid, int count) { Caches cc; std::vector codes; json j; int off = 0; if (count == 0) do { std::string output = get_user_caches_json(uuid, 1000, off); j = json::parse(output); for (auto& el : j.items()) { if (el.value()["type"] == "Found it") { codes.emplace_back(el.value()["cache_code"]); } } off += j.size(); } while (j.size() > 0); else { int count_req = (count > 1000) ? 1000 : count; do { std::string output = get_user_caches_json(uuid, count_req, off); j = json::parse(output); for (auto& el : j.items()) { if (el.value()["type"] == "Found it") { codes.emplace_back(el.value()["cache_code"]); } } off += j.size(); count -= count_req; } while (j.size() > 0 && count > 0); } // Debug(3) << codes; cc = get_caches(codes); Debug(2) << "Caches read from OC: " << cc.size() << '\n'; return cc; } std::string Okapi::get_uuid(std::string username) { std::string service = url + OKAPI_username; std::string query = "consumer_key=" + key + "&username=" + username + "&fields=uuid"; json j = json::parse(curl_post(service, query)); return j["uuid"]; }