-
Notifications
You must be signed in to change notification settings - Fork 445
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Converted 'data_publish' example to use C++17 std::filesystem
- Loading branch information
1 parent
be26343
commit 33d219a
Showing
1 changed file
with
41 additions
and
67 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,7 +26,7 @@ | |
// | ||
|
||
/******************************************************************************* | ||
* Copyright (c) 2013-2023 Frank Pagliughi <[email protected]> | ||
* Copyright (c) 2013-2024 Frank Pagliughi <[email protected]> | ||
* | ||
* All rights reserved. This program and the accompanying materials | ||
* are made available under the terms of the Eclipse Public License v2.0 | ||
|
@@ -41,15 +41,6 @@ | |
* Frank Pagliughi - initial implementation and documentation | ||
*******************************************************************************/ | ||
|
||
#if !defined(_WIN32) | ||
#include <dirent.h> | ||
#include <sys/stat.h> | ||
#include <sys/types.h> | ||
#include <unistd.h> | ||
|
||
#include <fstream> | ||
#endif | ||
|
||
#include <algorithm> | ||
#include <chrono> | ||
#include <cstdlib> | ||
|
@@ -59,30 +50,34 @@ | |
#include <random> | ||
#include <string> | ||
#include <thread> | ||
#include <filesystem> | ||
#include <fstream> | ||
|
||
#include "mqtt/async_client.h" | ||
|
||
using namespace std; | ||
using namespace std::chrono; | ||
namespace fs = std::filesystem; | ||
|
||
const std::string DFLT_SERVER_URI{"mqtt://localhost:1883"}; | ||
const std::string CLIENT_ID{"paho-cpp-data-publish"}; | ||
|
||
const string TOPIC{"data/rand"}; | ||
const int QOS = 1; | ||
|
||
// How often we output a data point | ||
const auto PERIOD = seconds(5); | ||
|
||
// The number of out-bound messages we will buffer locally when disconnected. | ||
const int MAX_BUFFERED_MSGS = 120; // 120 * 5sec => 10min off-line buffering | ||
|
||
const string PERSIST_DIR{"data-persist"}; | ||
|
||
///////////////////////////////////////////////////////////////////////////// | ||
// Top-level directory to keep persistence data | ||
const fs::path PERSIST_DIR{"persist"}; | ||
|
||
// At some point, when the library gets updated to C++17, we can use | ||
// std::filesystem to make a portable version of this. | ||
// A key for encoding the persistence data | ||
const string PERSIST_KEY{"elephant"}; | ||
|
||
#if !defined(_WIN32) | ||
///////////////////////////////////////////////////////////////////////////// | ||
|
||
// Example of user-based file persistence with a simple XOR encoding scheme. | ||
// | ||
|
@@ -96,11 +91,10 @@ const string PERSIST_DIR{"data-persist"}; | |
// SQLite or a local key/value store like Redis. | ||
class encoded_file_persistence : virtual public mqtt::iclient_persistence | ||
{ | ||
// The name of the store | ||
// Used as the directory name | ||
string name_; | ||
// The directory for the persistence store. | ||
fs::path dir_; | ||
|
||
// A key for encoding the data | ||
// A key for encoding the data, as supplied by the user | ||
string encodeKey_; | ||
|
||
// Simple, in-place XOR encoding and decoding | ||
|
@@ -114,7 +108,7 @@ class encoded_file_persistence : virtual public mqtt::iclient_persistence | |
} | ||
|
||
// Gets the persistence file name for the supplied key. | ||
string path_name(const string& key) const { return name_ + "/" + key; } | ||
fs::path path_name(const string& key) const { return dir_ /key; } | ||
|
||
public: | ||
// Create the persistence object with the specified encoding key | ||
|
@@ -132,52 +126,43 @@ class encoded_file_persistence : virtual public mqtt::iclient_persistence | |
if (clientId.empty() || serverURI.empty()) | ||
throw mqtt::persistence_exception(); | ||
|
||
name_ = serverURI + "-" + clientId; | ||
std::replace(name_.begin(), name_.end(), ':', '-'); | ||
// Create a name for the persistence subdirectory for this client | ||
string name = serverURI + "-" + clientId; | ||
std::replace(name.begin(), name.end(), ':', '-'); | ||
|
||
dir_ = PERSIST_DIR; | ||
dir_ /= name; | ||
|
||
mkdir(name_.c_str(), S_IRWXU | S_IRWXG); | ||
fs::create_directories(dir_); | ||
} | ||
|
||
// Close the persistent store that was previously opened. | ||
// Remove the persistence directory, if it's empty. | ||
void close() override { rmdir(name_.c_str()); } | ||
void close() override { fs::remove(dir_); } | ||
|
||
// Clears persistence, so that it no longer contains any persisted data. | ||
// Just remove all the files from the persistence directory. | ||
void clear() override | ||
{ | ||
DIR* dir = opendir(name_.c_str()); | ||
if (!dir) | ||
return; | ||
|
||
dirent* next; | ||
while ((next = readdir(dir)) != nullptr) { | ||
auto fname = string(next->d_name); | ||
if (fname == "." || fname == "..") | ||
continue; | ||
string path = name_ + "/" + fname; | ||
remove(path.c_str()); | ||
// We could iterate through and remove each file, | ||
// but this does the same thing in fewer steps. | ||
if (!fs::is_empty(dir_)) { | ||
fs::remove_all(dir_); | ||
fs::create_directories(dir_); | ||
} | ||
closedir(dir); | ||
} | ||
|
||
// Returns whether or not data is persisted using the specified key. | ||
// We just look for a file in the store directory with the same name as | ||
// the key. | ||
bool contains_key(const string& key) override | ||
{ | ||
DIR* dir = opendir(name_.c_str()); | ||
if (!dir) | ||
return false; | ||
|
||
dirent* next; | ||
while ((next = readdir(dir)) != nullptr) { | ||
if (string(next->d_name) == key) { | ||
closedir(dir); | ||
return true; | ||
if (fs::exists(dir_)) { | ||
for (const auto& entry : fs::directory_iterator(dir_)) { | ||
if (entry.path().filename() == key) | ||
return true; | ||
} | ||
} | ||
closedir(dir); | ||
return false; | ||
} | ||
|
||
|
@@ -186,19 +171,12 @@ class encoded_file_persistence : virtual public mqtt::iclient_persistence | |
mqtt::string_collection keys() const override | ||
{ | ||
mqtt::string_collection ks; | ||
DIR* dir = opendir(name_.c_str()); | ||
if (!dir) | ||
return ks; | ||
|
||
dirent* next; | ||
while ((next = readdir(dir)) != nullptr) { | ||
auto fname = string(next->d_name); | ||
if (fname == "." || fname == "..") | ||
continue; | ||
ks.push_back(fname); | ||
} | ||
|
||
closedir(dir); | ||
if (fs::exists(dir_)) { | ||
for (const auto& entry : fs::directory_iterator(dir_)) { | ||
ks.push_back(entry.path().filename().string()); | ||
} | ||
} | ||
return ks; | ||
} | ||
|
||
|
@@ -255,27 +233,23 @@ class encoded_file_persistence : virtual public mqtt::iclient_persistence | |
void remove(const string& key) override | ||
{ | ||
auto path = path_name(key); | ||
::remove(path.c_str()); | ||
fs::remove(path); | ||
} | ||
}; | ||
#endif | ||
|
||
///////////////////////////////////////////////////////////////////////////// | ||
|
||
int main(int argc, char* argv[]) | ||
{ | ||
string serverURI = (argc > 1) ? string{argv[1]} : DFLT_SERVER_URI; | ||
|
||
#if defined(_WIN32) | ||
mqtt::async_client cli(serverURI, CLIENT_ID, MAX_BUFFERED_MSGS); | ||
#else | ||
encoded_file_persistence persist("elephant"); | ||
encoded_file_persistence persist{PERSIST_KEY}; | ||
|
||
mqtt::async_client cli(serverURI, CLIENT_ID, MAX_BUFFERED_MSGS, &persist); | ||
#endif | ||
|
||
auto connOpts = mqtt::connect_options_builder() | ||
.keep_alive_interval(MAX_BUFFERED_MSGS * PERIOD) | ||
.clean_session(true) | ||
.clean_session(false) | ||
.automatic_reconnect(true) | ||
.finalize(); | ||
|
||
|