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@22
|
23
|
rt300@22
|
24
|
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@8
|
29 }
|
rt300@8
|
30 //---------------------------------------------------------------------------
|
rt300@24
|
31 // draw() - show path of last N scroll events - can be scrubbed along?
|
rt300@24
|
32 //
|
rt300@24
|
33 //---------------------------------------------------------------------------
|
rt300@8
|
34 void EventLogger::init(){
|
rt300@4
|
35
|
rt300@8
|
36 readJsonToLog(ofxiPhoneGetDocumentsDirectory() + EVENT_LOG_FILENAME);
|
rt300@8
|
37 sessionStartTime = ofGetSystemTime();
|
rt300@9
|
38
|
rt300@9
|
39 testConnection();
|
rt300@7
|
40
|
rt300@25
|
41 logEvent(APP_STARTED);
|
rt300@8
|
42 }
|
rt300@8
|
43 //---------------------------------------------------------------------------
|
rt300@22
|
44 void EventLogger::questionnaireAnswersObtained(vector<int> answers){
|
rt300@22
|
45
|
rt300@22
|
46 questionnaireCompleted = true;
|
rt300@22
|
47 questionnaireAnswers = answers;
|
rt300@22
|
48
|
rt300@22
|
49 uploadQuestionnaire();
|
rt300@22
|
50
|
rt300@22
|
51 }
|
rt300@22
|
52 //---------------------------------------------------------------------------
|
rt300@22
|
53 bool EventLogger::uploadQuestionnaire(){
|
rt300@22
|
54 // show indicator
|
rt300@22
|
55 cout << "^^^^^^^^ UPLOADING QUESTIONNAIRE ^^^^^^^^ \n";
|
rt300@22
|
56
|
rt300@22
|
57 questionnaireUploaded = sendToServer("questionnaire", questionnaireToJson());
|
rt300@22
|
58 return questionnaireUploaded;
|
rt300@22
|
59 }
|
rt300@22
|
60 //---------------------------------------------------------------------------
|
rt300@22
|
61 bool EventLogger::sendToServer(string functionName, Json::Value jsonData){
|
rt300@22
|
62 bool sent;
|
rt300@22
|
63 string request;
|
rt300@22
|
64
|
rt300@22
|
65 if(functionName == "testConnection"){
|
rt300@22
|
66 request = "http://127.0.0.1:8080/testservice/testConnection?jsontext=";
|
rt300@22
|
67 }else if(functionName == "questionnaire"){
|
rt300@22
|
68 request = "http://127.0.0.1:8080/testservice/questionnaire?jsontext=";
|
rt300@22
|
69 }else if(functionName == "eventlog"){
|
rt300@22
|
70 request = "http://127.0.0.1:8080/testservice/eventlog?jsontext=";
|
rt300@22
|
71 }
|
rt300@22
|
72 Json::FastWriter writer;
|
rt300@22
|
73 string jsontext = writer.write( jsonData );
|
rt300@22
|
74
|
rt300@22
|
75 if (!jsontext.empty() && jsontext[jsontext.length()-1] == '\n') {
|
rt300@22
|
76 jsontext.erase(jsontext.length()-1);
|
rt300@22
|
77 }
|
rt300@22
|
78
|
rt300@22
|
79 request.append(jsontext);
|
rt300@22
|
80
|
rt300@9
|
81 ofURLFileLoader fileLoader;
|
rt300@9
|
82 ofHttpResponse resp;
|
rt300@22
|
83 resp = fileLoader.get(request);
|
rt300@24
|
84 //fileLoader.getAsync(request);
|
rt300@9
|
85 cout << "HTTP STATUS " << resp.status << "\n";
|
rt300@9
|
86 cout << "HTTP ERROR " << resp.error << "\n";
|
rt300@22
|
87 cout << "HTTP DATA " << resp.data << "\n"; // ofBuffer
|
rt300@9
|
88
|
rt300@22
|
89 stringstream response;
|
rt300@22
|
90 response << resp.data;
|
rt300@22
|
91
|
rt300@22
|
92 if (resp.status == 200){
|
rt300@22
|
93 if(response.str() == "OK"){
|
rt300@22
|
94
|
rt300@22
|
95 sent = true;
|
rt300@22
|
96 }else{
|
rt300@22
|
97 // not ok
|
rt300@22
|
98 // problem serverside
|
rt300@22
|
99 sent = false;
|
rt300@22
|
100 }
|
rt300@9
|
101 }else{
|
rt300@22
|
102
|
rt300@22
|
103 sent = false;
|
rt300@9
|
104 // SHOW AN ALERT TO USER?
|
rt300@9
|
105 }
|
rt300@22
|
106 return sent;
|
rt300@22
|
107 }
|
rt300@22
|
108 //---------------------------------------------------------------------------
|
rt300@22
|
109 bool EventLogger::testConnection(){
|
rt300@22
|
110 Json::Value root;
|
rt300@22
|
111 root["test"] = "test";
|
rt300@22
|
112
|
rt300@22
|
113
|
rt300@22
|
114 serverConnectionOK = sendToServer("testConnection", root);
|
rt300@22
|
115 if (serverConnectionOK){
|
rt300@22
|
116 cout << "^^^^^^^^ server connection OK ^^^^^^^^ \n";
|
rt300@22
|
117 }else{
|
rt300@22
|
118 cout << "server connection ERROR \n";
|
rt300@22
|
119 }
|
rt300@9
|
120 }
|
rt300@9
|
121 //---------------------------------------------------------------------------
|
rt300@8
|
122 void EventLogger::readJsonToLog(const string &jsonFile){
|
rt300@8
|
123 Json::Value root;
|
rt300@8
|
124 Json::Reader reader;
|
rt300@5
|
125
|
rt300@5
|
126
|
rt300@8
|
127 ifstream theFile(jsonFile.c_str());
|
rt300@8
|
128 stringstream fileText;
|
rt300@8
|
129 string line;
|
rt300@8
|
130 if(!theFile){
|
rt300@8
|
131
|
rt300@8
|
132 firstEverAppOpen();
|
rt300@8
|
133
|
rt300@8
|
134 return;
|
rt300@8
|
135 }else{
|
rt300@8
|
136 while(theFile){
|
rt300@8
|
137 theFile >> line;
|
rt300@9
|
138 // cout << line; // lots!!!!
|
rt300@8
|
139 fileText << line;
|
rt300@8
|
140 }
|
rt300@8
|
141 theFile.close();
|
rt300@8
|
142 }
|
rt300@8
|
143
|
rt300@9
|
144 cout << "size of log JSON string:" << fileText.str().length() << "BYTES \n";
|
rt300@9
|
145
|
rt300@8
|
146 bool parsingSuccessful = reader.parse( fileText.str(), root );
|
rt300@8
|
147
|
rt300@8
|
148 if ( !parsingSuccessful )
|
rt300@8
|
149 {
|
rt300@8
|
150 // report to the user the failure and their locations in the document.
|
rt300@22
|
151 std::cout << "Failed to parse event log JSON: \n"
|
rt300@8
|
152 << reader.getFormattedErrorMessages();
|
rt300@8
|
153 return;
|
rt300@8
|
154 }
|
rt300@8
|
155
|
rt300@8
|
156 // now put user deets into variables
|
rt300@8
|
157 userName = root["userName"].asString();
|
rt300@8
|
158 deviceID = root["deviceID"].asLargestInt();
|
rt300@25
|
159 nextUploadNumber = root["uploadNumber"].asInt();
|
rt300@25
|
160 savedInteractionTime = root["savedInteractionTime"].asLargestInt();
|
rt300@22
|
161 questionnaireCompleted = root["questionnaireCompleted"].asBool();
|
rt300@22
|
162 questionnaireUploaded = root["questionnaireUploaded"].asBool();
|
rt300@22
|
163
|
rt300@22
|
164
|
rt300@22
|
165 if(questionnaireCompleted && !questionnaireUploaded){
|
rt300@22
|
166 // then read it in and upload it
|
rt300@22
|
167 Json::Value JArray = root["questionnaireAnswers"];
|
rt300@22
|
168 if(JArray.size() < 2){
|
rt300@22
|
169 cout << "Error - status of questionnaire is wierd\n";
|
rt300@22
|
170 }
|
rt300@22
|
171 for ( unsigned int i = 0; i < JArray.size(); i++ )
|
rt300@22
|
172 {
|
rt300@22
|
173 questionnaireAnswers.push_back(JArray[1].asInt());
|
rt300@22
|
174 }
|
rt300@22
|
175 uploadQuestionnaire();
|
rt300@22
|
176 }
|
rt300@8
|
177
|
rt300@8
|
178 // check for unuploaded evts
|
rt300@8
|
179 const Json::Value jlogs = root["events"];
|
rt300@8
|
180
|
rt300@8
|
181 for ( int index = 0; index < jlogs.size(); ++index ) theEvents.push_back(lEvent(jlogs[index]));
|
rt300@9
|
182 if(theEvents.size() > nextUploadQty){
|
rt300@8
|
183 //try to upload
|
rt300@22
|
184 uploadEventLog();
|
rt300@8
|
185 }
|
rt300@8
|
186 // TODO if the total interaction time is greater than a certain amount && no questions answered - questionnaire time!
|
rt300@25
|
187 cout << "Total interaction time: " << savedInteractionTime << '\n';
|
rt300@9
|
188
|
rt300@8
|
189
|
rt300@9
|
190 }
|
rt300@9
|
191
|
rt300@9
|
192
|
rt300@9
|
193 //---------------------------------------------------------------------------
|
rt300@9
|
194
|
rt300@22
|
195 bool EventLogger::uploadEventLog(){
|
rt300@22
|
196 // show indicator
|
rt300@25
|
197
|
rt300@25
|
198 cout << "^^^^^^^^ ATTEMPTING TO UPLOAD " << theEvents.size() << " EVENTS ^^^^^^^^ .\n";
|
rt300@9
|
199
|
rt300@22
|
200 bool logUploaded = sendToServer("eventlog", logsToJson());
|
rt300@22
|
201 if(!logUploaded){
|
rt300@9
|
202 // try later
|
rt300@25
|
203 nextUploadQty += UPLOAD_CHUNK_SIZE;
|
rt300@9
|
204 }else{
|
rt300@9
|
205
|
rt300@9
|
206 // if success - clear memory
|
rt300@9
|
207 theEvents.clear();
|
rt300@25
|
208 cout << "UPLOAD SUCCESS\n";
|
rt300@25
|
209 nextUploadNumber++;
|
rt300@9
|
210 }
|
rt300@22
|
211 return logUploaded;
|
rt300@8
|
212
|
rt300@1
|
213 }
|
rt300@8
|
214 //----------------------------------------------------------------------------
|
rt300@9
|
215 //void EventLogger::deleteLogFile(){
|
rt300@8
|
216
|
rt300@8
|
217 //---------------------------------------------------------------------------
|
rt300@8
|
218
|
rt300@8
|
219 void EventLogger::firstEverAppOpen(){
|
rt300@25
|
220 cout<<"no event log file - first APP open\n";
|
rt300@25
|
221 nextUploadNumber = 0;
|
rt300@8
|
222 deviceID = ofGetSystemTimeMicros();
|
rt300@25
|
223 savedInteractionTime = 0;
|
rt300@22
|
224 questionnaireCompleted = false;
|
rt300@22
|
225 questionnaireUploaded = false;
|
rt300@8
|
226
|
rt300@24
|
227 ((testApp *)ofGetAppPtr())->showIntro();
|
rt300@25
|
228 consentGiven = false;
|
rt300@8
|
229
|
rt300@8
|
230 }
|
rt300@8
|
231 //---------------------------------------------------------------------------
|
rt300@8
|
232 // called from alertView OK in iViewController
|
rt300@8
|
233 void EventLogger::setUsername(const char *u){
|
rt300@8
|
234 userName = u;
|
rt300@7
|
235
|
rt300@7
|
236 }
|
rt300@8
|
237
|
rt300@8
|
238 //---------------------------------------------------------------------------
|
rt300@8
|
239 // log zoom event
|
rt300@5
|
240 void EventLogger::logEvent(const leventType& evtType,const TwoVector& centre, const double& scale, const int& sliderID, const double& sliderVal){
|
rt300@3
|
241 //cout << "log: " << evtType << "\n";
|
rt300@1
|
242
|
rt300@1
|
243 // scroll has 2 double coords
|
rt300@1
|
244 // zoom has 1 double scale
|
rt300@1
|
245 // save preset has 2 coords
|
rt300@1
|
246 // switch view has view type
|
rt300@9
|
247 // slider change has int slider index and 1 float value
|
rt300@1
|
248
|
rt300@4
|
249 // get time for key index
|
rt300@4
|
250
|
rt300@5
|
251 // thinFactor
|
rt300@5
|
252 if(!loggingEnabled) return;
|
rt300@4
|
253 switch ( evtType ) {
|
rt300@4
|
254 case SAVE_PRESET:
|
rt300@5
|
255 theEvents.push_back(lEvent(evtType,centre.x,centre.y));
|
rt300@4
|
256 // Code
|
rt300@4
|
257 break;
|
rt300@4
|
258 case SAVE_DESET:
|
rt300@5
|
259 theEvents.push_back(lEvent(evtType,centre.x,centre.y));
|
rt300@4
|
260 break;
|
rt300@4
|
261 case SCROLL:
|
rt300@5
|
262 theEvents.push_back(lEvent(evtType,centre.x,centre.y));
|
rt300@5
|
263 break;
|
rt300@5
|
264 case SCROLL_STOPPED:
|
rt300@5
|
265 theEvents.push_back(lEvent(evtType,centre.x,centre.y));
|
rt300@22
|
266 cout << "SCROLL STOPPED EVENT\n";
|
rt300@22
|
267 break;
|
rt300@22
|
268 case SNAPPED_TO_PRESET:
|
rt300@22
|
269 theEvents.push_back(lEvent(evtType,centre.x,centre.y,sliderID));
|
rt300@22
|
270 cout << "SCROLL STOPPED EVENT\n";
|
rt300@4
|
271 break;
|
rt300@4
|
272 case ZOOM:
|
rt300@5
|
273 theEvents.push_back(lEvent(evtType,scale));
|
rt300@4
|
274 break;
|
rt300@4
|
275 case CHANGE_SLIDER:
|
rt300@5
|
276 theEvents.push_back(lEvent(evtType,sliderVal , 0.0 , sliderID));
|
rt300@4
|
277 break;
|
rt300@25
|
278 case SWAP_VIEW:
|
rt300@25
|
279 theEvents.push_back(lEvent(evtType,0.0 , 0.0 , sliderID)); // slider ID is which view
|
rt300@25
|
280 break;
|
rt300@4
|
281 default:
|
rt300@25
|
282 // default is just an event type with no values
|
rt300@25
|
283 theEvents.push_back(lEvent(evtType));
|
rt300@4
|
284 break;
|
rt300@1
|
285 }
|
rt300@8
|
286 if(theEvents.size() > nextUploadQty){
|
rt300@7
|
287 //try to upload
|
rt300@22
|
288 uploadEventLog();
|
rt300@7
|
289 }
|
rt300@9
|
290 //sessionTime = (ofGetSystemTime() - sessionStartTime);
|
rt300@25
|
291 totalInteractionTime = savedInteractionTime + (ofGetSystemTime() - sessionStartTime);
|
rt300@25
|
292 if(totalInteractionTime > QUESTIONNAIRE_ENABLE_TIME){
|
rt300@25
|
293 TopButtonViewController *tbvc = ((testApp *)ofGetAppPtr())->topButtonViewController;
|
rt300@25
|
294 [tbvc enableQuestionButton];
|
rt300@25
|
295 }
|
rt300@1
|
296 }
|
rt300@8
|
297
|
rt300@8
|
298 //---------------------------------------------------------------------------
|
rt300@7
|
299
|
rt300@7
|
300 void EventLogger::exitAndSave(){
|
rt300@25
|
301
|
rt300@25
|
302 if(!consentGiven){
|
rt300@25
|
303 logEvent(CONSENT_DENIED);
|
rt300@25
|
304 Json::Value jlogs = logsToJson();
|
rt300@25
|
305 // try to upload TODO (no - might hang and prevent exit???)
|
rt300@25
|
306 uploadEventLog();
|
rt300@25
|
307 return;
|
rt300@25
|
308 }
|
rt300@25
|
309 logEvent(APP_EXITED);
|
rt300@25
|
310 savedInteractionTime = savedInteractionTime + (ofGetSystemTime() - sessionStartTime);
|
rt300@7
|
311 // save user details
|
rt300@8
|
312 string fname = ofxiPhoneGetDocumentsDirectory() + EVENT_LOG_FILENAME;
|
rt300@8
|
313
|
rt300@25
|
314 // try to upload TODO (no - might hang and prevent exit???)
|
rt300@22
|
315 uploadEventLog();
|
rt300@7
|
316
|
rt300@8
|
317 // write to file
|
rt300@25
|
318 // json without the logs that were uploaded!
|
rt300@25
|
319 Json::Value jlogs = logsToJson();
|
rt300@8
|
320 ofFile logFile(fname,ofFile::WriteOnly);
|
rt300@8
|
321 logFile << jlogs;
|
rt300@8
|
322
|
rt300@8
|
323 }
|
rt300@8
|
324 //---------------------------------------------------------------------------
|
rt300@8
|
325
|
rt300@8
|
326 Json::Value EventLogger::logsToJson(){
|
rt300@8
|
327 // put all logged events into Json formatted string
|
rt300@8
|
328 Json::Value root;
|
rt300@8
|
329
|
rt300@8
|
330 vector<lEvent>::iterator eventIter;
|
rt300@8
|
331
|
rt300@22
|
332 root["programVersion"] = PROGRAM_VERSION;
|
rt300@8
|
333 root["userName"] = userName;
|
rt300@8
|
334 root["deviceID"] = deviceID;
|
rt300@25
|
335 root["uploadNumber"] = nextUploadNumber;
|
rt300@22
|
336 root["iOSdeviceType"] = iOSdeviceType;
|
rt300@25
|
337 root["savedInteractionTime"] = savedInteractionTime;
|
rt300@22
|
338 root["questionnaireCompleted"] = questionnaireCompleted;
|
rt300@22
|
339 root["questionnaireUploaded"] = questionnaireUploaded;
|
rt300@22
|
340 if(questionnaireCompleted && !questionnaireUploaded){
|
rt300@22
|
341 root["qAnswers"] = questionnaireToJson();
|
rt300@22
|
342 }
|
rt300@8
|
343
|
rt300@8
|
344 int i = 0;
|
rt300@8
|
345 for(eventIter = theEvents.begin(); eventIter < theEvents.end(); eventIter++){
|
rt300@8
|
346 root["events"][i] = (*eventIter).eventToJson();
|
rt300@8
|
347 i++;
|
rt300@7
|
348 }
|
rt300@25
|
349 root["numEventsHere"] = i;
|
rt300@8
|
350 return root;
|
rt300@8
|
351 }
|
rt300@22
|
352
|
rt300@8
|
353 //---------------------------------------------------------------------------
|
rt300@22
|
354
|
rt300@22
|
355 Json::Value EventLogger::questionnaireToJson(){
|
rt300@22
|
356 // put all answers into Json formatted string
|
rt300@22
|
357 Json::Value root;
|
rt300@22
|
358
|
rt300@22
|
359 vector<int>::iterator aIter;
|
rt300@22
|
360
|
rt300@22
|
361 Json::Value questionnaire;
|
rt300@22
|
362
|
rt300@22
|
363 int i = 0;
|
rt300@22
|
364 for(aIter = questionnaireAnswers.begin(); aIter < questionnaireAnswers.end(); aIter++){
|
rt300@22
|
365 questionnaire[i] = (*aIter);
|
rt300@22
|
366 i++;
|
rt300@22
|
367 }
|
rt300@22
|
368
|
rt300@22
|
369 root["qAnswers"] = questionnaire;
|
rt300@22
|
370 root["userName"] = userName;
|
rt300@22
|
371 root["deviceID"] = deviceID;
|
rt300@22
|
372 root["iOSdeviceType"] = iOSdeviceType;
|
rt300@22
|
373 root["programVersion"] = PROGRAM_VERSION;
|
rt300@22
|
374
|
rt300@22
|
375 return root;
|
rt300@22
|
376 }
|
rt300@8
|
377 //---------------------------------------------------------------------------
|
rt300@8
|
378 //---------------------------------------------------------------------------
|
rt300@22
|
379 //---------------------------------------------------------------------------
|