kopia lustrzana https://gitlab.com/tomaszg/geostat
209 wiersze
6.1 KiB
C++
209 wiersze
6.1 KiB
C++
#include "okapi.h"
|
|
#include "debug.h"
|
|
|
|
#include <iostream>
|
|
#include <vector>
|
|
#include <iomanip>
|
|
#include <sstream>
|
|
|
|
#include <curl/curl.h>
|
|
#include <nlohmann/json.hpp>
|
|
|
|
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";
|
|
static const std::string OKAPI_changelog = "services/replicate/changelog";
|
|
|
|
// Callback for cURL easy interface used to save received output to std::string object
|
|
size_t Okapi::write_cb(char* ptr, __attribute__((unused)) size_t size, size_t nmemb, void* userdata) {
|
|
std::string* str = reinterpret_cast<std::string*>(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|date&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|owner|region|size2";
|
|
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<float>();
|
|
// c.terr = j["terrain"].get<float>();
|
|
// // std::cout << j["difficulty"] << '\n';
|
|
// // std::cout << j["difficulty"].get<float>() << '\n';
|
|
// // std::cout << j["difficulty"].get<double>() << '\n';
|
|
// // std::cout << j["difficulty"].get<int>() << '\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<std::pair<std::string, std::tm>> codes) {
|
|
Cache c;
|
|
Caches cc;
|
|
|
|
uint n = 0;
|
|
uint k = 0;
|
|
while (n < codes.size()) {
|
|
std::string codes_list;
|
|
codes_list.reserve(500*7);
|
|
k = 0;
|
|
|
|
// int n = (codes.size() > 500) ? 500 : cc.codes();
|
|
while (n < codes.size() && k < 500) {
|
|
codes_list += codes.at(n).first;
|
|
codes_list += '|';
|
|
n++;
|
|
k++;
|
|
}
|
|
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.size = el.value()["size2"];
|
|
c.region = el.value()["region"];
|
|
c.diff = el.value()["difficulty"];
|
|
c.terr = el.value()["terrain"];
|
|
c.owner = el.value()["owner"]["username"];
|
|
c.owner_uuid = el.value()["owner"]["uuid"];
|
|
c.pos = get_lat_lon(el.value()["location"]);
|
|
c.origin = "OC.pl";
|
|
//ugly way to handle date...
|
|
for (auto& el2 : codes) {
|
|
if (el2.first == c.code) {
|
|
c.set_date(&el2.second);
|
|
break;
|
|
}
|
|
}
|
|
cc.insert(c);
|
|
}
|
|
}
|
|
return cc;
|
|
}
|
|
|
|
Caches Okapi::get_user_caches(std::string uuid, int count) {
|
|
Caches cc;
|
|
std::vector<std::pair<std::string, std::tm>> codes;
|
|
json j;
|
|
std::tm date;
|
|
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") {
|
|
std::stringstream ss(el.value()["date"].get<std::string>());
|
|
// TODO need to take care of the time zone :/
|
|
ss >> std::get_time(&date, "%Y-%m-%dT%H:%M:%S+");
|
|
codes.push_back(std::pair(el.value()["cache_code"].get<std::string>(), date));
|
|
}
|
|
}
|
|
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") {
|
|
std::stringstream ss(el.value()["date"].get<std::string>());
|
|
ss >> std::get_time(&date, "%Y-%m-%dT%H-%M-%S");
|
|
codes.push_back(std::pair(el.value()["cache_code"].get<std::string>(), date));
|
|
}
|
|
}
|
|
off += j.size();
|
|
count -= count_req;
|
|
} while (j.size() > 0 && count > 0);
|
|
}
|
|
|
|
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"];
|
|
}
|
|
|
|
std::string Okapi::get_changelog_json(int revision) {
|
|
std::string service = url + OKAPI_changelog;
|
|
std::string query = "consumer_key=" + key + "&since=" + std::to_string(revision);
|
|
return curl_post(service, query);
|
|
}
|