diff --git a/CHANGELOG.md b/CHANGELOG.md index ce92a154..faa6552a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - The `properties` list implements a const iterator - Added a `to_string()` and `operator<<()` for reason codes. - Cleaned up and fixed a number of example apps. + - Most apps no except server URI from the command line + - 'data_publish' example uses C++17 std::filesystem for creating a file-based encrypted persistence for messages. - Reorganized the source repository - Completely reformat the sources and added a .clang-format file (a project master and a slightly-different one for headers). - Added GitHub CI Action, removing legacy Travis and Appveyor files diff --git a/examples/async_publish_time.cpp b/examples/async_publish_time.cpp index 9d6f27b0..72fbf059 100644 --- a/examples/async_publish_time.cpp +++ b/examples/async_publish_time.cpp @@ -49,6 +49,8 @@ #include #include #include // For sleep +#include +#include #include "mqtt/async_client.h" @@ -69,6 +71,14 @@ const int DELTA_MS = 100; // How many to buffer while off-line const int MAX_BUFFERED_MESSAGES = 1200; +// Atomic flag to tell the main loop to exit. +atomic quit{false}; + +// Handler for ^C (SIGINT) +void ctrlc_handler(int) { + quit = true; +} + // -------------------------------------------------------------------------- // Gets the current time as the number of milliseconds since the epoch: // like a time_t with ms resolution. @@ -130,14 +140,17 @@ int main(int argc, char* argv[]) auto top = mqtt::topic(cli, "data/time", QOS); cout << "Publishing data..." << endl; + // Install a ^C handler for user to signal when to exit + signal(SIGINT, ctrlc_handler); + + // Sync clock to start of delta period while (timestamp() % DELTA_MS != 0) ; uint64_t t = timestamp(), tlast = t, tstart = t; - top.publish(to_string(t)); - while (true) { + while (!quit) { this_thread::sleep_for(SAMPLE_PERIOD); t = timestamp(); diff --git a/examples/data_publish.cpp b/examples/data_publish.cpp index 5a3b7fe4..35a343b9 100644 --- a/examples/data_publish.cpp +++ b/examples/data_publish.cpp @@ -52,6 +52,9 @@ #include #include #include +#include +#include +#include #include "mqtt/async_client.h" @@ -77,6 +80,20 @@ const fs::path PERSIST_DIR{"persist"}; // A key for encoding the persistence data const string PERSIST_KEY{"elephant"}; +// Condition variable & flag to tell the main loop to exit. +std::condition_variable cv; +std::mutex mtx; +bool quit{false}; + +// Handler for ^C (SIGINT) +void ctrlc_handler(int) { + { + lock_guard lk(mtx); + quit = true; + } + cv.notify_one(); +} + ///////////////////////////////////////////////////////////////////////////// // Example of user-based file persistence with a simple XOR encoding scheme. @@ -108,7 +125,7 @@ class encoded_file_persistence : virtual public mqtt::iclient_persistence } // Gets the persistence file name for the supplied key. - fs::path path_name(const string& key) const { return dir_ /key; } + fs::path path_name(const string& key) const { return dir_ / key; } public: // Create the persistence object with the specified encoding key @@ -138,7 +155,10 @@ class encoded_file_persistence : virtual public mqtt::iclient_persistence // Close the persistent store that was previously opened. // Remove the persistence directory, if it's empty. - void close() override { fs::remove(dir_); } + void close() override { + fs::remove(dir_); + fs::remove(dir_.parent_path()); + } // Clears persistence, so that it no longer contains any persisted data. // Just remove all the files from the persistence directory. @@ -271,12 +291,18 @@ int main(int argc, char* argv[]) char tmbuf[32]; unsigned nsample = 0; - // The time at which to reads the next sample, starting now - auto tm = steady_clock::now(); + // Install a ^C handler for user to signal when to exit + signal(SIGINT, ctrlc_handler); + + // The steady time at which to read the next sample + auto tm = steady_clock::now() + 250ms; + + // Pace the sampling by letting the condition variable time out + // periodically. When 'cv' is signaled, it's time to quit. + unique_lock lk(mtx); - while (true) { - // Pace the samples to the desired rate - this_thread::sleep_until(tm); + while (!cv.wait_until(lk, tm, []{ return quit; })) { + lk.unlock(); // Get a timestamp and format as a string time_t t = system_clock::to_time_t(system_clock::now()); @@ -293,6 +319,7 @@ int main(int argc, char* argv[]) top.publish(std::move(payload)); tm += PERIOD; + lk.lock(); } // Disconnect