Skip to content

Commit

Permalink
Added User ID to telemetry
Browse files Browse the repository at this point in the history
  • Loading branch information
mondus committed Nov 20, 2024
1 parent c347616 commit 52f1596
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 2 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ Information is collected when a simulation, ensemble or test suite run have comp
The [TelemetryDeck](https://telemetrydeck.com/) service is used to store telemetry data.
All data is sent to their API endpoint of https://nom.telemetrydeck.com/v1/ via https. For more details please review the [TelmetryDeck privacy policy](https://telemetrydeck.com/privacy/).

We do not collect any personal data such as usernames, email addresses or machine identifiers.
We do not collect any personal data such as usernames, email addresses or hardware identifiers but we do generate a random user identifier. This identifier is salted and hashed by Telemetry deck.

More information can be found in the [FLAMEGPU documentation](https://docs.flamegpu.com/guide/telemetry).

Expand Down
18 changes: 18 additions & 0 deletions include/flamegpu/io/Telemetry.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,24 @@ static void encourageUsage();
* @return if telemetry is currently in test mode or not.
*/
static bool isTestMode();

/**
* Gets a cross platform location for storing user configuration data. Required to store a per user Id. On windows this uses the AppData folder (CSIDL_APPDATA) and in Linux this uses XDG_CONFIG_HOME.
* @return Root directory for storing configuration files
*/
static std::string getConfigDirectory();

/**
* Generates a randomised 36 character alphanumeric string for use as a User Id.
* @return A 36 character randomised alphanumeric string
*/
static std::string generateRandomId();

/**
* Obtains a unique user Id. If a configuration file (flamegpu_user.cfg) exists this will be loaded from disk otherwise it will be generated and stored in the configuration location. If the configuration location is not writeable a new user Id will be generated each time. The user Id will be further obfuscated by Telemetry Deck which will salt and hash the Id.
* @return A 36 character randomised alphanumeric string representing a unique user Id
*/
static std::string getUserId();
};
} // namespace io
} // namespace flamegpu
Expand Down
96 changes: 95 additions & 1 deletion src/flamegpu/io/Telemetry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,22 @@
#include <memory>
#include <array>
#include <iostream>
#include <fstream>
#include <filesystem>
#include <cstdio>
#include <cctype>
#include <sstream>
#include <string>
#include <map>
#include <random>
#ifdef _WIN32
#include <windows.h>
#include <shlobj.h>
#else
#include <cstdlib>

Check failure on line 21 in src/flamegpu/io/Telemetry.cpp

View workflow job for this annotation

GitHub Actions / cpplint (11.8, ubuntu-20.04)

"cstdlib" already included at /home/runner/work/FLAMEGPU2/FLAMEGPU2/src/flamegpu/io/Telemetry.cpp:3
#include <sys/types.h>
#include <pwd.h>
#endif

#include "flamegpu/version.h"

Expand Down Expand Up @@ -159,7 +170,7 @@ std::string Telemetry::generateData(std::string event_name, std::map<std::string
// check ENV for test variable FLAMEGPU_TEST_ENVIRONMENT
std::string testmode = isTestMode() ? "true" : "false";
std::string appID = TELEMETRY_APP_ID;
std::string telemetryRandomID = flamegpu::TELEMETRY_RANDOM_ID;
std::string telemetryRandomID = Telemetry::getUserId(); // Obtain a unique user ID

Check failure on line 173 in src/flamegpu/io/Telemetry.cpp

View workflow job for this annotation

GitHub Actions / cpplint (11.8, ubuntu-20.04)

At least two spaces is best between code and comments

// Differentiate pyflamegpu in the payload via the SWIG compiler macro, which we only define when building for pyflamegpu.
// A user could potentially static link against a build using that macro, but that's not a use-case we are currently concerned with.
Expand All @@ -178,6 +189,7 @@ std::string Telemetry::generateData(std::string event_name, std::map<std::string
payload_items["appVersionPatch"] = std::to_string(flamegpu::VERSION_PATCH);
payload_items["appVersionPreRelease"] = flamegpu::VERSION_PRERELEASE;
payload_items["buildNumber"] = flamegpu::VERSION_BUILDMETADATA; // e.g. '0553592f' (graphed in Telemetry deck)
payload_items["buildID"] = flamegpu::TELEMETRY_RANDOM_ID; // e.g. 'e7e0fe30325c83a3ad52e2cb2180e50979d3e6bcb0692789977a06ad09889843' (ID generated a cmake time)

// OS
#ifdef _WIN32
Expand Down Expand Up @@ -291,5 +303,87 @@ void Telemetry::encourageUsage() {
}
}

std::string Telemetry::getConfigDirectory() {
#ifdef _WIN32
char path[MAX_PATH];
if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_APPDATA, NULL, 0, path))) {
return std::string(path);
}
throw std::runtime_error("Unable to retrieve config directory on Windows");
#else
const char* configHome = std::getenv("XDG_CONFIG_HOME");
if (configHome) {
return std::string(configHome);
}
const char* home = std::getenv("HOME");
if (home) {
return std::string(home) + "/.config";
}
else {
struct passwd* pwd = getpwuid(getuid());

Check failure on line 323 in src/flamegpu/io/Telemetry.cpp

View workflow job for this annotation

GitHub Actions / cpplint (11.8, ubuntu-20.04)

Consider using getpwuid_r(...) instead of getpwuid(...) for improved thread safety.

Check failure on line 323 in src/flamegpu/io/Telemetry.cpp

View workflow job for this annotation

GitHub Actions / build (11.0, 3.12, OFF, Release, ubuntu-20.04)

‘getuid’ was not declared in this scope

Check failure on line 323 in src/flamegpu/io/Telemetry.cpp

View workflow job for this annotation

GitHub Actions / build (11.2, 3.12, OFF, Release, ubuntu-20.04)

‘getuid’ was not declared in this scope; did you mean ‘getpwuid’?

Check failure on line 323 in src/flamegpu/io/Telemetry.cpp

View workflow job for this annotation

GitHub Actions / build (11.8, 3.12, OFF, Release, ubuntu-22.04)

‘getuid’ was not declared in this scope; did you mean ‘getpwuid’?

Check failure on line 323 in src/flamegpu/io/Telemetry.cpp

View workflow job for this annotation

GitHub Actions / build (12.0, 3.12, OFF, Release, ubuntu-20.04)

‘getuid’ was not declared in this scope; did you mean ‘getpwuid’?

Check failure on line 323 in src/flamegpu/io/Telemetry.cpp

View workflow job for this annotation

GitHub Actions / build (12.0, 3.12, OFF, Release, ubuntu-22.04)

‘getuid’ was not declared in this scope; did you mean ‘getpwuid’?

Check failure on line 323 in src/flamegpu/io/Telemetry.cpp

View workflow job for this annotation

GitHub Actions / build (11.8, 3.12, ON, Release, ubuntu-22.04)

‘getuid’ was not declared in this scope; did you mean ‘getpwuid’?

Check failure on line 323 in src/flamegpu/io/Telemetry.cpp

View workflow job for this annotation

GitHub Actions / build (12.6, 3.12, OFF, Beltsoff, ubuntu-22.04)

‘getuid’ was not declared in this scope; did you mean ‘getpwuid’?

Check failure on line 323 in src/flamegpu/io/Telemetry.cpp

View workflow job for this annotation

GitHub Actions / build (12.6, 3.12, OFF, Release, ubuntu-22.04)

‘getuid’ was not declared in this scope; did you mean ‘getpwuid’?

Check failure on line 323 in src/flamegpu/io/Telemetry.cpp

View workflow job for this annotation

GitHub Actions / build (11.2, 3.12, ON, Release, ubuntu-20.04)

‘getuid’ was not declared in this scope; did you mean ‘getpwuid’?

Check failure on line 323 in src/flamegpu/io/Telemetry.cpp

View workflow job for this annotation

GitHub Actions / build (12.0, 3.12, ON, Release, ubuntu-20.04)

‘getuid’ was not declared in this scope; did you mean ‘getpwuid’?

Check failure on line 323 in src/flamegpu/io/Telemetry.cpp

View workflow job for this annotation

GitHub Actions / build (12.6, 3.12, ON, Release, ubuntu-22.04)

‘getuid’ was not declared in this scope; did you mean ‘getpwuid’?
if (pwd) {
return std::string(pwd->pw_dir) + "/.config";
}
}
throw std::runtime_error("Unable to retrieve config directory on Linux");
#endif
}

std::string Telemetry::generateRandomId() {
const char charset[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
const size_t length = 36;
std::random_device rd;
std::mt19937 generator(rd());
std::uniform_int_distribution<size_t> distribution(0, sizeof(charset) - 2);

std::string randomId;
for (size_t i = 0; i < length; ++i) {
randomId += charset[distribution(generator)];
}
return randomId;
}

std::string Telemetry::getUserId() {
// Generate and a new random 36-character user ID
std::string userId = Telemetry::generateRandomId();

// Try to load an existing ID from file if it exists
try {
// Determine config file location
std::string configDir = Telemetry::getConfigDirectory() + "/FLAMEGPU";
std::filesystem::create_directories(configDir); // Ensure the directory exists

Check failure on line 357 in src/flamegpu/io/Telemetry.cpp

View workflow job for this annotation

GitHub Actions / cpplint (11.8, ubuntu-20.04)

At least two spaces is best between code and comments
std::string filePath = configDir + "/flamegpu_user.cfg";

// Check if the file exists
if (std::filesystem::exists(filePath)) {
std::ifstream file(filePath);
if (file.is_open()) {
std::getline(file, userId); // overwrite existing Id

Check failure on line 364 in src/flamegpu/io/Telemetry.cpp

View workflow job for this annotation

GitHub Actions / cpplint (11.8, ubuntu-20.04)

At least two spaces is best between code and comments
file.close();
return userId; // Config file and user id found so return it

Check failure on line 366 in src/flamegpu/io/Telemetry.cpp

View workflow job for this annotation

GitHub Actions / cpplint (11.8, ubuntu-20.04)

At least two spaces is best between code and comments
}
else {
throw std::runtime_error("Unable to open user ID file for reading");
}
}

std::ofstream file(filePath);
if (file.is_open()) {
file << userId;
file.close();
}
else {
throw std::runtime_error("Unable to create user ID file");
}
} catch (const std::exception&) {
fprintf(stderr, "Warning: Telemetry User Id file is not read/writeable from config file. A new User Id will be used.");
}
return userId;
}


} // namespace io
} // namespace flamegpu

0 comments on commit 52f1596

Please sign in to comment.