dodo  0.0.1
A C++ library to create containerized Linux services
util.hpp
Go to the documentation of this file.
1 /*
2  * This file is part of the dodo library (https://github.com/jmspit/dodo).
3  * Copyright (c) 2019 Jan-Marten Spit.
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, version 3.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 /**
19  * @file util.hpp
20  * Defines utilities.
21  */
22 
23 #ifndef common_util_hpp
24 #define common_util_hpp
25 
26 #include <chrono>
27 #include <string>
28 #include <ostream>
29 #include <regex>
30 #include <set>
31 #include <sstream>
32 #include <vector>
33 #include "buildenv.hpp"
34 #include <sys/time.h>
35 
36 #include <yaml-cpp/yaml.h>
37 #include <openssl/ssl.h>
38 #include <openssl/err.h>
39 
40 namespace dodo::common {
41 
42  void dumpBinaryData( std::ostream &out, const std::string &s, size_t width );
43 
44  /**
45  * StopWatch timing class.
46  * @code
47  * StopWatch sw;
48  * sw.start();
49  * ...
50  * sw.stop();
51  * double seconds = sw.getElapsedSecond();
52  * @endcode
53  */
54  class StopWatch {
55  public:
56 
57  /**
58  * Construct a StopWatch. The start time is taken here, or can be reset by calling start().
59  */
61  stop_ = std::chrono::high_resolution_clock::now() - std::chrono::hours(24);
62  start_ = std::chrono::high_resolution_clock::now();
63  };
64 
65  /**
66  * Start the stopwatch. If calling start() is omitted,
67  * start_ is set to the time StopWatch::StopWatch() was called.
68  */
69  void start() {
70  stop_ = std::chrono::high_resolution_clock::now() - std::chrono::hours(24);
71  start_ = std::chrono::high_resolution_clock::now();
72  }
73 
74  /**
75  * Stop the stopwatch.
76  * @return the elapsed time in seconds.
77  */
78  double stop() { stop_ = std::chrono::high_resolution_clock::now(); return getElapsedSeconds(); }
79 
80  /**
81  * Stop the stopwatch, start the Stopwatch again and return the elapsed time since previous start.
82  * @return the elapsed time in seconds.
83  */
84  double restart() { double t = stop(); start(); return t; };
85 
86  /**
87  * Return the number of seconds between
88  * - start() and stop() calls
89  * - start() and time of this call
90  * - StopWatch constructor and time of this call.
91  * @return The number of seconds.
92  */
93  double getElapsedSeconds() const {
94  std::chrono::duration<double> diff;
95  if ( stop_ < start_ ) {
96  diff = std::chrono::high_resolution_clock::now() - start_;
97  } else {
98  diff = stop_ - start_;
99  }
100  return diff.count();
101  };
102 
103  private:
104  /** Start time */
105  std::chrono::time_point<std::chrono::high_resolution_clock> start_;
106  /** Stop time */
107  std::chrono::time_point<std::chrono::high_resolution_clock> stop_;
108 
109  };
110 
111 
112  /**
113  * Read from a file, expecting it to contain a (signed) int.
114  * @param file The file name.
115  * @param i The int read.
116  * @return False if the read or conversion failed.
117  */
118  bool fileReadInt( const std::string &file, int &i );
119 
120  /**
121  * Return difference in seconds as a double. t2 must be > t1 for the return value to be positive.
122  * @param t1 The earlier time.
123  * @param t2 The later time.
124  * @return the difference in seconds from t1 to t2.
125  */
126  inline double getSecondDiff( struct timeval& t1, struct timeval &t2 ) {
127  return (double)t2.tv_sec - (double)t1.tv_sec + ( (double)t2.tv_usec - (double)t1.tv_usec ) / 1.0E6;
128  }
129 
130  /**
131  * Split a string into substrings.
132  * @param src The string to split from.
133  * @param delimiter The delimiter to use.
134  * @return A vector of strings.
135  */
136  inline std::vector<std::string> split( const std::string &src, char delimiter = ' ' ) {
137  std::vector<std::string> result;
138  std::istringstream is(src);
139  std::string s;
140  while ( getline( is, s, delimiter ) ) {
141  result.push_back( s );
142  }
143  return result;
144  }
145 
146  /**
147  * Split a string into substrings by delimiter - unless the delimiter is escaped.
148  * Passing ( 'one:two$:three', '$', ':' ) splits into ['one','two:three'].
149  * Passing ( 'one:t$$wo:three', '$', ':' ) splits into ['one','t$$wo','three'].
150  * So the escape character only has effect when followed by a delimiter, otherwise
151  * taken as input.
152  * @param src The string to split from.
153  * @param escape The escape characters to use
154  * @param delimiter The delimiter to use.
155  * @return A vector of strings.
156  */
157  inline std::vector<std::string> escapedSplit( const std::string &src, std::set<char> escape, char delimiter = ' ' ) {
158  enum State { stInit, stEscape, stInput };
159  std::vector<std::string> result;
160  std::stringstream tmp;
161  State state = stInit;
162  for ( auto c : src ) {
163  if ( escape.find(c) != escape.end() ) {
164  state = stEscape;
165  } else if ( c == delimiter ) {
166  if ( state != stEscape ) {
167  result.push_back( tmp.str() );
168  tmp.str("");
169  state = stInput;
170  } else {
171  tmp << c;
172  state = stInput;
173  }
174  } else {
175  tmp << c;
176  }
177  }
178  if ( tmp.str().length() > 0 ) result.push_back( tmp.str() );
179  return result;
180  }
181 
182  /**
183  * Convert the data contents of an OpenSSL BIO to a std::string.
184  * @param bio The source BIO.
185  * @return The string representation of the BIO contents.
186  */
187  std::string bio2String( BIO* bio );
188 
189  /**
190  * Write OpenSSL errors occurred in this thread to ostream, and clear their error state.
191  * @param out The std::ostream to write to.
192  * @param terminator The char to use to separate lines.
193  * @return The number of SSL errors written.
194  */
195  size_t writeSSLErrors( std::ostream& out, char terminator );
196 
197  /**
198  * Get all OpenSSL errors as a single string, and clear their error state.
199  * @param terminator The terminator character for a single error line. If 0, no character will be appended.
200  * @return The string.
201  * @see writeSSLErrors( ostream& out)
202  */
203  std::string getSSLErrors( char terminator );
204 
205  /**
206  * Read the file as a single string.
207  * @throw Oops when the file cannot be read.
208  * @param filename the file to read from.
209  * @return the file contents as a string.
210  */
211  std::string fileReadString( const std::string &filename );
212 
213  /**
214  * Read the file as vector of strings.
215  * @throw Oops when the file cannot be read.
216  * @param filename the file to read from.
217  * @return the file as a vector of strings
218  */
219  std::vector<std::string> fileReadStrings( const std::string &filename );
220 
221  /**
222  * Read the file as vector of strings, return only regexp matches
223  * @throw Oops when the file cannot be read.
224  * @param filename the file to read from.
225  * @param exp the regex that must match.
226  * @return the file as a vector of strings.
227  */
228  std::vector<std::string> fileReadStrings( const std::string &filename, const std::regex& exp );
229 
230  /**
231  * Return true when the file exists and the calling user has read access
232  * @param path The path to the file.
233  * @return True when the file exists and can be read.
234  */
235  bool fileReadAccess( const std::string& path );
236 
237  /**
238  * Return true when the directory exists
239  * @param path The path to the directory.
240  * @return True when the directory exists.
241  */
242  bool directoryExists( const std::string &path );
243 
244  /**
245  * Return true when the directory exists and is writable to the caller.
246  * @param path The path to the directory.
247  * @return True when the directory exists and is writable to the caller.
248  */
249  bool directoryWritable( const std::string &path );
250 
251  /**
252  * Return true when the free space could be determined, and set in avail.
253  * @param path The path on which to check.
254  * @param avail The available free space.
255  * @return False if the free space could not be determined (for example, when the file does not exist).
256  */
257  bool availableFileSpace( const std::string &path, size_t &avail );
258 
259  /**
260  * Return the size of the file.
261  * If the file does not exist or is otherwise inaccessible, returns 0.
262  * @param path The path of the file.
263  * @return The file size
264  */
265  size_t getFileSize( const std::string &path );
266 
267  /**
268  * Return a datetime string in UTC (2020-07-01T20:14:36.442929Z)
269  * @param tv The tv time struct.
270  * @return The formatted datetime.
271  */
272  std::string formatDateTimeUTC( const struct timeval &tv );
273 
274  /**
275  * Escape a JSOn string.
276  * @param s The JSON string to escape.
277  * @return The escaped string.
278  */
279  std::string escapeJSON( const std::string &s );
280 
281  /**
282  * Template function to check existence and read YAML values of arbitrary type. The key-value
283  * pair must must exist under node.
284  * @param node The YAML::Node containing the key-value pair
285  * @param key The YAML::Node name.
286  * @return the value of type T
287  * @throw common::Exception when the node does not exist.
288  */
289  template <typename T> T YAML_read_key( const YAML::Node &node, const std::string& key );
290 
291  /**
292  * Template function to check existence and read YAML values of arbitrary type. The key-value
293  * pair must must exist under node.
294  * @param node The YAML::Node containing the key-value pair
295  * @param key The YAML::Node name.
296  * @param default_value The default value to assign when the key is missing
297  * @return the value of type T
298  */
299  template <typename T> T YAML_read_key_default( const YAML::Node &node,
300  const std::string& key,
301  const T& default_value );
302 
303 }
304 
305 #endif
dodo::common::split
std::vector< std::string > split(const std::string &src, char delimiter=' ')
Split a string into substrings.
Definition: util.hpp:136
dodo::common::escapeJSON
std::string escapeJSON(const std::string &s)
Escape a JSOn string.
Definition: util.cpp:197
dodo::common::fileReadInt
bool fileReadInt(const std::string &file, int &i)
Read from a file, expecting it to contain a (signed) int.
Definition: util.cpp:39
dodo::common::fileReadString
std::string fileReadString(const std::string &filename)
Read the file as a single string.
Definition: util.cpp:161
dodo::common::escapedSplit
std::vector< std::string > escapedSplit(const std::string &src, std::set< char > escape, char delimiter=' ')
Split a string into substrings by delimiter - unless the delimiter is escaped.
Definition: util.hpp:157
dodo::common::directoryExists
bool directoryExists(const std::string &path)
Return true when the directory exists.
Definition: util.cpp:230
dodo::common::StopWatch::start_
std::chrono::time_point< std::chrono::high_resolution_clock > start_
Start time.
Definition: util.hpp:101
dodo::common::writeSSLErrors
size_t writeSSLErrors(std::ostream &out, char terminator)
Write OpenSSL errors occurred in this thread to ostream, and clear their error state.
Definition: util.cpp:140
dodo::common::StopWatch::start
void start()
Start the stopwatch.
Definition: util.hpp:69
dodo::common::StopWatch::StopWatch
StopWatch()
Construct a StopWatch.
Definition: util.hpp:60
dodo::common::StopWatch::stop_
std::chrono::time_point< std::chrono::high_resolution_clock > stop_
Stop time.
Definition: util.hpp:107
dodo::common::dumpBinaryData
void dumpBinaryData(std::ostream &out, const std::string &s, size_t width)
Dump binary data to a std::ostream.
Definition: util.cpp:105
dodo::common::StopWatch
StopWatch timing class.
Definition: util.hpp:54
dodo::common::StopWatch::stop
double stop()
Stop the stopwatch.
Definition: util.hpp:78
dodo::common::availableFileSpace
bool availableFileSpace(const std::string &path, size_t &avail)
Return true when the free space could be determined, and set in avail.
Definition: util.cpp:249
dodo::common::bio2String
std::string bio2String(BIO *bio)
Convert the data contents of an OpenSSL BIO to a std::string.
Definition: util.cpp:132
dodo::common::YAML_read_key_default
T YAML_read_key_default(const YAML::Node &node, const std::string &key, const T &default_value)
Template function to check existence and read YAML values of arbitrary type.
Definition: util.cpp:331
dodo::common::getFileSize
size_t getFileSize(const std::string &path)
Return the size of the file.
Definition: util.cpp:256
dodo::common::getSSLErrors
std::string getSSLErrors(char terminator)
Get all OpenSSL errors as a single string, and clear their error state.
Definition: util.cpp:154
dodo::common::getSecondDiff
double getSecondDiff(struct timeval &t1, struct timeval &t2)
Return difference in seconds as a double.
Definition: util.hpp:126
dodo::common
Common and utility interfaces.
Definition: application.hpp:29
dodo::common::YAML_read_key
T YAML_read_key(const YAML::Node &node, const std::string &key)
Template function to check existence and read YAML values of arbitrary type.
Definition: util.cpp:276
dodo::common::StopWatch::getElapsedSeconds
double getElapsedSeconds() const
Return the number of seconds between.
Definition: util.hpp:93
dodo::common::fileReadStrings
std::vector< std::string > fileReadStrings(const std::string &filename)
Read the file as vector of strings.
Definition: util.cpp:170
dodo::common::formatDateTimeUTC
std::string formatDateTimeUTC(const struct timeval &tv)
Return a datetime string in UTC (2020-07-01T20:14:36.442929Z)
Definition: util.cpp:262
dodo::common::fileReadAccess
bool fileReadAccess(const std::string &path)
Return true when the file exists and the calling user has read access.
Definition: util.cpp:220
dodo::common::directoryWritable
bool directoryWritable(const std::string &path)
Return true when the directory exists and is writable to the caller.
Definition: util.cpp:239
dodo::common::StopWatch::restart
double restart()
Stop the stopwatch, start the Stopwatch again and return the elapsed time since previous start.
Definition: util.hpp:84