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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@
- Added the health check feature. The SDK now sends a health check request once after `start()`. Like any request, it updates the user's last seen time on the server.
- Added the SDK name and version (`sdk_name` and `sdk_version`) to every request, including the remote config and SDK Behavior Settings fetches. Before, only the begin session request carried them.
- Added `multiplyCustomUserDetail` for multiplying the numeric value of a custom user property on the server.
- Added `changeServerUrl` to change the server URL after init.
- Added `changeAppKey` to change the app key after init.
- Added `flushQueues` to clear the request and event queues.
- Added `replaceAllAppKeysInQueueWithCurrentAppKey` to give the queued requests the current app key.
- Added `removeDifferentAppKeysFromQueue` to remove the queued requests of other app keys.
- Added `attemptToSendStoredRequests` to send the stored requests now.
- Added `disableHealthCheck()` for turning off the health check request.
- Added `status_code` and `body` to `HTTPResponse`. A custom HTTP client can fill them so that the health check reports the last request the server refused; a client that leaves them empty works as before.
- Calls made before `start()`, a second `start()`, beginning a session that already runs and ending one that does not are now logged at warning level. Failed and non-JSON server answers, and session calls ignored because the SDK Behavior Settings turned session tracking off, are now logged at debug level.
Expand Down
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,8 @@ if(COUNTLY_BUILD_TESTS)
${CMAKE_CURRENT_SOURCE_DIR}/tests/behavior_settings.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tests/remote_config.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tests/crash_reporting.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tests/location.cpp)
${CMAKE_CURRENT_SOURCE_DIR}/tests/location.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tests/server_url_app_key.cpp)

target_compile_options(countly-tests PRIVATE $<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-g>)
target_compile_definitions(countly-tests PRIVATE COUNTLY_BUILD_TESTS)
Expand Down
59 changes: 59 additions & 0 deletions include/countly.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,24 @@ class Countly : public cly::CountlyDelegates {

void stop();

/**
* Changes the server URL, in memory only. Host and port work as in start(): port 0 is the scheme's default and
* trailing slashes are removed. A host that is not an absolute http:// or https:// URL is ignored and logged. Queued
* requests go to the new server; a request already on its way finishes at the old one. The SDK then sends the consent
* state (when consent is required), fetches the SDK behavior settings and, with enableRemoteConfig(), downloads
* remote config. A custom HTTP client gets only the path, so it does not follow the change. Call after start().
*/
void changeServerUrl(const std::string &host, int port = 0);

/**
* Changes the app key, in memory only. Running views end, and their end events, the queued events, waiting user
* details and the end of the running session go with the old key; a session that was running then begins with the
* new key. Queued requests keep their key (see replaceAllAppKeysInQueueWithCurrentAppKey() and
* removeDifferentAppKeysFromQueue()). The old app's remote config values are cleared and the new app is caught up as
* in changeServerUrl(). An empty key, "YOUR_APP_KEY" and the current key are ignored and logged. Call after start().
*/
void changeAppKey(const std::string &appKey);

void setUpdateInterval(size_t milliseconds);

void addEvent(const cly::Event &event) override;
Expand Down Expand Up @@ -315,6 +333,28 @@ class Countly : public cly::CountlyDelegates {
*/
int checkRQSize();

/**
* Clears the request queue and the event queue. Running views, timed events, user details still waiting for the
* first session and the health check counters stay. A request already on its way is still delivered.
*/
void flushQueues();

/**
* Gives every queued request the current app key, so that requests queued before changeAppKey() go to the new app.
*/
void replaceAllAppKeysInQueueWithCurrentAppKey();

/**
* Removes the queued requests whose app key is not the current one, such as those queued before changeAppKey().
*/
void removeDifferentAppKeysFromQueue();

/**
* Moves the queued events into a request and sends the request queue now, on the calling thread, like each update:
* until the queue is empty, a request fails or a batch is sent. Returns at once if the SDK's own thread is sending.
*/
void attemptToSendStoredRequests();

/**
* Checks and returns the size of the event queue in persistent storage.
*/
Expand Down Expand Up @@ -817,6 +857,25 @@ class Countly : public cly::CountlyDelegates {
*/
bool endSessionInternal(bool automatic);

/**
* Whether the public call 'caller' may run: never inside the log callback, and not before start(), which is logged
* with w101.
*/
bool isCallAllowed(const char *caller);

/**
* Queues the end_session request of the running session and marks the session ended, counted in the health check as
* a call of the SDK with 'automatic'. The caller holds the instance mutex.
*/
void queueEndSession(bool automatic);

/**
* After a server URL or app key change, fetches the SDK behavior settings and, with enableRemoteConfig(), remote
* config, unless 'remoteConfigRequested' says a session start downloads it already. The caller does not hold the
* instance mutex.
*/
void fetchAfterServerChange(bool remoteConfigRequested);

/**
* Sends the health check once, as an immediate request to /i, unless it is disabled, the SDK behavior settings
* turn networking off, or it was sent already. It carries the base request parameters, the app version as
Expand Down
5 changes: 4 additions & 1 deletion include/countly/remote_config_store.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ struct RemoteConfigStore {
std::mutex mutex;
nlohmann::json values = nlohmann::json::object();

// True from the moment a fetch is started until its thread body returns.
// The app key the values belong to. Only a fetch for this key stores its result or clears fetch_running.
std::string app_key;

// True from the moment a fetch is started until its thread body returns, or until the app key changes.
std::atomic<bool> fetch_running{false};

// Bumped when the device ID changes, so that a download that started for an earlier user is discarded.
Expand Down
24 changes: 20 additions & 4 deletions include/countly/request_module.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,29 @@ class RequestModule {
void addRequestToQueue(const std::map<std::string, std::string> &data);

/**
* Clear request queue.
* Warning: This method is for debugging purposes, and it is going to be removed in the future.
* You should not be using this method.
* @return a vector object containing requests.
* Clears the request queue. A request that processQueue() is sending meanwhile is not removed again once it is
* delivered. The caller holds the mutex it passes to processQueue().
*/
void clearRequestQueue();

/**
* Replaces the server URL and the port that the following requests go to, the way start() sets them: a URL without
* a scheme gets "http://" in front, trailing slashes are removed, and a port of 0 becomes the scheme's default port.
*/
void setServerUrl(const std::string &url, unsigned int port);

/**
* Gives every queued request the app key. The caller holds the mutex it passes to processQueue().
*/
void replaceAppKeysInQueue(const std::string &appKey);

/**
* Removes the queued requests whose app key is not the given one. The caller holds the mutex it passes to
* processQueue().
* @return the number of removed requests
*/
long long removeOtherAppKeysFromQueue(const std::string &appKey);

long long RQSize();
void setConfigurationProvider(std::weak_ptr<ConfigurationProvider> provider); // try injecting

Expand Down
16 changes: 16 additions & 0 deletions include/countly/storage_module_base.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,22 @@ class StorageModuleBase {
*/
virtual void RQInsertAtEnd(const std::string &request) = 0;

/**
* Replace the content of a stored request, keeping its id and its place in the queue.
* @param id: id of the request
* @param request: new content of the request
*/
virtual void RQUpdate(long long id, const std::string &request) {
(void)id;
(void)request;
}

/**
* Remove the stored request with the id, wherever it is in the queue.
* @param id: id of the request
*/
virtual void RQRemove(long long id) { (void)id; }

virtual void storeSDKBehaviorSettings(const std::string &sdk_behavior_settings) = 0;

virtual std::string getSDKBehaviorSettings() = 0;
Expand Down
2 changes: 2 additions & 0 deletions include/countly/storage_module_db.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ class StorageModuleDB : public StorageModuleBase {
std::vector<std::shared_ptr<DataEntry>> RQPeekAll() override;
void RQRemoveFront(std::shared_ptr<DataEntry> request) override;
void RQInsertAtEnd(const std::string &request) override;
void RQUpdate(long long id, const std::string &request) override;
void RQRemove(long long id) override;
void storeSDKBehaviorSettings(const std::string &sdk_behavior_settings) override;
std::string getSDKBehaviorSettings() override;
void storeHealthCheckState(const std::string &state) override;
Expand Down
2 changes: 2 additions & 0 deletions include/countly/storage_module_memory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ class StorageModuleMemory : public StorageModuleBase {
std::vector<std::shared_ptr<DataEntry>> RQPeekAll() override;
void RQRemoveFront(std::shared_ptr<DataEntry> request) override;
void RQInsertAtEnd(const std::string &request) override;
void RQUpdate(long long id, const std::string &request) override;
void RQRemove(long long id) override;
void storeSDKBehaviorSettings(const std::string &sdk_behavior_settings) override;
std::string getSDKBehaviorSettings() override;
};
Expand Down
Loading
Loading