rt300@0: // rt300@0: // eventLogger.mm rt300@0: // oscSenderExample rt300@0: // rt300@0: // Created by Robert Tubb on 05/11/2012. rt300@0: // rt300@0: // rt300@4: rt300@8: //--------------------------------------------------------------------------- rt300@0: #include "eventLogger.h" rt300@1: rt300@8: rt300@1: EventLogger eventLogger; rt300@8: extern IViewController *iViewController; rt300@1: rt300@8: //--------------------------------------------------------------------------- rt300@1: EventLogger::EventLogger(){ rt300@14: //QuestionnaireViewController * questionnaireViewController; rt300@14: rt300@14: questionnaireViewController = [[QuestionnaireViewController alloc] initWithNibName:@"QuestionnaireViewController" bundle:nil]; rt300@14: rt300@14: rt300@8: rt300@14: rt300@8: loggingEnabled = true; rt300@9: internetConnectionOK = false; rt300@9: nextUploadQty = 5000; // amount of data uploaded is always more than 5000 events rt300@8: } rt300@8: //--------------------------------------------------------------------------- rt300@8: void EventLogger::init(){ rt300@4: rt300@8: readJsonToLog(ofxiPhoneGetDocumentsDirectory() + EVENT_LOG_FILENAME); rt300@8: sessionStartTime = ofGetSystemTime(); rt300@9: rt300@9: testConnection(); rt300@7: rt300@14: [ofxiPhoneGetGLParentView() addSubview:questionnaireViewController.view]; rt300@8: } rt300@8: //--------------------------------------------------------------------------- rt300@9: bool EventLogger::testConnection(){ rt300@14: string url = "http://127.0.0.1:8080/testservice/testConnection?testtext={%22test%22=%22sometext%22}"; rt300@9: bool success = false; rt300@9: ofURLFileLoader fileLoader; rt300@9: ofHttpResponse resp; rt300@9: resp = fileLoader.get(url); rt300@9: rt300@9: cout << "HTTP STATUS " << resp.status << "\n"; rt300@9: cout << "HTTP ERROR " << resp.error << "\n"; rt300@9: cout << "HTTP DATA " << resp.data << "\n"; rt300@9: rt300@9: if (resp.status == 0){ rt300@9: success = true; rt300@9: internetConnectionOK = true; rt300@9: }else{ rt300@9: success = false; rt300@9: internetConnectionOK = false; rt300@9: // SHOW AN ALERT TO USER? rt300@9: } rt300@9: return success; rt300@9: } rt300@9: //--------------------------------------------------------------------------- rt300@8: void EventLogger::readJsonToLog(const string &jsonFile){ rt300@8: Json::Value root; rt300@8: Json::Reader reader; rt300@5: rt300@5: rt300@8: ifstream theFile(jsonFile.c_str()); rt300@8: stringstream fileText; rt300@8: string line; rt300@8: if(!theFile){ rt300@8: cout<<"no event log file - first APP open\n"; rt300@8: rt300@8: firstEverAppOpen(); rt300@8: rt300@8: return; rt300@8: }else{ rt300@8: rt300@8: while(theFile){ rt300@8: theFile >> line; rt300@9: // cout << line; // lots!!!! rt300@8: fileText << line; rt300@8: rt300@8: } rt300@8: rt300@8: theFile.close(); rt300@8: } rt300@8: rt300@9: cout << "size of log JSON string:" << fileText.str().length() << "BYTES \n"; rt300@9: rt300@8: bool parsingSuccessful = reader.parse( fileText.str(), root ); rt300@8: rt300@8: if ( !parsingSuccessful ) rt300@8: { rt300@8: // report to the user the failure and their locations in the document. rt300@8: std::cout << "Failed to parse preset JSON\n" rt300@8: << reader.getFormattedErrorMessages(); rt300@8: return; rt300@8: } rt300@8: rt300@8: // now put user deets into variables rt300@8: userName = root["userName"].asString(); rt300@8: deviceID = root["deviceID"].asLargestInt(); rt300@8: totalInteractionTime = root["totalInteractionTime"].asLargestInt(); rt300@8: rt300@8: // check for unuploaded evts rt300@8: const Json::Value jlogs = root["events"]; rt300@8: rt300@8: for ( int index = 0; index < jlogs.size(); ++index ) theEvents.push_back(lEvent(jlogs[index])); rt300@9: if(theEvents.size() > nextUploadQty){ rt300@8: //try to upload rt300@8: attemptUpload(); rt300@8: } rt300@8: // TODO if the total interaction time is greater than a certain amount && no questions answered - questionnaire time! rt300@14: cout << "Total interaction time: " << totalInteractionTime << '\n'; rt300@8: rt300@14: if(totalInteractionTime > 0){ rt300@14: // questionnaireViewController.show; rt300@14: [questionnaireViewController show:(id)this]; rt300@14: rt300@14: //IF THE VIEW IS HIDDEN LETS BRING IT BACK! rt300@14: if( questionnaireViewController.view.hidden ){ rt300@14: questionnaireViewController.view.hidden = NO; rt300@14: } rt300@14: rt300@14: } rt300@8: // is there logged stuff that hasn't been uploaded yet? rt300@8: rt300@8: // don't actually need to load old ones unless uploading? or saving... rt300@8: //while(eventLogFile >> nextLine){ rt300@8: rt300@8: //} rt300@9: rt300@8: rt300@9: } rt300@9: rt300@9: rt300@9: //--------------------------------------------------------------------------- rt300@9: rt300@9: bool EventLogger::attemptUpload(){ rt300@9: rt300@9: // do simple check of internet connection ? rt300@9: // if not connected return rt300@9: if(!internetConnectionOK){ rt300@9: return false; rt300@9: } rt300@9: // show indicator rt300@9: cout << "UPLOADING: " << theEvents.size() << " logs.\n"; rt300@9: rt300@9: // if numlogs > 500000 show alert...? rt300@9: rt300@9: string url = "http://127.0.0.1:8080/testservice/eventlog?jsontext="; rt300@9: url.append(logsToJson().toStyledString()); rt300@9: rt300@9: rt300@9: ofURLFileLoader fileLoader; rt300@9: ofHttpResponse resp; rt300@9: resp = fileLoader.get(url); // Does this sit and wait and arse up interaction? rt300@9: rt300@9: cout << "HTTP STATUS " << resp.status << "\n"; rt300@9: cout << "HTTP ERROR " << resp.error << "\n"; rt300@9: cout << "HTTP DATA " << resp.data << "\n"; rt300@9: rt300@9: bool uploaded = false; rt300@9: if (resp.status == 0) uploaded = true; // should do a check on server, and report in data ? rt300@9: if(!uploaded){ rt300@9: // try later rt300@9: nextUploadQty += 5000; rt300@9: }else{ rt300@9: rt300@9: // if success - clear memory rt300@9: theEvents.clear(); rt300@9: } rt300@9: return uploaded; rt300@8: rt300@1: } rt300@1: rt300@8: //---------------------------------------------------------------------------- rt300@9: //void EventLogger::deleteLogFile(){ rt300@8: rt300@8: //--------------------------------------------------------------------------- rt300@8: rt300@8: void EventLogger::firstEverAppOpen(){ rt300@8: deviceID = ofGetSystemTimeMicros(); rt300@8: totalInteractionTime = 0; rt300@8: rt300@9: [iViewController showUserNamePrompt]; rt300@9: // then we get userName via setUsername, called from button delegate rt300@8: rt300@8: } rt300@8: //--------------------------------------------------------------------------- rt300@8: // called from alertView OK in iViewController rt300@8: void EventLogger::setUsername(const char *u){ rt300@8: userName = u; rt300@7: rt300@7: } rt300@8: rt300@8: //--------------------------------------------------------------------------- rt300@8: // log zoom event rt300@5: void EventLogger::logEvent(const leventType& evtType,const TwoVector& centre, const double& scale, const int& sliderID, const double& sliderVal){ rt300@3: //cout << "log: " << evtType << "\n"; rt300@1: rt300@1: // scroll has 2 double coords rt300@1: // zoom has 1 double scale rt300@1: // save preset has 2 coords rt300@1: // switch view has view type rt300@9: // slider change has int slider index and 1 float value rt300@1: rt300@4: // get time for key index rt300@4: rt300@5: // thinFactor rt300@5: if(!loggingEnabled) return; rt300@4: switch ( evtType ) { rt300@4: case SAVE_PRESET: rt300@5: theEvents.push_back(lEvent(evtType,centre.x,centre.y)); rt300@4: // Code rt300@4: break; rt300@4: case SAVE_DESET: rt300@5: theEvents.push_back(lEvent(evtType,centre.x,centre.y)); rt300@4: break; rt300@4: case SCROLL: rt300@5: theEvents.push_back(lEvent(evtType,centre.x,centre.y)); rt300@5: break; rt300@5: case SCROLL_STOPPED: rt300@5: theEvents.push_back(lEvent(evtType,centre.x,centre.y)); rt300@4: break; rt300@4: case ZOOM: rt300@5: theEvents.push_back(lEvent(evtType,scale)); rt300@4: break; rt300@4: case CHANGE_SLIDER: rt300@5: theEvents.push_back(lEvent(evtType,sliderVal , 0.0 , sliderID)); rt300@4: break; rt300@4: default: rt300@4: // Code rt300@4: break; rt300@1: } rt300@8: if(theEvents.size() > nextUploadQty){ rt300@7: //try to upload rt300@7: attemptUpload(); rt300@7: } rt300@9: //sessionTime = (ofGetSystemTime() - sessionStartTime); rt300@7: rt300@1: rt300@1: } rt300@8: rt300@8: //--------------------------------------------------------------------------- rt300@1: void EventLogger::sendHttp(){ rt300@1: rt300@5: string url = "http://www.rootnot.co.uk/cgi-bin/zoomlogs.cgi"; rt300@1: ofURLFileLoader fileLoader; rt300@1: ofHttpResponse resp; rt300@1: resp = fileLoader.get(url); rt300@1: cout << "HTTP STATUS " << resp.status << "\n"; rt300@1: cout << "HTTP ERROR " << resp.error << "\n"; rt300@1: cout << "HTTP DATA " << resp.data << "\n"; rt300@7: } rt300@7: rt300@7: rt300@7: rt300@8: //--------------------------------------------------------------------------- rt300@7: rt300@7: void EventLogger::exitAndSave(){ rt300@8: totalInteractionTime = totalInteractionTime + (ofGetSystemTime() - sessionStartTime); rt300@7: // save user details rt300@8: string fname = ofxiPhoneGetDocumentsDirectory() + EVENT_LOG_FILENAME; rt300@8: rt300@8: Json::Value jlogs = logsToJson(); rt300@8: // try to upload rt300@8: bool uploaded = attemptUpload(); rt300@7: rt300@8: // write to file rt300@8: rt300@8: ofFile logFile(fname,ofFile::WriteOnly); rt300@8: logFile << jlogs; rt300@8: rt300@8: } rt300@8: //--------------------------------------------------------------------------- rt300@8: rt300@8: Json::Value EventLogger::logsToJson(){ rt300@8: // put all logged events into Json formatted string rt300@8: Json::Value root; rt300@8: rt300@8: vector::iterator eventIter; rt300@8: rt300@8: root["userName"] = userName; rt300@8: root["deviceID"] = deviceID; rt300@8: root["totalInteractionTime"] = totalInteractionTime; rt300@8: rt300@8: int i = 0; rt300@8: for(eventIter = theEvents.begin(); eventIter < theEvents.end(); eventIter++){ rt300@8: root["events"][i] = (*eventIter).eventToJson(); rt300@8: i++; rt300@7: } rt300@8: rt300@8: return root; rt300@8: } rt300@8: //--------------------------------------------------------------------------- rt300@8: //--------------------------------------------------------------------------- rt300@8: //---------------------------------------------------------------------------