utils.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. #include <sstream>
  2. #include <netinet/in.h>
  3. #include <arpa/inet.h>
  4. #include <unistd.h>
  5. #include <ifaddrs.h>
  6. #include <curl/curl.h>
  7. #include <fstream>
  8. #include "utils.h"
  9. namespace hm {
  10. Level gConfLogLevel = Warn;
  11. std::string gConfFaceRemote = "http://127.0.0.1/", gConfCarRemote = "http://127.0.0.1/", // NOLINT
  12. gConfLoginUser = "<username here>", gConfLoginPass = "<password here>"; // NOLINT
  13. unsigned int gConfSearchGap = 60, gConfSearchDuration = 4, gConfServerPort = 8040;
  14. void ReadConfig(const char *path) {
  15. std::ifstream file(path);
  16. if (!file) {
  17. LogM(Error, "config file \"%s\" open failed.", path);
  18. } else {
  19. std::string line, key, value;
  20. while (std::getline(file, line)) {
  21. if (line.empty() || line.size() == 1 || line[0] == '#') continue;
  22. if (splitKeyValue(line, key, value)) {
  23. if (key == "faceRemote") gConfFaceRemote = value;
  24. else if (key == "carRemote") gConfCarRemote = value;
  25. else if (key == "user") gConfLoginUser = value;
  26. else if (key == "pass") gConfLoginPass = value;
  27. else if (key == "logLevel") gConfLogLevel = (Level) std::stoi(value);
  28. else if (key == "searchGap") gConfSearchGap = std::stoi(value);
  29. else if (key == "searchDuration") gConfSearchDuration = std::stoi(value);
  30. else if (key == "serverPort") gConfServerPort = std::stoi(value);
  31. else
  32. LogM(Warn, "unrecognized config key[%s], value[%s]", key.c_str(), value.c_str());
  33. }
  34. }
  35. }
  36. Log(
  37. Trace, "{faceRemote:%s, carRemote:%s, user:%s, pass:%s, logLevel:%d, port:%d, searchGap:%d, searchDuration:%d}",
  38. gConfFaceRemote.c_str(), gConfCarRemote.c_str(), gConfLoginUser.c_str(), gConfLoginPass.c_str(),
  39. gConfLogLevel, gConfServerPort, gConfSearchGap, gConfSearchDuration
  40. );
  41. }
  42. const char *logLevelName(const Level &level) {
  43. switch (level) {
  44. case Trace:
  45. return "TRACE";
  46. case Info:
  47. return "INFO";
  48. case Warn:
  49. return "WARN";
  50. case Error:
  51. return "ERROR";
  52. default:
  53. return "NULL";
  54. }
  55. }
  56. bool getLogStatus(const Level &level) {
  57. return gConfLogLevel && level >= gConfLogLevel;
  58. }
  59. bool startsWith(const std::string &str, const std::string &start) {
  60. if (str.length() < start.length()) {
  61. return false;
  62. }
  63. return str.compare(0, start.length(), start) == 0;
  64. }
  65. bool endsWith(const std::string &str, const std::string &end) {
  66. if (str.length() < end.length()) {
  67. return false;
  68. }
  69. return str.compare(str.length() - end.length(), end.length(), end) == 0;
  70. }
  71. std::string trim(const std::string &str) {
  72. unsigned start = 0, end = str.size() - 1;
  73. while (std::isspace(str[start])) start++;
  74. while (std::isspace(str[end])) end--;
  75. return str.substr(start, end - start + 1);
  76. }
  77. bool splitKeyValue(const std::string &src, std::string &key, std::string &value) {
  78. std::stringstream ss(src);
  79. std::string token;
  80. if (std::getline(ss, token, '=') && !token.empty()) {
  81. key = trim(token);
  82. if (std::getline(ss, token)) {
  83. value = trim(token);
  84. return true;
  85. }
  86. }
  87. return false;
  88. }
  89. std::vector<std::string> getIpList() {
  90. std::vector<std::string> ipList;
  91. struct ifaddrs *ifap, *ifa;
  92. if (getifaddrs(&ifap) == -1) {
  93. return ipList;
  94. }
  95. for (ifa = ifap; ifa != nullptr; ifa = ifa->ifa_next) {
  96. if (ifa->ifa_addr == nullptr) {
  97. continue;
  98. }
  99. if (ifa->ifa_addr->sa_family == AF_INET) {
  100. auto *addr = (struct sockaddr_in *) ifa->ifa_addr;
  101. char localIP[INET_ADDRSTRLEN];
  102. inet_ntop(AF_INET, &(addr->sin_addr), localIP, INET_ADDRSTRLEN);
  103. ipList.emplace_back(localIP);
  104. }
  105. }
  106. freeifaddrs(ifap);
  107. return ipList;
  108. }
  109. int imageRead(const std::string &path, char *&buffer) {
  110. std::ifstream img(path, std::ios::binary);
  111. img.seekg(0, std::ios::end);
  112. int size = (int) img.tellg();
  113. img.seekg(0, std::ios::beg);
  114. buffer = new char[size];
  115. img.read(buffer, size);
  116. return size;
  117. }
  118. int imgcpy(char *&dest, const std::string &src) {
  119. int size = (int) src.size();
  120. dest = new char[size];
  121. for (int i = 0; i < size; ++i) dest[i] = src[i];
  122. return size;
  123. }
  124. void imageSave(const std::string &path, char *&start, const int &size) {
  125. if (size > 0 && start != nullptr) {
  126. std::ofstream out(path, std::ios::binary);
  127. if (!out.is_open()) return;
  128. out.write(start, size);
  129. out.close();
  130. }
  131. }
  132. void imageSave(const std::string &path, unsigned char *&start, const unsigned int &size) {
  133. if (size > 0 && start != nullptr) {
  134. std::ofstream out(path, std::ios::binary);
  135. if (!out.is_open()) return;
  136. out.write((char *) start, size);
  137. out.close();
  138. }
  139. }
  140. time_t toTimestamp(
  141. const unsigned int &year, const unsigned int &mon, const unsigned int &day,
  142. const unsigned int &hour, const unsigned int &min, const unsigned int &sec
  143. ) {
  144. struct tm info = {
  145. .tm_sec = (int) sec, .tm_min = (int) min, .tm_hour = (int) hour,
  146. .tm_mday = (int) day, .tm_mon = (int) mon - 1, .tm_year = (int) year - 1900
  147. };
  148. return mktime(&info);
  149. }
  150. size_t onPostResponse(void *contents, size_t size, size_t nMem, std::string *output) {
  151. size_t total_size = size * nMem;
  152. output->append(static_cast<char *>(contents), total_size);
  153. return total_size;
  154. }
  155. // 22(21+1) errors here, never mind, it's ok anyway.
  156. void dataUpload(
  157. const std::string &url, const std::map<std::string, std::string> &data,
  158. unsigned char *&imgBuf, const unsigned int &bufSize
  159. ) {
  160. CURL *curl = curl_easy_init();
  161. if (!curl) {
  162. Log(Error, "CURL initialization failed.");
  163. return;
  164. }
  165. curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);
  166. curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
  167. curl_easy_setopt(curl, CURLOPT_POST, 1);
  168. struct curl_httppost *form = nullptr;
  169. struct curl_httppost *last = nullptr;
  170. // json data
  171. for (const auto &it : data) {
  172. curl_formadd(
  173. &form, &last, CURLFORM_COPYNAME, it.first.c_str(),
  174. CURLFORM_COPYCONTENTS, it.second.c_str(), CURLFORM_END
  175. );
  176. }
  177. // image
  178. curl_formadd(
  179. &form, &last, CURLFORM_COPYNAME, "image", CURLFORM_BUFFER, "image.jpg",
  180. CURLFORM_BUFFERPTR, imgBuf, CURLFORM_BUFFERLENGTH, bufSize, CURLFORM_END
  181. );
  182. curl_easy_setopt(curl, CURLOPT_HTTPPOST, form);
  183. // response
  184. std::string response;
  185. curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, onPostResponse);
  186. curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
  187. CURLcode res = curl_easy_perform(curl);
  188. if (res == CURLE_OPERATION_TIMEDOUT) {
  189. Log(Warn, "Connection Timeout");
  190. } else if (res == CURLE_OK) {
  191. long code;
  192. curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code);
  193. if (code == 200) {
  194. Log(Trace, "upload success with: %s", response.c_str());
  195. } else {
  196. Log(Warn, "upload fail with: code[%ld], msg: %s", code, response.c_str());
  197. }
  198. } else {
  199. Log(Error, "HTTP request failed: %s", curl_easy_strerror(res));
  200. }
  201. curl_easy_cleanup(curl);
  202. curl_formfree(form);
  203. }
  204. }