Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backport to 3.1.x [TIMOB-14114] fixed sending duplicate events #79

Merged
merged 1 commit into from
Jun 5, 2013
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
65 changes: 45 additions & 20 deletions src/tibb/TiAnalyticsObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#include <bb/device/HardwareInfo>
#include "TiGenericFunctionObject.h"
#include <QUuid>
#include <bps/bps.h>
#include <bps/netstatus.h>


/**
Expand Down Expand Up @@ -92,10 +94,10 @@ TiAnalyticsObject::TiAnalyticsObject(NativeObjectFactory* objectFactory)

if (createAnalyticsDatabase()) {
addAnalyticsEvent("ti.enroll");
sendPendingAnalyticsEvents();
}

// Set up timer and every 10 minutes send out analytics events if any are pending
// set up timer and every 30 seconds send out analytics events if any are pending
// usually because of unavailable network access
TiAnalyticsHandler* eventHandler = new TiAnalyticsHandler(this, "");
timer_ = new QTimer(eventHandler);
QObject::connect(timer_, SIGNAL(timeout()), eventHandler, SLOT(sendPendingRequests()));
Expand Down Expand Up @@ -160,10 +162,11 @@ bool TiAnalyticsObject::createAnalyticsDatabase()
return dbCreate ;
}

void TiAnalyticsObject::addAnalyticsEvent(std::string const& name, std::string const& data)
void TiAnalyticsObject::addAnalyticsEvent(std::string const& name, std::string const& data, std::string const& typeArg)
{
sqlite3_stmt* stmt;
int rc;
string type;

string cmd = "INSERT INTO events VALUES (?, ?)";
rc = sqlite3_prepare_v2(db, cmd.c_str(), strlen(cmd.c_str()) + 1, &stmt, NULL);
Expand All @@ -183,10 +186,16 @@ void TiAnalyticsObject::addAnalyticsEvent(std::string const& name, std::string c
uid.replace("}", "");
QByteArray id = uid.toLocal8Bit();

if (name.find("app.feature") == std::string::npos) {
type = name;
} else {
type = typeArg;
}

// TODO guard against 1024 overrun
char json[1024];
sprintf(json, "[{\"seq\":%d,\"ver\":\"2\",\"id\":\"%s\",\"sid\":\"%s\",\"mid\":\"%s\",\"aguid\":\"%s\",\"type\":\"%s\",\"event\":\"%s\",\"ts\":\"%s\",\"data\":{\"platform\":\"blackberry\",\"deploytype\":\"%s\",\"app_version\":\"%s\",\"feature_data\":\"%s\"}}]",
sequence_, id.data(), sid_.data(), mid_.data(), aguid_.data(), name.c_str(), name.c_str(), ts.data(),
sequence_, id.data(), sid_.data(), mid_.data(), aguid_.data(), name.c_str(), type.c_str(), ts.data(),
deployType_.data(), appVersion_.data(), data.c_str());

sqlite3_bind_text(stmt, 1, id.data(), strlen(id.data()), 0);
Expand All @@ -201,8 +210,6 @@ void TiAnalyticsObject::addAnalyticsEvent(std::string const& name, std::string c
sqlite3_reset(stmt);
sqlite3_clear_bindings(stmt);



if (name == "ti.end" ) {
bb::cascades::Application::instance()->exit(0);
}
Expand Down Expand Up @@ -233,19 +240,31 @@ void TiAnalyticsObject::sendPendingAnalyticsEvents()
uid = sqlite3_column_text (stmt, 0);
json = sqlite3_column_text (stmt, 1);

bool log = defaultSettings.value("analytics-log").toBool();
if (log) {
TiLogger::getInstance().log("Sending Analytic Event: ");
TiLogger::getInstance().log((const char*)json);
bool is_available = true;
netstatus_get_availability(&is_available);

if (is_available) {
// do not send an http post if a reply is pending
std::string id = std::string((const char*)uid, strlen((const char*)uid));
if (pendingHttpReplies.find(id) == pendingHttpReplies.end())
{
TiAnalyticsHandler* requestHandler = new TiAnalyticsHandler(this, (const char*)uid);
pendingHttpReplies[id] = requestHandler;

bool log = defaultSettings.value("analytics-log").toBool();
if (log) {
TiLogger::getInstance().log("Sending Analytic Event: ");
TiLogger::getInstance().log((const char*)json);
}


// send HTTP POST Asynchronously
QByteArray postDataSize = QByteArray::number(strlen((const char*)json));
request_.setRawHeader("Content-Length", postDataSize);
QNetworkReply* reply = networkAccessManager_.post(request_, (const char*)json);
QObject::connect(reply, SIGNAL(finished()), requestHandler, SLOT(finished()));
}
}

// Send HTTP POST Asynchronously
QByteArray postDataSize = QByteArray::number(strlen((const char*)json));
request_.setRawHeader("Content-Length", postDataSize);
QNetworkReply* reply = networkAccessManager_.post(request_, (const char*)json);

TiAnalyticsHandler* requestHandler = new TiAnalyticsHandler(this, (const char*)uid);
QObject::connect(reply, SIGNAL(finished()), requestHandler, SLOT(finished()));
}
else if (s == SQLITE_DONE) {
break;
Expand All @@ -262,10 +281,10 @@ void TiAnalyticsObject::sendPendingAnalyticsEvents()
Handle<Value> TiAnalyticsObject::_featureEvent(void* userContext, TiObject*, const Arguments& args)
{
TiAnalyticsObject* obj = (TiAnalyticsObject*) userContext;
string name = "feature.app." +TiObject::getSTDStringFromValue(args[0]);
string type = TiObject::getSTDStringFromValue(args[0]);
string data = TiObject::getSTDStringFromValue(args[1]);

obj->addAnalyticsEvent(name, data);
obj->addAnalyticsEvent("app.feature", data, type);

return Undefined();
}
Expand Down Expand Up @@ -306,11 +325,17 @@ void TiAnalyticsHandler::finished()

sqlite3_reset(stmt);
sqlite3_clear_bindings(stmt);

// remove the pending http reply
tiAnalyticsObject_->pendingHttpReplies.erase(uid_);
this->deleteLater();

}

void TiAnalyticsHandler::errors(QNetworkReply* reply)
{
TiLogger::getInstance().log("\nHTTP error while sending analytic event.\n");
this->deleteLater();
}

void TiAnalyticsHandler::sendPendingRequests()
Expand Down
3 changes: 2 additions & 1 deletion src/tibb/TiAnalyticsObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,12 @@ class TiAnalyticsObject : public TiProxy
public:
static void addObjectToParent(TiObject* parent, NativeObjectFactory* objectFactory);
bool createAnalyticsDatabase();
void addAnalyticsEvent(std::string const& name, std::string const& data = "");
void addAnalyticsEvent(std::string const& name, std::string const& data = "", std::string const& type = "");
void sendPendingAnalyticsEvents();

sqlite3* db;
bool appStart;
std::map <std::string, TiAnalyticsHandler*> pendingHttpReplies;

protected:
virtual ~TiAnalyticsObject();
Expand Down
3 changes: 3 additions & 0 deletions src/tibb/TitaniumRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <QtCore/QObject>
#include <stdio.h>
#include <string.h>
#include <bps/bps.h>

TitaniumRuntime* TitaniumRuntime::runtime = 0;

Expand Down Expand Up @@ -53,6 +54,8 @@ int TitaniumRuntime::run(const char* javaScript, int argc, char** argv)

int TitaniumRuntime::internalRun(int argc, char** argv)
{
bps_initialize(); // initialize the bps services

TiRootObject* obj;
obj = TiRootObject::createRootObject();
rootObject_.attachTiObject(obj);
Expand Down
2 changes: 1 addition & 1 deletion test/apps/native/tibbtest/assets/app_properties.ini
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ ti.ui.defaultunit = system
acs-oauth-secret-production = U2xW7T4PduMwimYGkf0CCtmZwDKE78B5
acs-oauth-key-development = caJzH5kwqSRXVDgzTmtNxCbbRrXvKcl5
acs-oauth-key-production = X6yI3EA9b1GDbA1WrbG7dtGJ7rRthzAZ
analytics = false
analytics = true
analytics-log = true
aguid = 15d9f2b2-26d9-4870-ba56-edf7ab69d5ad
deploytype = development
Expand Down