aegis.cpp
 All Classes Functions Variables Typedefs Enumerations Enumerator Friends Pages
utility.hpp
1 //
2 // utility.hpp
3 // ***********
4 //
5 // Copyright (c) 2019 Sharon W (sharon at aegis dot gg)
6 //
7 // Distributed under the MIT License. (See accompanying file LICENSE)
8 //
9 
10 #pragma once
11 
12 #include "aegis/config.hpp"
13 #include <string>
14 #include <atomic>
15 #include <map>
16 #include <unordered_map>
17 #include <vector>
18 #include <string>
19 #include <iostream>
20 #include <chrono>
21 #include <sstream>
22 #include <iomanip>
23 #include <spdlog/fmt/fmt.h>
24 #include <stdint.h>
25 
26 #if defined(_WIN32)
27 #define WIN32_LEAN_AND_MEAN
28 #include <windows.h>
29 #include <psapi.h>
30 #elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__))
31 #include <unistd.h>
32 #include <sys/resource.h>
33 #if defined(__APPLE__) && defined(__MACH__)
34 #include <mach/mach.h>
35 #elif (defined(_AIX) || defined(__TOS__AIX__)) || (defined(__sun__) || defined(__sun) || defined(sun) && (defined(__SVR4) || defined(__svr4__)))
36 #include <fcntl.h>
37 #include <procfs.h>
38 #elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
39 #include <stdio.h>
40 #endif
41 #else
42 #error "Cannot define getPeakRSS( ) or getCurrentRSS( ) for an unknown OS."
43 #endif
44 
45 namespace aegis
46 {
47 
50 enum class bot_status
51 {
52  uninitialized = 0,
53  running,
54  shutdown
55 };
56 
57 enum class shard_status
58 {
59  uninitialized = 0,
60  connecting,
61  preready,
62  online,
63  queued,
64  reconnecting,
65  closing,
66  closed,
67  shutdown
68 };
69 
70 enum class heartbeat_status
71 {
72  normal,
73  waiting
74 };
75 
76 namespace utility
77 {
78 
79 template<class Func>
80 std::string perf_run(const std::string & name, Func f)
81 {
82  std::stringstream ss;
83  ss << "Running [" << name << "]\n";
84  auto n = std::chrono::steady_clock::now();
85 
86  f();
87 
88  auto n_end = std::chrono::steady_clock::now();
89 
90  ss << "Time: [" << std::chrono::duration_cast<std::chrono::microseconds>(n_end - n).count() << "us]\n";
91  return ss.str();
92 }
93 
95 
99 template<class Duration, class int_type, typename ratio = std::nano>
100 constexpr Duration to_t(const std::chrono::duration<int_type, ratio> & t)
101 {
102  return std::chrono::duration_cast<Duration>(t);
103 }
104 
106 
110 template<typename Duration, typename T = std::chrono::steady_clock::time_point>
111 constexpr Duration to_t(const T & t)
112 {
113  return std::chrono::duration_cast<Duration>(t.time_since_epoch());
114 }
115 
119 
123 template<class S, typename ratio = std::nano>
124 constexpr S to_ms(const std::chrono::duration<S, ratio> & t)
125 {
126  return to_t<std::chrono::milliseconds>(t).count();
127 }
128 
132 
136 template<typename T = std::chrono::steady_clock::time_point>
137 constexpr typename T::rep to_ms(const T & t)
138 {
139  return to_t<std::chrono::duration<typename T::rep, std::milli>>(t.time_since_epoch()).count();
140 }
141 
143 
147 inline std::chrono::system_clock::time_point from_iso8601(const std::string & _time_t)
148 {
149  std::tm tm = {};
150  std::istringstream ss(_time_t);
151  ss >> std::get_time(&tm, "%Y-%m-%dT%H:%M:%S");
152  return std::chrono::system_clock::from_time_t(std::mktime(&tm));
153 }
154 
155 inline std::string to_iso8601(std::chrono::system_clock::time_point tp)
156 {
157  auto itt = std::chrono::system_clock::to_time_t(tp);
158  std::ostringstream ss;
159  ss << std::put_time(gmtime(&itt), "%FT%TZ");
160  return ss.str();
161 }
162 
163 inline std::string to_iso8601(int64_t tp)
164 {
165  auto itt = std::chrono::system_clock::to_time_t(std::chrono::time_point<std::chrono::system_clock>(std::chrono::milliseconds(tp)));
166  std::ostringstream ss;
167  ss << std::put_time(gmtime(&itt), "%FT%TZ");
168  return ss.str();
169 }
170 
172 
176 inline std::chrono::system_clock::time_point from_http_date(const std::string & _time_t)
177 {
178  std::tm tm = {};
179  std::istringstream ss(_time_t);
180  ss >> std::get_time(&tm, "%a, %d %b %Y %T");
181  return std::chrono::system_clock::from_time_t(std::mktime(&tm));
182 }
183 //Mon, 19 Nov 2018 06:51 : 17 GMT
184 
185 inline std::string url_encode(const std::string & value)
186 {
187  std::ostringstream escaped;
188  escaped.fill('0');
189  escaped << std::hex;
190 
191  for (std::string::value_type c : value)
192  {
193  // Keep alphanumeric and other accepted characters intact
194  if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~')
195  {
196  escaped << c;
197  continue;
198  }
199 
200  // Any other characters are percent-encoded
201  escaped << std::uppercase;
202  escaped << '%' << std::setw(2) << int((unsigned char)c);
203  escaped << std::nouppercase;
204  }
205 
206  return escaped.str();
207 }
208 
209 inline std::string escape_quotes(const std::string & value)
210 {
211  std::ostringstream escaped;
212 
213  for (std::string::value_type c : value)
214  {
215  if (c == '"')
216  escaped << '\\';
217  escaped << c;
218  }
219  return escaped.str();
220 }
221 
222 inline char random_letter()
223 {
224  return (rand() % 2) ? (rand() % 26 + 'a') : (rand() % 26 + 'A');
225 }
226 
227 inline std::string random_string(const std::size_t length)
228 {
229  std::string temp;
230  temp.reserve(length);
231 
232  for (int i = 0; i < length; ++i)
233  temp.push_back(random_letter());
234 
235  return temp;
236 }
237 
238 inline std::string uptime_str(std::chrono::steady_clock::time_point _start) noexcept
239 {
240  using seconds = std::chrono::duration<int, std::ratio<1, 1>>;
241  using minutes = std::chrono::duration<int, std::ratio<60, 1>>;
242  using hours = std::chrono::duration<int, std::ratio<3600, 1>>;
243  using days = std::chrono::duration<int, std::ratio<24 * 3600, 1>>;
244 
245  std::stringstream ss;
246  std::chrono::time_point<std::chrono::steady_clock> now_t = std::chrono::steady_clock::now();
247 
248  auto time_is = now_t - _start;
249  auto d = std::chrono::duration_cast<days>(time_is).count();
250  time_is -= days(d);
251  auto h = std::chrono::duration_cast<hours>(time_is).count();
252  time_is -= hours(h);
253  auto m = std::chrono::duration_cast<minutes>(time_is).count();
254  time_is -= minutes(m);
255  auto s = std::chrono::duration_cast<seconds>(time_is).count();
256 
257  if (d)
258  ss << d << "d ";
259  if (h)
260  ss << h << "h ";
261  if (m)
262  ss << m << "m ";
263  ss << s << "s ";
264  return ss.str();
265 }
266 
267 inline std::string format_bytes(uint64_t size)
268 {
269  if ((size > 1024ull * 5) && (size < 1024ull * 1024 * 5))// over 5KB and up to 5MB show KB
270  {
271  return fmt::format("{:.3f} KB", double(size) / 1024);
272  }
273  if ((size > 1024ull * 1024 * 5) && (size < 1024ull * 1024 * 1024 * 5))// over 5MB and up to 5GB show MB
274  {
275  return fmt::format("{:.3f} MB", (double(size) / 1024) / 1024);
276  }
277  if (size > 1024ull * 1024 * 1024 * 5)// over 5GB show GB
278  {
279  return fmt::format("{:.3f} GB", ((double(size) / 1024) / 1024) / 1024);
280  }
281  return fmt::format("{} B", size);
282 }
283 
284 namespace platform
285 {
286 
289 enum class OS
290 {
291  Linux,
292  Windows32,
293  Windows64,
294  BSD,
295  iOS,
296  OSX,
297  undefined
298 };
299 
300 #if defined(__clang__) || defined(__GNUC__)
301 # if (__cplusplus >= 201703)
302 # define CXX_VERSION 17
303 # else
304 # define CXX_VERSION 14
305 # endif
306 #elif defined(AEGIS_MSVC)
307 # if _MSVC_LANG == 201703L || _HAS_CXX17 == 1
308 # define CXX_VERSION 17
309 # else
310 # define CXX_VERSION 14
311 # endif
312 #endif
313 
314 
315 #if defined(_WIN64)
316 constexpr const char * m_platform = "Windows x64";
317 constexpr OS m_os = OS::Windows64;
318 #elif defined(_WIN32)
319 constexpr const char * m_platform = "Windows x86";
320 constexpr OS m_os = OS::Windows32;
321 #elif defined(__CYGWIN__) && !defined(_WIN32)
322 constexpr const char * m_platform = "Windows (Cygwin)";
323 constexpr OS m_os = OS::undefined;
324 #elif defined(__linux__)
325 constexpr const char * m_platform = "Linux";
326 constexpr OS m_os = OS::Linux;
327 #elif defined(__unix__) || defined(__APPLE__) && defined(__MACH__)
328 #include <sys/param.h>
329 #if defined(BSD)
330 constexpr const char * m_platform = "*BSD";
331 constexpr OS m_os = OS::BSD;
332 #endif
333 #elif defined(__APPLE__) && defined(__MACH__) // Apple OSX and iOS (Darwin)
334 #include <TargetConditionals.h>
335 constexpr const char * m_platform = "OSX";
336 constexpr OS m_os = OS::Mac;
337 #else
338 constexpr const char * m_platform = "undefined";
339 constexpr OS m_os = OS::undefined;
340 #endif
341 
342 
345 inline const std::string get_platform()
346 {
347  return std::string(m_platform);
348 };
349 
350 } //platform
351 
353  /*
354  * Author: David Robert Nadeau
355  * Site: http://NadeauSoftware.com/
356  * License: Creative Commons Attribution 3.0 Unported License
357  * http://creativecommons.org/licenses/by/3.0/deed.en_US
358  */
364 size_t getPeakRSS();
365 size_t getCurrentRSS();
366 
367 inline size_t getPeakRSS()
368 {
369 #if defined(_WIN32)
370  /* Windows -------------------------------------------------- */
371  PROCESS_MEMORY_COUNTERS info;
372  GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info));
373  return (size_t)info.PeakWorkingSetSize;
374 
375 #elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__))
376  /* BSD, Linux, and OSX -------------------------------------- */
377  struct rusage rusage;
378  getrusage(RUSAGE_SELF, &rusage);
379 #if defined(__APPLE__) && defined(__MACH__)
380  return (size_t)rusage.ru_maxrss;
381 #else
382  return (size_t)(rusage.ru_maxrss * 1024L);
383 #endif
384 
385 #else
386  /* Unknown OS ----------------------------------------------- */
387  return (size_t)0L; /* Unsupported. */
388 #endif
389 }
390 
395 inline size_t getCurrentRSS()
396 {
397 #if defined(_WIN32)
398  /* Windows -------------------------------------------------- */
399  PROCESS_MEMORY_COUNTERS info;
400  GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info));
401  return (size_t)info.WorkingSetSize;
402 
403 #elif defined(__APPLE__) && defined(__MACH__)
404  /* OSX ------------------------------------------------------ */
405  struct mach_task_basic_info info;
406  mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT;
407  if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO,
408  (task_info_t)&info, &infoCount) != KERN_SUCCESS)
409  return (size_t)0L; /* Can't access? */
410  return (size_t)info.resident_size;
411 
412 #elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
413  /* Linux ---------------------------------------------------- */
414  long rss = 0L;
415  FILE* fp = NULL;
416  if ((fp = fopen("/proc/self/statm", "r")) == NULL)
417  return (size_t)0L; /* Can't open? */
418  if (fscanf(fp, "%*s%ld", &rss) != 1)
419  {
420  fclose(fp);
421  return (size_t)0L; /* Can't read? */
422  }
423  fclose(fp);
424  return (size_t)rss * (size_t)sysconf(_SC_PAGESIZE);
425 
426 #else
427  /* AIX, BSD, Solaris, and Unknown OS ------------------------ */
428  return (size_t)0L; /* Unsupported. */
429 #endif
430 }
432 
433 }
434 
435 }