Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
## XX.XX.XX
## XX.XX.XX
- Added manual session control, which can be enabled via "Countly::enableManualSessionControl".
- Added "checkRQSize" function to return the current number of requests in the queue.

## 23.2.0
Expand Down
3 changes: 3 additions & 0 deletions include/countly.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ class Countly : public cly::CountlyDelegates {

void setSha256(cly::SHA256Function fun);

void enableManualSessionControl();

void setHTTPClient(HTTPClientFunction fun);

void setMetrics(const std::string &os, const std::string &os_version, const std::string &device, const std::string &resolution, const std::string &carrier, const std::string &app_version);
Expand Down Expand Up @@ -324,6 +326,7 @@ class Countly : public cly::CountlyDelegates {
std::chrono::system_clock::duration getSessionDuration();

void updateLoop();
void packEvents();
bool began_session = false;
bool is_being_disposed = false;
bool is_sdk_initialized = false;
Expand Down
2 changes: 2 additions & 0 deletions include/countly/countly_configuration.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ struct CountlyConfiguration {

SHA256Function sha256_function = nullptr;

bool manualSessionControl = false;

HTTPClientFunction http_client_function = nullptr;

nlohmann::json metrics;
Expand Down
108 changes: 77 additions & 31 deletions src/countly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,20 @@ void Countly::setSha256(SHA256Function fun) {
mutex->unlock();
}

/**
* Enable manual session handling.
*/
void Countly::enableManualSessionControl() {
if (is_sdk_initialized) {
log(LogLevel::WARNING, "[Countly][enableManualSessionControl] You can not enable manual session control after SDK initialization.");
return;
}

mutex->lock();
configuration->manualSessionControl = true;
mutex->unlock();
}

void Countly::setMetrics(const std::string &os, const std::string &os_version, const std::string &device, const std::string &resolution, const std::string &carrier, const std::string &app_version) {
if (is_sdk_initialized) {
log(LogLevel::WARNING, "[Countly][setMetrics] You can not set metrics after SDK initialization.");
Expand Down Expand Up @@ -332,17 +346,19 @@ void Countly::_changeDeviceIdWithoutMerge(const std::string &value) {

// send all event to server and end current session of old user
flushEvents();
if (began_session) {
if(!configuration->manualSessionControl){
endSession();
mutex->lock();
session_params["device_id"] = value;
mutex->unlock();
}

mutex->lock();
session_params["device_id"] = value;
mutex->unlock();

// start a new session for new user
if(!configuration->manualSessionControl){
beginSession();
} else {
mutex->lock();
session_params["device_id"] = value;
mutex->unlock();
}

}
#pragma endregion Device Id

Expand Down Expand Up @@ -387,7 +403,7 @@ void Countly::start(const std::string &app_key, const std::string &host, int por
log(LogLevel::INFO, "[Countly][start] '_WIN32' is not defined");
#endif

enable_automatic_session = start_thread;
enable_automatic_session = start_thread && !configuration->manualSessionControl;
start_thread = true;

if (port < 0 || port > 65535) {
Expand Down Expand Up @@ -422,9 +438,11 @@ void Countly::start(const std::string &app_key, const std::string &host, int por

if (!running) {

mutex->unlock();
beginSession();
mutex->lock();
if(!configuration->manualSessionControl){
mutex->unlock();
beginSession();
mutex->lock();
}

if (start_thread) {
stop_thread = false;
Expand All @@ -451,7 +469,7 @@ void Countly::startOnCloud(const std::string &app_key) {

void Countly::stop() {
_deleteThread();
if (began_session) {
if (!configuration->manualSessionControl) {
endSession();
}
}
Expand Down Expand Up @@ -593,8 +611,16 @@ bool Countly::attemptSessionUpdateEQ() {
return false;
}
#endif

return !updateSession();
bool result;
if(!configuration->manualSessionControl){
result = !updateSession();
} else {
log(LogLevel::WARNING, "[Countly][attemptSessionUpdateEQ] SDK is in manual session control mode. Please start a session first.");
result = false;
}

packEvents();
return result;
}

void Countly::clearEQInternal() {
Expand Down Expand Up @@ -656,6 +682,7 @@ bool Countly::beginSession() {
log(LogLevel::INFO, "[Countly][beginSession]");
if (began_session) {
mutex->unlock();
log(LogLevel::DEBUG, "[Countly][beginSession] Session is already active.");
return true;
}

Expand Down Expand Up @@ -711,15 +738,42 @@ bool Countly::updateSession() {
mutex->lock();
if (!began_session) {
mutex->unlock();
if(configuration->manualSessionControl){
log(LogLevel::WARNING, "[Countly][updateSession] SDK is in manual session control mode and there is no active session. Please start a session first.");
return false;
}
if (!beginSession()) {
// if beginSession fails, we should not try to update session
return false;
}
mutex->lock();
began_session = true;
}

mutex->unlock();
auto duration = std::chrono::duration_cast<std::chrono::seconds>(getSessionDuration());
mutex->lock();

// report session duration if it is greater than the configured session duration value
if (duration.count() >= configuration->sessionDuration) {
log(LogLevel::DEBUG, "[Countly][updateSession] sending session update.");
std::map<std::string, std::string> data = {{"app_key", session_params["app_key"].get<std::string>()}, {"device_id", session_params["device_id"].get<std::string>()}, {"session_duration", std::to_string(duration.count())}};
requestModule->addRequestToQueue(data);

last_sent_session_request += duration;
}
} catch (const std::system_error &e) {
std::ostringstream log_message;
log_message << "update session, error: " << e.what();
log(LogLevel::FATAL, log_message.str());
}
mutex->unlock();
return true;
}

// events array
void Countly::packEvents() {
try {
// events array
nlohmann::json events = nlohmann::json::array();
std::string event_ids;
mutex->unlock();
Expand All @@ -740,20 +794,7 @@ bool Countly::updateSession() {
} else {
log(LogLevel::DEBUG, "[Countly][updateSession] EQ empty.");
}
mutex->unlock();
auto duration = std::chrono::duration_cast<std::chrono::seconds>(getSessionDuration());
mutex->lock();

// report session duration if it is greater than the configured session duration value
if (duration.count() >= configuration->sessionDuration) {
log(LogLevel::DEBUG, "[Countly][updateSession] sending session update.");
std::map<std::string, std::string> data = {{"app_key", session_params["app_key"].get<std::string>()}, {"device_id", session_params["device_id"].get<std::string>()}, {"session_duration", std::to_string(duration.count())}};
requestModule->addRequestToQueue(data);

last_sent_session_request += duration;
}

// report events if there are any to request queue
// report events if there are any to request queue
if (!no_events) {
sendEventsToRQ(events);
}
Expand All @@ -774,9 +815,9 @@ bool Countly::updateSession() {
log(LogLevel::FATAL, log_message.str());
}
mutex->unlock();
return true;
}


void Countly::sendEventsToRQ(const nlohmann::json &events) {
log(LogLevel::DEBUG, "[Countly][sendEventsToRQ] Sending events to RQ.");
std::map<std::string, std::string> data = {{"app_key", session_params["app_key"].get<std::string>()}, {"device_id", session_params["device_id"].get<std::string>()}, {"events", events.dump()}};
Expand All @@ -785,6 +826,10 @@ void Countly::sendEventsToRQ(const nlohmann::json &events) {

bool Countly::endSession() {
log(LogLevel::INFO, "[Countly][endSession]");
if(!began_session) {
log(LogLevel::DEBUG, "[Countly][endSession] There is no active session to end.");
return true;
}
const std::chrono::system_clock::time_point now = Countly::getTimestamp();
const auto timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch());
const auto duration = std::chrono::duration_cast<std::chrono::seconds>(getSessionDuration(now));
Expand Down Expand Up @@ -1125,6 +1170,7 @@ void Countly::updateLoop() {
if (enable_automatic_session) {
updateSession();
}
packEvents();
requestModule->processQueue(mutex);
}
mutex->lock();
Expand Down
Loading