influxdb.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. /*
  2. influxdb-cpp -- 💜 C++ client for InfluxDB.
  3. Copyright (c) 2010-2018 <http://ez8.co> <orca.zhang@yahoo.com>
  4. This library is released under the MIT License.
  5. Please see LICENSE file or visit https://github.com/orca-zhang/influxdb-cpp for details.
  6. */
  7. #include <sstream>
  8. #include <cstring>
  9. #include <cstdio>
  10. #ifdef _WIN32
  11. #define NOMINMAX
  12. #include <windows.h>
  13. #include <algorithm>
  14. #pragma comment(lib, "ws2_32")
  15. typedef struct iovec { void* iov_base; size_t iov_len; } iovec;
  16. inline __int64 writev(int sock, struct iovec* iov, int cnt) {
  17. __int64 r = send(sock, (const char*)iov->iov_base, iov->iov_len, 0);
  18. return (r < 0 || cnt == 1) ? r : r + writev(sock, iov + 1, cnt - 1);
  19. }
  20. #else
  21. #include <unistd.h>
  22. #include <sys/types.h>
  23. #include <sys/socket.h>
  24. #include <sys/uio.h>
  25. #include <netinet/in.h>
  26. #include <arpa/inet.h>
  27. #define closesocket close
  28. #endif
  29. namespace influxdb_cpp {
  30. struct server_info {
  31. std::string host_;
  32. int port_;
  33. std::string db_;
  34. std::string usr_;
  35. std::string pwd_;
  36. server_info(const std::string& host, int port, const std::string& db = "", const std::string& usr = "", const std::string& pwd = "")
  37. : host_(host), port_(port), db_(db), usr_(usr), pwd_(pwd) {}
  38. };
  39. namespace detail {
  40. struct meas_caller;
  41. struct tag_caller;
  42. struct field_caller;
  43. struct ts_caller;
  44. struct inner {
  45. static int http_request(const char*, const char*, const std::string&, const std::string&, const server_info&, std::string*);
  46. static inline unsigned char to_hex(unsigned char x) { return x > 9 ? x + 55 : x + 48; }
  47. static void url_encode(std::string& out, const std::string& src);
  48. };
  49. }
  50. inline int query(std::string& resp, const std::string& query, const server_info& si) {
  51. std::string qs("&q=");
  52. detail::inner::url_encode(qs, query);
  53. return detail::inner::http_request("GET", "query", qs, "", si, &resp);
  54. }
  55. inline int create_db(std::string& resp, const std::string& db_name, const server_info& si) {
  56. std::string qs("&q=create+database+");
  57. detail::inner::url_encode(qs, db_name);
  58. return detail::inner::http_request("POST", "query", qs, "", si, &resp);
  59. }
  60. struct builder {
  61. detail::tag_caller& meas(const std::string& m) {
  62. lines_.imbue(std::locale("C"));
  63. lines_.clear();
  64. return _m(m);
  65. }
  66. protected:
  67. detail::tag_caller& _m(const std::string& m) {
  68. _escape(m, ", ");
  69. return (detail::tag_caller&)*this;
  70. }
  71. detail::tag_caller& _t(const std::string& k, const std::string& v) {
  72. lines_ << ',';
  73. _escape(k, ",= ");
  74. lines_ << '=';
  75. _escape(v, ",= ");
  76. return (detail::tag_caller&)*this;
  77. }
  78. detail::field_caller& _f_s(char delim, const std::string& k, const std::string& v) {
  79. lines_ << delim;
  80. _escape(k, ",= ");
  81. lines_ << "=\"";
  82. _escape(v, "\"");
  83. lines_ << '\"';
  84. return (detail::field_caller&)*this;
  85. }
  86. detail::field_caller& _f_i(char delim, const std::string& k, long long v) {
  87. lines_ << delim;
  88. _escape(k, ",= ");
  89. lines_ << '=';
  90. lines_ << v << 'i';
  91. return (detail::field_caller&)*this;
  92. }
  93. detail::field_caller& _f_f(char delim, const std::string& k, double v, int prec) {
  94. lines_ << delim;
  95. _escape(k, ",= ");
  96. lines_.precision(prec);
  97. lines_ << '=' << v;
  98. return (detail::field_caller&)*this;
  99. }
  100. detail::field_caller& _f_b(char delim, const std::string& k, bool v) {
  101. lines_ << delim;
  102. _escape(k, ",= ");
  103. lines_ << '=' << (v ? 't' : 'f');
  104. return (detail::field_caller&)*this;
  105. }
  106. detail::ts_caller& _ts(long long ts) {
  107. lines_ << ' ' << ts;
  108. return (detail::ts_caller&)*this;
  109. }
  110. int _post_http(const server_info& si, std::string* resp) {
  111. return detail::inner::http_request("POST", "write", "", lines_.str(), si, resp);
  112. }
  113. int _send_udp(const std::string& host, int port) {
  114. int sock, ret = 0;
  115. struct sockaddr_in addr;
  116. addr.sin_family = AF_INET;
  117. addr.sin_port = htons(port);
  118. if((addr.sin_addr.s_addr = inet_addr(host.c_str())) == INADDR_NONE) return -1;
  119. if((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) return -2;
  120. lines_ << '\n';
  121. if(sendto(sock, &lines_.str()[0], lines_.str().length(), 0, (struct sockaddr *)&addr, sizeof(addr)) < (int)lines_.str().length())
  122. ret = -3;
  123. closesocket(sock);
  124. return ret;
  125. }
  126. void _escape(const std::string& src, const char* escape_seq) {
  127. size_t pos = 0, start = 0;
  128. while((pos = src.find_first_of(escape_seq, start)) != std::string::npos) {
  129. lines_.write(src.c_str() + start, pos - start);
  130. lines_ << '\\' << src[pos];
  131. start = ++pos;
  132. }
  133. lines_.write(src.c_str() + start, src.length() - start);
  134. }
  135. std::stringstream lines_;
  136. };
  137. namespace detail {
  138. struct tag_caller : public builder {
  139. detail::tag_caller& tag(const std::string& k, const std::string& v) { return _t(k, v); }
  140. detail::field_caller& field(const std::string& k, const std::string& v) { return _f_s(' ', k, v); }
  141. detail::field_caller& field(const std::string& k, bool v) { return _f_b(' ', k, v); }
  142. detail::field_caller& field(const std::string& k, short v) { return _f_i(' ', k, v); }
  143. detail::field_caller& field(const std::string& k, int v) { return _f_i(' ', k, v); }
  144. detail::field_caller& field(const std::string& k, long v) { return _f_i(' ', k, v); }
  145. detail::field_caller& field(const std::string& k, long long v) { return _f_i(' ', k, v); }
  146. detail::field_caller& field(const std::string& k, double v, int prec = 2) { return _f_f(' ', k, v, prec); }
  147. private:
  148. detail::tag_caller& meas(const std::string& m);
  149. };
  150. struct ts_caller : public builder {
  151. detail::tag_caller& meas(const std::string& m) { lines_ << '\n'; return _m(m); }
  152. int post_http(const server_info& si, std::string* resp = NULL) { return _post_http(si, resp); }
  153. int send_udp(const std::string& host, int port) { return _send_udp(host, port); }
  154. };
  155. struct field_caller : public ts_caller {
  156. detail::field_caller& field(const std::string& k, const std::string& v) { return _f_s(',', k, v); }
  157. detail::field_caller& field(const std::string& k, bool v) { return _f_b(',', k, v); }
  158. detail::field_caller& field(const std::string& k, short v) { return _f_i(',', k, v); }
  159. detail::field_caller& field(const std::string& k, int v) { return _f_i(',', k, v); }
  160. detail::field_caller& field(const std::string& k, long v) { return _f_i(',', k, v); }
  161. detail::field_caller& field(const std::string& k, long long v) { return _f_i(',', k, v); }
  162. detail::field_caller& field(const std::string& k, double v, int prec = 2) { return _f_f(',', k, v, prec); }
  163. detail::ts_caller& timestamp(unsigned long long ts) { return _ts(ts); }
  164. };
  165. inline void inner::url_encode(std::string& out, const std::string& src) {
  166. size_t pos = 0, start = 0;
  167. while((pos = src.find_first_not_of("abcdefghijklmnopqrstuvwxyqABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~", start)) != std::string::npos) {
  168. out.append(src.c_str() + start, pos - start);
  169. if(src[pos] == ' ')
  170. out += "+";
  171. else {
  172. out += '%';
  173. out += to_hex((unsigned char)src[pos] >> 4);
  174. out += to_hex((unsigned char)src[pos] & 0xF);
  175. }
  176. start = ++pos;
  177. }
  178. out.append(src.c_str() + start, src.length() - start);
  179. }
  180. inline int inner::http_request(const char* method, const char* uri,
  181. const std::string& querystring, const std::string& body, const server_info& si, std::string* resp) {
  182. std::string header;
  183. struct iovec iv[2];
  184. struct sockaddr_in addr;
  185. int sock, ret_code = 0, content_length = 0, len = 0;
  186. char ch;
  187. unsigned char chunked = 0;
  188. addr.sin_family = AF_INET;
  189. addr.sin_port = htons(si.port_);
  190. if((addr.sin_addr.s_addr = inet_addr(si.host_.c_str())) == INADDR_NONE) return -1;
  191. if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) return -2;
  192. if(connect(sock, (struct sockaddr*)(&addr), sizeof(addr)) < 0) {
  193. closesocket(sock);
  194. return -3;
  195. }
  196. header.resize(len = 0x100);
  197. for(;;) {
  198. iv[0].iov_len = snprintf(&header[0], len,
  199. "%s /%s?db=%s&u=%s&p=%s%s HTTP/1.1\r\nHost: %s\r\nContent-Length: %d\r\n\r\n",
  200. method, uri, si.db_.c_str(), si.usr_.c_str(), si.pwd_.c_str(),
  201. querystring.c_str(), si.host_.c_str(), (int)body.length());
  202. if((int)iv[0].iov_len >= len)
  203. header.resize(len *= 2);
  204. else
  205. break;
  206. }
  207. iv[0].iov_base = &header[0];
  208. iv[1].iov_base = (void*)&body[0];
  209. iv[1].iov_len = body.length();
  210. if(writev(sock, iv, 2) < (int)(iv[0].iov_len + iv[1].iov_len)) {
  211. ret_code = -6;
  212. goto END;
  213. }
  214. iv[0].iov_len = len;
  215. #define _NO_MORE() (len >= (int)iv[0].iov_len && \
  216. (iv[0].iov_len = recv(sock, &header[0], header.length(), len = 0)) == size_t(-1))
  217. #define _GET_NEXT_CHAR() (ch = _NO_MORE() ? 0 : header[len++])
  218. #define _LOOP_NEXT(statement) for(;;) { if(!(_GET_NEXT_CHAR())) { ret_code = -7; goto END; } statement }
  219. #define _UNTIL(c) _LOOP_NEXT( if(ch == c) break; )
  220. #define _GET_NUMBER(n) _LOOP_NEXT( if(ch >= '0' && ch <= '9') n = n * 10 + (ch - '0'); else break; )
  221. #define _GET_CHUNKED_LEN(n, c) _LOOP_NEXT( if(ch >= '0' && ch <= '9') n = n * 16 + (ch - '0'); \
  222. else if(ch >= 'A' && ch <= 'F') n = n * 16 + (ch - 'A') + 10; \
  223. else if(ch >= 'a' && ch <= 'f') n = n * 16 + (ch - 'a') + 10; else {if(ch != c) { ret_code = -8; goto END; } break;} )
  224. #define _(c) if((_GET_NEXT_CHAR()) != c) break;
  225. #define __(c) if((_GET_NEXT_CHAR()) != c) { ret_code = -9; goto END; }
  226. if(resp) resp->clear();
  227. _UNTIL(' ')_GET_NUMBER(ret_code)
  228. for(;;) {
  229. _UNTIL('\n')
  230. switch(_GET_NEXT_CHAR()) {
  231. case 'C':_('o')_('n')_('t')_('e')_('n')_('t')_('-')
  232. _('L')_('e')_('n')_('g')_('t')_('h')_(':')_(' ')
  233. _GET_NUMBER(content_length)
  234. break;
  235. case 'T':_('r')_('a')_('n')_('s')_('f')_('e')_('r')_('-')
  236. _('E')_('n')_('c')_('o')_('d')_('i')_('n')_('g')_(':')
  237. _(' ')_('c')_('h')_('u')_('n')_('k')_('e')_('d')
  238. chunked = 1;
  239. break;
  240. case '\r':__('\n')
  241. switch(chunked) {
  242. do {__('\r')__('\n')
  243. case 1:
  244. _GET_CHUNKED_LEN(content_length, '\r')__('\n')
  245. if(!content_length) {
  246. __('\r')__('\n')
  247. goto END;
  248. }
  249. case 0:
  250. while(content_length > 0 && !_NO_MORE()) {
  251. content_length -= (iv[1].iov_len = std::min(content_length, (int)iv[0].iov_len - len));
  252. if(resp) resp->append(&header[len], iv[1].iov_len);
  253. len += iv[1].iov_len;
  254. }
  255. } while(chunked);
  256. }
  257. goto END;
  258. }
  259. if(!ch) {
  260. ret_code = -10;
  261. goto END;
  262. }
  263. }
  264. ret_code = -11;
  265. END:
  266. closesocket(sock);
  267. return ret_code / 100 == 2 ? 0 : ret_code;
  268. #undef _NO_MORE
  269. #undef _GET_NEXT_CHAR
  270. #undef _LOOP_NEXT
  271. #undef _UNTIL
  272. #undef _GET_NUMBER
  273. #undef _GET_CHUNKED_LEN
  274. #undef _
  275. #undef __
  276. }
  277. }
  278. }