#include #include #include #include #include #include #include #include "utils.h" namespace hm { Level gConfLogLevel = Warn; std::string gConfFaceRemote = "http://127.0.0.1/", gConfCarRemote = "http://127.0.0.1/", // NOLINT gConfLoginUser = "", gConfLoginPass = ""; // NOLINT unsigned int gConfSearchGap = 60, gConfSearchDuration = 4, gConfServerPort = 8040; void ReadConfig(const char *path) { std::ifstream file(path); if (!file) { LogM(Error, "config file \"%s\" open failed.", path); } else { std::string line, key, value; while (std::getline(file, line)) { if (line.empty() || line.size() == 1 || line[0] == '#') continue; if (splitKeyValue(line, key, value)) { if (key == "faceRemote") gConfFaceRemote = value; else if (key == "carRemote") gConfCarRemote = value; else if (key == "user") gConfLoginUser = value; else if (key == "pass") gConfLoginPass = value; else if (key == "logLevel") gConfLogLevel = (Level) std::stoi(value); else if (key == "searchGap") gConfSearchGap = std::stoi(value); else if (key == "searchDuration") gConfSearchDuration = std::stoi(value); else if (key == "serverPort") gConfServerPort = std::stoi(value); else LogM(Warn, "unrecognized config key[%s], value[%s]", key.c_str(), value.c_str()); } } } Log( Trace, "{faceRemote:%s, carRemote:%s, user:%s, pass:%s, logLevel:%d, port:%d, searchGap:%d, searchDuration:%d}", gConfFaceRemote.c_str(), gConfCarRemote.c_str(), gConfLoginUser.c_str(), gConfLoginPass.c_str(), gConfLogLevel, gConfServerPort, gConfSearchGap, gConfSearchDuration ); } const char *logLevelName(const Level &level) { switch (level) { case Trace: return "TRACE"; case Info: return "INFO"; case Warn: return "WARN"; case Error: return "ERROR"; default: return "NULL"; } } bool getLogStatus(const Level &level) { return gConfLogLevel && level >= gConfLogLevel; } bool startsWith(const std::string &str, const std::string &start) { if (str.length() < start.length()) { return false; } return str.compare(0, start.length(), start) == 0; } bool endsWith(const std::string &str, const std::string &end) { if (str.length() < end.length()) { return false; } return str.compare(str.length() - end.length(), end.length(), end) == 0; } std::string trim(const std::string &str) { unsigned start = 0, end = str.size() - 1; while (std::isspace(str[start])) start++; while (std::isspace(str[end])) end--; return str.substr(start, end - start + 1); } bool splitKeyValue(const std::string &src, std::string &key, std::string &value) { std::stringstream ss(src); std::string token; if (std::getline(ss, token, '=') && !token.empty()) { key = trim(token); if (std::getline(ss, token)) { value = trim(token); return true; } } return false; } std::vector getIpList() { std::vector ipList; struct ifaddrs *ifap, *ifa; if (getifaddrs(&ifap) == -1) { return ipList; } for (ifa = ifap; ifa != nullptr; ifa = ifa->ifa_next) { if (ifa->ifa_addr == nullptr) { continue; } if (ifa->ifa_addr->sa_family == AF_INET) { auto *addr = (struct sockaddr_in *) ifa->ifa_addr; char localIP[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &(addr->sin_addr), localIP, INET_ADDRSTRLEN); ipList.emplace_back(localIP); } } freeifaddrs(ifap); return ipList; } int imageRead(const std::string &path, char *&buffer) { std::ifstream img(path, std::ios::binary); img.seekg(0, std::ios::end); int size = (int) img.tellg(); img.seekg(0, std::ios::beg); buffer = new char[size]; img.read(buffer, size); return size; } int imgcpy(char *&dest, const std::string &src) { int size = (int) src.size(); dest = new char[size]; for (int i = 0; i < size; ++i) dest[i] = src[i]; return size; } void imageSave(const std::string &path, char *&start, const int &size) { if (size > 0 && start != nullptr) { std::ofstream out(path, std::ios::binary); if (!out.is_open()) return; out.write(start, size); out.close(); } } void imageSave(const std::string &path, unsigned char *&start, const unsigned int &size) { if (size > 0 && start != nullptr) { std::ofstream out(path, std::ios::binary); if (!out.is_open()) return; out.write((char *) start, size); out.close(); } } time_t toTimestamp( const unsigned int &year, const unsigned int &mon, const unsigned int &day, const unsigned int &hour, const unsigned int &min, const unsigned int &sec ) { struct tm info = { .tm_sec = (int) sec, .tm_min = (int) min, .tm_hour = (int) hour, .tm_mday = (int) day, .tm_mon = (int) mon - 1, .tm_year = (int) year - 1900 }; return mktime(&info); } size_t onPostResponse(void *contents, size_t size, size_t nMem, std::string *output) { size_t total_size = size * nMem; output->append(static_cast(contents), total_size); return total_size; } // 22(21+1) errors here, never mind, it's ok anyway. void dataUpload( const std::string &url, const std::map &data, unsigned char *&imgBuf, const unsigned int &bufSize ) { CURL *curl = curl_easy_init(); if (!curl) { Log(Error, "CURL initialization failed."); return; } curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3); curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl, CURLOPT_POST, 1); struct curl_httppost *form = nullptr; struct curl_httppost *last = nullptr; // json data for (const auto &it : data) { curl_formadd( &form, &last, CURLFORM_COPYNAME, it.first.c_str(), CURLFORM_COPYCONTENTS, it.second.c_str(), CURLFORM_END ); } // image curl_formadd( &form, &last, CURLFORM_COPYNAME, "image", CURLFORM_BUFFER, "image.jpg", CURLFORM_BUFFERPTR, imgBuf, CURLFORM_BUFFERLENGTH, bufSize, CURLFORM_END ); curl_easy_setopt(curl, CURLOPT_HTTPPOST, form); // response std::string response; curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, onPostResponse); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); CURLcode res = curl_easy_perform(curl); if (res == CURLE_OPERATION_TIMEDOUT) { Log(Warn, "Connection Timeout"); } else if (res == CURLE_OK) { long code; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code); if (code == 200) { Log(Trace, "upload success with: %s", response.c_str()); } else { Log(Warn, "upload fail with: code[%ld], msg: %s", code, response.c_str()); } } else { Log(Error, "HTTP request failed: %s", curl_easy_strerror(res)); } curl_easy_cleanup(curl); curl_formfree(form); } }