annotate eventLogger.mm @ 27:ae4d2c3ce5e0

Details. Zoom trailing finger move sorted. Qs rephrased.
author Robert Tubb <rt300@eecs.qmul.ac.uk>
date Wed, 13 Feb 2013 17:03:56 +0000
parents f42a00e3f22d
children e2c62db1e265
rev   line source
rt300@0 1 //
rt300@0 2 // eventLogger.mm
rt300@0 3 // oscSenderExample
rt300@0 4 //
rt300@0 5 // Created by Robert Tubb on 05/11/2012.
rt300@0 6 //
rt300@0 7 //
rt300@4 8
rt300@8 9 //---------------------------------------------------------------------------
rt300@0 10 #include "eventLogger.h"
rt300@1 11
rt300@1 12 EventLogger eventLogger;
rt300@1 13
rt300@8 14 //---------------------------------------------------------------------------
rt300@1 15 EventLogger::EventLogger(){
rt300@14 16 //QuestionnaireViewController * questionnaireViewController;
rt300@8 17
rt300@25 18 consentGiven = true; // unless told otherwise by introView
rt300@8 19 loggingEnabled = true;
rt300@22 20 serverConnectionOK = false;
rt300@22 21 questionnaireCompleted = false;
rt300@22 22 questionnaireUploaded = false;
rt300@27 23 currentHTTPRequestID = -1;
rt300@27 24 logUploadInProgress = false;
rt300@22 25 ofxiPhoneDeviceType iOSdeviceType = ofxiPhoneGetDeviceType();
rt300@22 26 cout << "Device: " << iOSdeviceType << '\n';
rt300@22 27
rt300@25 28 nextUploadQty = UPLOAD_CHUNK_SIZE; // amount of data uploaded is always more than UPLOAD_CHUNK_SIZE events
rt300@27 29
rt300@8 30 }
rt300@8 31 //---------------------------------------------------------------------------
rt300@24 32 // draw() - show path of last N scroll events - can be scrubbed along?
rt300@24 33 //
rt300@24 34 //---------------------------------------------------------------------------
rt300@8 35 void EventLogger::init(){
rt300@4 36
rt300@8 37 readJsonToLog(ofxiPhoneGetDocumentsDirectory() + EVENT_LOG_FILENAME);
rt300@8 38 sessionStartTime = ofGetSystemTime();
rt300@9 39
rt300@9 40 testConnection();
rt300@7 41
rt300@25 42 logEvent(APP_STARTED);
rt300@8 43 }
rt300@8 44 //---------------------------------------------------------------------------
rt300@22 45 void EventLogger::questionnaireAnswersObtained(vector<int> answers){
rt300@22 46
rt300@22 47 questionnaireCompleted = true;
rt300@22 48 questionnaireAnswers = answers;
rt300@22 49
rt300@22 50 uploadQuestionnaire();
rt300@22 51
rt300@22 52 }
rt300@22 53 //---------------------------------------------------------------------------
rt300@27 54 void EventLogger::uploadQuestionnaire(){
rt300@22 55 // show indicator
rt300@22 56 cout << "^^^^^^^^ UPLOADING QUESTIONNAIRE ^^^^^^^^ \n";
rt300@22 57
rt300@27 58 sendToServer("questionnaire", questionnaireToJson(), true);
rt300@27 59
rt300@22 60 }
rt300@22 61 //---------------------------------------------------------------------------
rt300@27 62 bool EventLogger::sendToServer(string functionName, Json::Value jsonData, bool async = false){
rt300@22 63 bool sent;
rt300@22 64 string request;
rt300@22 65
rt300@22 66 if(functionName == "testConnection"){
rt300@22 67 request = "http://127.0.0.1:8080/testservice/testConnection?jsontext=";
rt300@22 68 }else if(functionName == "questionnaire"){
rt300@22 69 request = "http://127.0.0.1:8080/testservice/questionnaire?jsontext=";
rt300@22 70 }else if(functionName == "eventlog"){
rt300@22 71 request = "http://127.0.0.1:8080/testservice/eventlog?jsontext=";
rt300@22 72 }
rt300@22 73 Json::FastWriter writer;
rt300@22 74 string jsontext = writer.write( jsonData );
rt300@22 75
rt300@27 76 // remove newline
rt300@22 77 if (!jsontext.empty() && jsontext[jsontext.length()-1] == '\n') {
rt300@22 78 jsontext.erase(jsontext.length()-1);
rt300@22 79 }
rt300@22 80
rt300@22 81 request.append(jsontext);
rt300@27 82
rt300@27 83 if(!async){
rt300@27 84 ofURLFileLoader fileLoader;
rt300@27 85 ofHttpResponse resp;
rt300@27 86 resp = fileLoader.get(request);
rt300@22 87
rt300@27 88 cout << "HTTP STATUS " << resp.status << "\n";
rt300@27 89 cout << "HTTP ERROR " << resp.error << "\n";
rt300@27 90 cout << "HTTP DATA " << resp.data << "\n"; // ofBuffer
rt300@27 91
rt300@27 92 stringstream response;
rt300@27 93 response << resp.data;
rt300@27 94
rt300@27 95 if (resp.status == 200){
rt300@27 96 if(response.str() == "OK"){
rt300@27 97
rt300@27 98 sent = true;
rt300@27 99 }else{
rt300@27 100 // not ok
rt300@27 101 // problem serverside
rt300@27 102 sent = false;
rt300@27 103 }
rt300@27 104 }else{
rt300@27 105
rt300@27 106 sent = false;
rt300@27 107 // SHOW AN ALERT TO USER?
rt300@27 108 }
rt300@27 109
rt300@27 110 return sent;
rt300@27 111 }else{ // async
rt300@27 112 ofURLFileLoader fileLoader;
rt300@27 113 currentHTTPRequestID = ofLoadURLAsync(request, functionName);
rt300@27 114 ofRegisterURLNotification(this);
rt300@27 115
rt300@27 116 return true; // ???
rt300@27 117 }
rt300@27 118 }
rt300@27 119 //-----------------------------
rt300@27 120 void EventLogger::urlResponse(ofHttpResponse & response){
rt300@27 121 cout << "gotHTTPRequestStatus\n";
rt300@27 122 cout << "HTTP REQUEST NAME " << response.request.name << "\n";
rt300@27 123 cout << "HTTP STATUS " << response.status << "\n";
rt300@27 124 cout << "HTTP ERROR " << response.error << "\n";
rt300@27 125 cout << "HTTP DATA " << response.data << "\n"; // ofBuffer
rt300@9 126
rt300@27 127 bool sent;
rt300@27 128 stringstream respStr;
rt300@27 129 respStr << response.data;
rt300@22 130
rt300@27 131 if (response.status == 200){
rt300@27 132 if(respStr.str() == "OK"){
rt300@22 133
rt300@22 134 sent = true;
rt300@22 135 }else{
rt300@22 136 // not ok
rt300@22 137 // problem serverside
rt300@22 138 sent = false;
rt300@22 139 }
rt300@9 140 }else{
rt300@22 141
rt300@22 142 sent = false;
rt300@9 143 // SHOW AN ALERT TO USER?
rt300@9 144 }
rt300@27 145
rt300@27 146 // now do request specific stuff
rt300@27 147 if(response.request.name == "eventlog"){
rt300@27 148 if(!sent){
rt300@27 149 // try later
rt300@27 150 nextUploadQty += UPLOAD_CHUNK_SIZE;
rt300@27 151 }else{
rt300@27 152
rt300@27 153 // if success - clear memory
rt300@27 154 theEvents.clear();
rt300@27 155 cout << "UPLOAD SUCCESS\n";
rt300@27 156 nextUploadNumber++;
rt300@27 157 }
rt300@27 158 logUploadInProgress = false;
rt300@27 159 }else if(response.request.name == "questionnaire"){
rt300@27 160 if(sent){
rt300@27 161 questionnaireUploaded = true;
rt300@27 162 }else{
rt300@27 163 questionnaireUploaded = false; // will try next time... when?
rt300@27 164 }
rt300@27 165 }else if(response.request.name == "testConnection"){
rt300@27 166
rt300@27 167 if (sent){
rt300@27 168 cout << "^^^^^^^^ server connection OK ^^^^^^^^ \n";
rt300@27 169 serverConnectionOK = true;
rt300@27 170 }else{
rt300@27 171 cout << "server connection ERROR \n";
rt300@27 172 }
rt300@27 173 }
rt300@27 174
rt300@22 175 }
rt300@22 176 //---------------------------------------------------------------------------
rt300@22 177 bool EventLogger::testConnection(){
rt300@22 178 Json::Value root;
rt300@22 179 root["test"] = "test";
rt300@22 180
rt300@22 181
rt300@27 182 sendToServer("testConnection", root, true);
rt300@27 183
rt300@9 184 }
rt300@9 185 //---------------------------------------------------------------------------
rt300@8 186 void EventLogger::readJsonToLog(const string &jsonFile){
rt300@8 187 Json::Value root;
rt300@8 188 Json::Reader reader;
rt300@5 189
rt300@5 190
rt300@8 191 ifstream theFile(jsonFile.c_str());
rt300@8 192 stringstream fileText;
rt300@8 193 string line;
rt300@8 194 if(!theFile){
rt300@8 195
rt300@8 196 firstEverAppOpen();
rt300@8 197
rt300@8 198 return;
rt300@8 199 }else{
rt300@8 200 while(theFile){
rt300@8 201 theFile >> line;
rt300@9 202 // cout << line; // lots!!!!
rt300@8 203 fileText << line;
rt300@8 204 }
rt300@8 205 theFile.close();
rt300@8 206 }
rt300@8 207
rt300@9 208 cout << "size of log JSON string:" << fileText.str().length() << "BYTES \n";
rt300@9 209
rt300@8 210 bool parsingSuccessful = reader.parse( fileText.str(), root );
rt300@8 211
rt300@8 212 if ( !parsingSuccessful )
rt300@8 213 {
rt300@8 214 // report to the user the failure and their locations in the document.
rt300@22 215 std::cout << "Failed to parse event log JSON: \n"
rt300@8 216 << reader.getFormattedErrorMessages();
rt300@8 217 return;
rt300@8 218 }
rt300@8 219
rt300@8 220 // now put user deets into variables
rt300@8 221 userName = root["userName"].asString();
rt300@8 222 deviceID = root["deviceID"].asLargestInt();
rt300@25 223 nextUploadNumber = root["uploadNumber"].asInt();
rt300@25 224 savedInteractionTime = root["savedInteractionTime"].asLargestInt();
rt300@22 225 questionnaireCompleted = root["questionnaireCompleted"].asBool();
rt300@22 226 questionnaireUploaded = root["questionnaireUploaded"].asBool();
rt300@22 227
rt300@22 228
rt300@22 229 if(questionnaireCompleted && !questionnaireUploaded){
rt300@22 230 // then read it in and upload it
rt300@22 231 Json::Value JArray = root["questionnaireAnswers"];
rt300@22 232 if(JArray.size() < 2){
rt300@22 233 cout << "Error - status of questionnaire is wierd\n";
rt300@22 234 }
rt300@22 235 for ( unsigned int i = 0; i < JArray.size(); i++ )
rt300@22 236 {
rt300@22 237 questionnaireAnswers.push_back(JArray[1].asInt());
rt300@22 238 }
rt300@22 239 uploadQuestionnaire();
rt300@22 240 }
rt300@8 241
rt300@8 242 // check for unuploaded evts
rt300@8 243 const Json::Value jlogs = root["events"];
rt300@8 244
rt300@8 245 for ( int index = 0; index < jlogs.size(); ++index ) theEvents.push_back(lEvent(jlogs[index]));
rt300@27 246 if(theEvents.size() > nextUploadQty && ! logUploadInProgress){
rt300@8 247 //try to upload
rt300@27 248 uploadEventLog(true);
rt300@8 249 }
rt300@8 250 // TODO if the total interaction time is greater than a certain amount && no questions answered - questionnaire time!
rt300@25 251 cout << "Total interaction time: " << savedInteractionTime << '\n';
rt300@9 252
rt300@8 253
rt300@9 254 }
rt300@9 255
rt300@9 256
rt300@9 257 //---------------------------------------------------------------------------
rt300@9 258
rt300@27 259 bool EventLogger::uploadEventLog(bool async){
rt300@22 260 // show indicator
rt300@27 261 logUploadInProgress = true;
rt300@25 262 cout << "^^^^^^^^ ATTEMPTING TO UPLOAD " << theEvents.size() << " EVENTS ^^^^^^^^ .\n";
rt300@27 263 if(!async){
rt300@27 264 bool success = sendToServer("eventlog", logsToJson(), async);
rt300@27 265 if(!success){
rt300@27 266 // try later
rt300@27 267 nextUploadQty += UPLOAD_CHUNK_SIZE;
rt300@27 268 }else{
rt300@27 269
rt300@27 270 // if success - clear memory
rt300@27 271 theEvents.clear();
rt300@27 272 cout << "UPLOAD SUCCESS\n";
rt300@27 273 nextUploadNumber++;
rt300@27 274 }
rt300@27 275 logUploadInProgress = false;
rt300@27 276 return success;
rt300@9 277 }else{
rt300@27 278 sendToServer("eventlog", logsToJson(), async);
rt300@9 279 }
rt300@1 280 }
rt300@8 281 //----------------------------------------------------------------------------
rt300@27 282
rt300@27 283 //----------------------------------------------------------------------------
rt300@9 284 //void EventLogger::deleteLogFile(){
rt300@8 285
rt300@8 286 //---------------------------------------------------------------------------
rt300@8 287
rt300@8 288 void EventLogger::firstEverAppOpen(){
rt300@25 289 cout<<"no event log file - first APP open\n";
rt300@25 290 nextUploadNumber = 0;
rt300@8 291 deviceID = ofGetSystemTimeMicros();
rt300@25 292 savedInteractionTime = 0;
rt300@22 293 questionnaireCompleted = false;
rt300@22 294 questionnaireUploaded = false;
rt300@8 295
rt300@24 296 ((testApp *)ofGetAppPtr())->showIntro();
rt300@25 297 consentGiven = false;
rt300@8 298
rt300@8 299 }
rt300@27 300 void EventLogger::newUser(){
rt300@27 301 cout<<"setup new user\n";
rt300@27 302 nextUploadNumber = 0;
rt300@27 303 deviceID = ofGetSystemTimeMicros();
rt300@27 304 savedInteractionTime = 0;
rt300@27 305 questionnaireCompleted = false;
rt300@27 306 questionnaireUploaded = false;
rt300@27 307 consentGiven = true; // other wise we wouldn't be doing this
rt300@27 308 ((testApp *)ofGetAppPtr())->introHidden(true); // hacky
rt300@27 309
rt300@27 310 }
rt300@8 311 //---------------------------------------------------------------------------
rt300@8 312 // called from alertView OK in iViewController
rt300@8 313 void EventLogger::setUsername(const char *u){
rt300@8 314 userName = u;
rt300@7 315
rt300@7 316 }
rt300@8 317
rt300@8 318 //---------------------------------------------------------------------------
rt300@8 319 // log zoom event
rt300@5 320 void EventLogger::logEvent(const leventType& evtType,const TwoVector& centre, const double& scale, const int& sliderID, const double& sliderVal){
rt300@3 321 //cout << "log: " << evtType << "\n";
rt300@1 322
rt300@1 323 // scroll has 2 double coords
rt300@1 324 // zoom has 1 double scale
rt300@1 325 // save preset has 2 coords
rt300@1 326 // switch view has view type
rt300@9 327 // slider change has int slider index and 1 float value
rt300@1 328
rt300@4 329 // get time for key index
rt300@4 330
rt300@5 331 // thinFactor
rt300@5 332 if(!loggingEnabled) return;
rt300@4 333 switch ( evtType ) {
rt300@4 334 case SAVE_PRESET:
rt300@5 335 theEvents.push_back(lEvent(evtType,centre.x,centre.y));
rt300@4 336 // Code
rt300@4 337 break;
rt300@4 338 case SAVE_DESET:
rt300@5 339 theEvents.push_back(lEvent(evtType,centre.x,centre.y));
rt300@4 340 break;
rt300@4 341 case SCROLL:
rt300@5 342 theEvents.push_back(lEvent(evtType,centre.x,centre.y));
rt300@5 343 break;
rt300@5 344 case SCROLL_STOPPED:
rt300@5 345 theEvents.push_back(lEvent(evtType,centre.x,centre.y));
rt300@22 346 cout << "SCROLL STOPPED EVENT\n";
rt300@22 347 break;
rt300@22 348 case SNAPPED_TO_PRESET:
rt300@22 349 theEvents.push_back(lEvent(evtType,centre.x,centre.y,sliderID));
rt300@22 350 cout << "SCROLL STOPPED EVENT\n";
rt300@4 351 break;
rt300@4 352 case ZOOM:
rt300@5 353 theEvents.push_back(lEvent(evtType,scale));
rt300@4 354 break;
rt300@4 355 case CHANGE_SLIDER:
rt300@5 356 theEvents.push_back(lEvent(evtType,sliderVal , 0.0 , sliderID));
rt300@4 357 break;
rt300@25 358 case SWAP_VIEW:
rt300@25 359 theEvents.push_back(lEvent(evtType,0.0 , 0.0 , sliderID)); // slider ID is which view
rt300@25 360 break;
rt300@4 361 default:
rt300@25 362 // default is just an event type with no values
rt300@25 363 theEvents.push_back(lEvent(evtType));
rt300@4 364 break;
rt300@1 365 }
rt300@27 366 if(theEvents.size() > nextUploadQty && !logUploadInProgress){
rt300@27 367 //try to upload asynchronously
rt300@27 368 uploadEventLog(true);
rt300@7 369 }
rt300@9 370 //sessionTime = (ofGetSystemTime() - sessionStartTime);
rt300@25 371 totalInteractionTime = savedInteractionTime + (ofGetSystemTime() - sessionStartTime);
rt300@25 372 if(totalInteractionTime > QUESTIONNAIRE_ENABLE_TIME){
rt300@25 373 TopButtonViewController *tbvc = ((testApp *)ofGetAppPtr())->topButtonViewController;
rt300@25 374 [tbvc enableQuestionButton];
rt300@25 375 }
rt300@1 376 }
rt300@8 377
rt300@8 378 //---------------------------------------------------------------------------
rt300@7 379
rt300@7 380 void EventLogger::exitAndSave(){
rt300@25 381
rt300@25 382 if(!consentGiven){
rt300@25 383 logEvent(CONSENT_DENIED);
rt300@25 384 Json::Value jlogs = logsToJson();
rt300@25 385 // try to upload TODO (no - might hang and prevent exit???)
rt300@27 386 uploadEventLog(true);
rt300@25 387 return;
rt300@25 388 }
rt300@25 389 logEvent(APP_EXITED);
rt300@25 390 savedInteractionTime = savedInteractionTime + (ofGetSystemTime() - sessionStartTime);
rt300@7 391 // save user details
rt300@8 392 string fname = ofxiPhoneGetDocumentsDirectory() + EVENT_LOG_FILENAME;
rt300@8 393
rt300@25 394 // try to upload TODO (no - might hang and prevent exit???)
rt300@27 395 // do it async because event list needs to be cleared to prevent saving on device
rt300@27 396 uploadEventLog(false);
rt300@7 397
rt300@8 398 // write to file
rt300@25 399 // json without the logs that were uploaded!
rt300@25 400 Json::Value jlogs = logsToJson();
rt300@8 401 ofFile logFile(fname,ofFile::WriteOnly);
rt300@8 402 logFile << jlogs;
rt300@8 403
rt300@8 404 }
rt300@8 405 //---------------------------------------------------------------------------
rt300@8 406
rt300@8 407 Json::Value EventLogger::logsToJson(){
rt300@8 408 // put all logged events into Json formatted string
rt300@8 409 Json::Value root;
rt300@8 410
rt300@8 411 vector<lEvent>::iterator eventIter;
rt300@8 412
rt300@22 413 root["programVersion"] = PROGRAM_VERSION;
rt300@8 414 root["userName"] = userName;
rt300@8 415 root["deviceID"] = deviceID;
rt300@25 416 root["uploadNumber"] = nextUploadNumber;
rt300@22 417 root["iOSdeviceType"] = iOSdeviceType;
rt300@25 418 root["savedInteractionTime"] = savedInteractionTime;
rt300@22 419 root["questionnaireCompleted"] = questionnaireCompleted;
rt300@22 420 root["questionnaireUploaded"] = questionnaireUploaded;
rt300@22 421 if(questionnaireCompleted && !questionnaireUploaded){
rt300@22 422 root["qAnswers"] = questionnaireToJson();
rt300@22 423 }
rt300@8 424
rt300@8 425 int i = 0;
rt300@8 426 for(eventIter = theEvents.begin(); eventIter < theEvents.end(); eventIter++){
rt300@8 427 root["events"][i] = (*eventIter).eventToJson();
rt300@8 428 i++;
rt300@7 429 }
rt300@25 430 root["numEventsHere"] = i;
rt300@8 431 return root;
rt300@8 432 }
rt300@22 433
rt300@8 434 //---------------------------------------------------------------------------
rt300@22 435
rt300@22 436 Json::Value EventLogger::questionnaireToJson(){
rt300@22 437 // put all answers into Json formatted string
rt300@22 438 Json::Value root;
rt300@22 439
rt300@22 440 vector<int>::iterator aIter;
rt300@22 441
rt300@22 442 Json::Value questionnaire;
rt300@22 443
rt300@22 444 int i = 0;
rt300@22 445 for(aIter = questionnaireAnswers.begin(); aIter < questionnaireAnswers.end(); aIter++){
rt300@22 446 questionnaire[i] = (*aIter);
rt300@22 447 i++;
rt300@22 448 }
rt300@22 449
rt300@22 450 root["qAnswers"] = questionnaire;
rt300@22 451 root["userName"] = userName;
rt300@22 452 root["deviceID"] = deviceID;
rt300@22 453 root["iOSdeviceType"] = iOSdeviceType;
rt300@22 454 root["programVersion"] = PROGRAM_VERSION;
rt300@22 455
rt300@22 456 return root;
rt300@22 457 }
rt300@8 458 //---------------------------------------------------------------------------
rt300@8 459 //---------------------------------------------------------------------------
rt300@22 460 //---------------------------------------------------------------------------