Skip to content

Commit 9c012fc

Browse files
[SDK 634] User location bug fixed! (#30)
* User location bug fixed! * PR Changes * change log entery * merged files left behind * Bug fixed while sending userdetail request to server. * Update CHANGELOG.md Co-authored-by: ArtursKadikis <[email protected]>
1 parent b41d08b commit 9c012fc

File tree

3 files changed

+155
-26
lines changed

3 files changed

+155
-26
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
* Fixed bug when device id was changed without server merge. Previously the new session was started with the old device ID and not the new one.
1111
* Fixed a bug that was a typo ('COUNTLY_CUSTOM_HTTP' instead of 'COUNTLY_USE_CUSTOM_HTTP') in the cmake file that cause the SDK to be misconfigured.
1212
* Fixed a bug that caused POST requests to fail on Windows.
13+
* Fixed issues with location requests.
14+
* Deprecated old location calls and introduced a new location call
1315

1416
21.11.0
1517
* Fixed session duration issue.

include/countly.hpp

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,30 @@ class Countly {
6161

6262
void setCustomUserDetails(const std::map<std::string, std::string>& value);
6363

64+
/*
65+
setCountry is deprecated, please use void `setLocation(const std::string& countryCode, const std::string& city, const std::string& gpsCoordinates, const std::string& ipAddress)` function instead.
66+
*/
6467
void setCountry(const std::string& country_code);
6568

69+
/*
70+
setCity is deprecated, please use void `setLocation(const std::string& countryCode, const std::string& city, const std::string& gpsCoordinates, const std::string& ipAddress)` function instead.
71+
*/
6672
void setCity(const std::string& city_name);
6773

74+
/*
75+
setLocation is deprecated, please use void `setLocation(const std::string& countryCode, const std::string& city, const std::string& gpsCoordinates, const std::string& ipAddress)` function instead.
76+
*/
6877
void setLocation(double lattitude, double longitude);
6978

79+
/*
80+
Set Country code(ISO Country code), City, Location and IP address to be used for future requests.
81+
@param[in] countryCode: ISO Country code for the user's country
82+
@param[in] city: Name of the user's city.
83+
@param[in] gpsCoordinates: Comma separate latitude and longitude values.For example, `56.42345,123.45325`.
84+
@param[in] ipAddress: IpAddress like `192.168.88.33`
85+
*/
86+
void setLocation(const std::string& countryCode, const std::string& city, const std::string& gpsCoordinates, const std::string& ipAddress);
87+
7088
void setDeviceID(const std::string& value, bool same_user = false);
7189

7290
void start(const std::string& app_key, const std::string& host, int port = -1, bool start_thread = false);
@@ -214,6 +232,7 @@ class Countly {
214232
}
215233
private:
216234
void _deleteThread();
235+
void _sendIndependantLocationRequest();
217236
void log(LogLevel level, const std::string& message);
218237

219238
HTTPResponse sendHTTP(std::string path, std::string data);
@@ -232,13 +251,17 @@ class Countly {
232251
HTTPResponse (*http_client_function)(bool is_post, const std::string& url, const std::string& data);
233252

234253
std::string host;
254+
235255
int port;
236256
bool use_https;
237257
bool always_use_post;
238-
bool is_being_disposed;
239-
std::chrono::system_clock::time_point last_sent_session_request;
258+
240259
bool began_session;
260+
bool is_being_disposed;
261+
bool is_sdk_initialized;
241262

263+
std::chrono::system_clock::time_point last_sent_session_request;
264+
242265
json session_params;
243266
std::string salt;
244267

src/countly.cpp

Lines changed: 128 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ Countly::Countly() : max_events(COUNTLY_MAX_EVENTS_DEFAULT), wait_milliseconds(C
3737
began_session = false;
3838
always_use_post = false;
3939
is_being_disposed = false;
40+
is_sdk_initialized = false;
4041
remote_config_enabled = false;
4142

4243
//Petting to null values
@@ -123,48 +124,125 @@ void Countly::setUserDetails(const std::map<std::string, std::string>& value) {
123124
mutex.lock();
124125
session_params["user_details"] = value;
125126

126-
if (began_session) {
127-
std::map<std::string, std::string> data = {
128-
{"app_key", session_params["app_key"].dump()},
129-
{"device_id", session_params["device_id"].dump()},
127+
if (!is_sdk_initialized) {
128+
log(Countly::LogLevel::ERROR, "[Countly][setUserDetails] Can not send user detail if the SDK has not been initialized.");
129+
mutex.unlock();
130+
return;
131+
}
132+
133+
std::map<std::string, std::string> data = {
134+
{"app_key", session_params["app_key"].get<std::string>()},
135+
{"device_id", session_params["device_id"].get<std::string>()},
130136
{"user_details", session_params["user_details"].dump()}
131-
};
137+
};
132138

133-
sendHTTP("/i", Countly::serializeForm(data));
134-
}
139+
sendHTTP("/i", Countly::serializeForm(data));
135140
mutex.unlock();
136141
}
137142

138143
void Countly::setCustomUserDetails(const std::map<std::string, std::string>& value) {
139144
mutex.lock();
140145
session_params["user_details"]["custom"] = value;
141146

142-
if (began_session) {
143-
std::map<std::string, std::string> data = {
144-
{"app_key", session_params["app_key"].dump()},
145-
{"device_id", session_params["device_id"].dump()},
147+
if (!is_sdk_initialized) {
148+
log(Countly::LogLevel::ERROR, "[Countly][setCustomUserDetails] Can not send user detail if the SDK has not been initialized.");
149+
mutex.unlock();
150+
return;
151+
}
152+
153+
std::map<std::string, std::string> data = {
154+
{"app_key", session_params["app_key"].get<std::string>()},
155+
{"device_id", session_params["device_id"].get<std::string>()},
146156
{"user_details", session_params["user_details"].dump()}
147-
};
157+
};
148158

149-
sendHTTP("/i", Countly::serializeForm(data));
150-
}
159+
sendHTTP("/i", Countly::serializeForm(data));
151160
mutex.unlock();
152161
}
153162

163+
#pragma region User location
164+
154165
void Countly::setCountry(const std::string& country_code) {
155-
session_params["country_code"] = country_code;
166+
log(Countly::LogLevel::WARNING, "[Countly][setCountry] 'setCountry' is deprecated, please use 'setLocation(countryCode, city, gpsCoordinates, ipAddress)' method instead.");
167+
setLocation(country_code, "", "", "");
156168
}
157169

158170
void Countly::setCity(const std::string& city_name) {
159-
session_params["city"] = city_name;
171+
log(Countly::LogLevel::WARNING, "[Countly][setCity] 'setCity' is deprecated, please use 'setLocation(countryCode, city, gpsCoordinates, ipAddress)' method instead.");
172+
setLocation("", city_name, "", "");
160173
}
161174

162175
void Countly::setLocation(double lattitude, double longitude) {
176+
log(Countly::LogLevel::WARNING, "[Countly][setLocation] 'setLocation(latitude, longitude)' is deprecated, please use 'setLocation(countryCode, city, gpsCoordinates, ipAddress)' method instead.");
177+
163178
std::ostringstream location_stream;
164179
location_stream << lattitude << ',' << longitude;
165-
session_params["location"] = location_stream.str();
180+
setLocation("", "", location_stream.str(), "");
181+
}
182+
183+
void Countly::setLocation(const std::string& countryCode, const std::string& city, const std::string& gpsCoordinates, const std::string& ipAddress) {
184+
mutex.lock();
185+
log(Countly::LogLevel::INFO, "[Countly][setLocation] SetLocation : countryCode = " + countryCode + ", city = " + city + ", gpsCoordinates = " + gpsCoordinates + ", ipAddress = " + ipAddress);
186+
187+
188+
if ((!countryCode.empty() && city.empty())
189+
|| (!city.empty() && countryCode.empty())) {
190+
log(Countly::LogLevel::WARNING, "[Countly][setLocation] In \"SetLocation\" both country code and city should be set together");
191+
}
192+
193+
session_params["city"] = city;
194+
session_params["ip_address"] = ipAddress;
195+
session_params["location"] = gpsCoordinates;
196+
session_params["country_code"] = countryCode;
197+
198+
mutex.unlock();
199+
200+
if (is_sdk_initialized) {
201+
_sendIndependantLocationRequest();
202+
}
166203
}
167204

205+
void Countly::_sendIndependantLocationRequest() {
206+
mutex.lock();
207+
log(Countly::LogLevel::DEBUG, "[Countly] [_sendIndependantLocationRequest]");
208+
209+
/*
210+
* Empty country code, city and IP address can not be sent.
211+
*/
212+
213+
std::map<std::string, std::string> data;
214+
215+
if (session_params.contains("city") && session_params["city"].is_string() && !session_params["city"].get<std::string>().empty()) {
216+
data["city"] = session_params["city"].get<std::string>();
217+
}
218+
219+
if (session_params.contains("location") && session_params["location"].is_string() && !session_params["location"].get<std::string>().empty()) {
220+
data["location"] = session_params["location"].get<std::string>();
221+
}
222+
223+
if (session_params.contains("country_code") && session_params["country_code"].is_string() && !session_params["country_code"].get<std::string>().empty()) {
224+
data["country_code"] = session_params["country_code"].get<std::string>();
225+
}
226+
227+
if (session_params.contains("ip_address") && session_params["ip_address"].is_string() && !session_params["ip_address"].get<std::string>().empty()) {
228+
data["ip_address"] = session_params["ip_address"].get<std::string>();
229+
}
230+
231+
const std::chrono::system_clock::time_point now = Countly::getTimestamp();
232+
const auto timestamp = std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch());
233+
234+
if (!data.empty()) {
235+
data["app_key"] = session_params["app_key"].get<std::string>();
236+
data["device_id"] = session_params["device_id"].get<std::string>();
237+
data["timestamp"] = std::to_string(timestamp.count());
238+
sendHTTP("/i", Countly::serializeForm(data));
239+
}
240+
241+
mutex.unlock();
242+
}
243+
244+
#pragma endregion User location
245+
168246
#pragma region Device Id
169247
void Countly::setDeviceID(const std::string& value, bool same_user) {
170248
mutex.lock();
@@ -184,8 +262,12 @@ void Countly::setDeviceID(const std::string& value, bool same_user) {
184262
return;
185263
}
186264

187-
//If code does reach here without sdk init, it will throw an exception.
188265
mutex.unlock();
266+
if (!is_sdk_initialized) {
267+
log(Countly::LogLevel::ERROR, "[Countly][setDeviceID] Can not change the device id if the SDK has not been initialized.");
268+
return;
269+
}
270+
189271
if (same_user) {
190272
_changeDeviceIdWithMerge(value);
191273
}
@@ -260,6 +342,8 @@ void Countly::start(const std::string& app_key, const std::string& host, int por
260342
this->port = port;
261343
}
262344

345+
is_sdk_initialized = true; // after this point SDK is initialized.
346+
263347
if (!running) {
264348

265349
mutex.unlock();
@@ -455,18 +539,38 @@ bool Countly::beginSession() {
455539
{"sdk_name", COUNTLY_SDK_NAME},
456540
{"sdk_version", COUNTLY_API_VERSION},
457541
{"timestamp", std::to_string(timestamp.count())},
542+
{"app_key", session_params["app_key"].get<std::string>()},
543+
{"device_id", session_params["device_id"].get<std::string>()},
458544
{"begin_session", "1"}
459545
};
460546

461-
for (auto& element : session_params.items()) {
462-
if (element.value().is_string()) {
463-
data[element.key()] = element.value().get<std::string>();
464-
} else {
465-
data[element.key()] = element.value().dump();
466-
}
547+
if (session_params.contains("city") && session_params["city"].is_string() && !session_params["city"].get<std::string>().empty()) {
548+
data["city"] = session_params["city"].get<std::string>();
549+
}
550+
551+
if (session_params.contains("location") && session_params["location"].is_string() && !session_params["location"].get<std::string>().empty()) {
552+
data["location"] = session_params["location"].get<std::string>();
553+
}
554+
555+
if (session_params.contains("country_code") && session_params["country_code"].is_string() && !session_params["country_code"].get<std::string>().empty()) {
556+
data["country_code"] = session_params["country_code"].get<std::string>();
557+
}
558+
559+
if (session_params.contains("ip_address") && session_params["ip_address"].is_string() && !session_params["ip_address"].get<std::string>().empty()) {
560+
data["ip_address"] = session_params["ip_address"].get<std::string>();
561+
}
562+
563+
if (session_params.contains("user_details")) {
564+
data["user_details"] = session_params["user_details"].dump();
565+
session_params.erase("user_details");
566+
}
567+
568+
if (session_params.contains("metrics")) {
569+
data["metrics"] = session_params["metrics"].dump();
467570
}
468571

469572
if (sendHTTP("/i", Countly::serializeForm(data)).success) {
573+
session_params.erase("user_details");
470574
last_sent_session_request = Countly::getTimestamp();
471575
began_session = true;
472576
}

0 commit comments

Comments
 (0)