854 lines
29 KiB
C#
854 lines
29 KiB
C#
using System;
|
|
using GameAnalyticsSDK.Net.Threading;
|
|
using GameAnalyticsSDK.Net.Logging;
|
|
using System.Collections.Generic;
|
|
using GameAnalyticsSDK.Net.Store;
|
|
using GameAnalyticsSDK.Net.Utilities;
|
|
using GameAnalyticsSDK.Net.Http;
|
|
using GameAnalyticsSDK.Net.State;
|
|
using GameAnalyticsSDK.Net.Validators;
|
|
using System.Globalization;
|
|
|
|
namespace GameAnalyticsSDK.Net.Events
|
|
{
|
|
internal class GAEvents
|
|
{
|
|
#region Fields and properties
|
|
|
|
private static readonly GAEvents _instance = new GAEvents();
|
|
private const string CategorySessionStart = "user";
|
|
private const string CategorySessionEnd = "session_end";
|
|
private const string CategoryDesign = "design";
|
|
private const string CategoryBusiness = "business";
|
|
private const string CategoryProgression = "progression";
|
|
private const string CategoryResource = "resource";
|
|
private const string CategoryError = "error";
|
|
private bool isRunning;
|
|
private bool keepRunning;
|
|
private const double ProcessEventsIntervalInSeconds = 8.0;
|
|
private const int MaxEventCount = 500;
|
|
|
|
private static GAEvents Instance
|
|
{
|
|
get
|
|
{
|
|
return _instance;
|
|
}
|
|
}
|
|
|
|
#endregion // Fields and properties
|
|
|
|
private GAEvents()
|
|
{
|
|
}
|
|
|
|
#region Public methods
|
|
|
|
public static void StopEventQueue()
|
|
{
|
|
Instance.keepRunning = false;
|
|
}
|
|
|
|
public static void EnsureEventQueueIsRunning()
|
|
{
|
|
Instance.keepRunning = true;
|
|
|
|
if(!Instance.isRunning)
|
|
{
|
|
Instance.isRunning = true;
|
|
GAThreading.ScheduleTimer(ProcessEventsIntervalInSeconds, "processEventQueue", ProcessEventQueue);
|
|
}
|
|
}
|
|
|
|
public static void AddSessionStartEvent()
|
|
{
|
|
if(!GAState.IsEventSubmissionEnabled)
|
|
{
|
|
return;
|
|
}
|
|
|
|
string categorySessionStart = CategorySessionStart;
|
|
|
|
// Event specific data
|
|
JSONObject eventDict = new JSONObject();
|
|
eventDict["category"] = categorySessionStart;
|
|
|
|
// Increment session number and persist
|
|
GAState.IncrementSessionNum();
|
|
GAStore.SetState(GAState.SessionNumKey, GAState.SessionNum.ToString(CultureInfo.InvariantCulture));
|
|
|
|
// Add custom dimensions
|
|
AddDimensionsToEvent(eventDict);
|
|
|
|
// Add to store
|
|
AddEventToStore(eventDict);
|
|
|
|
// Log
|
|
GALogger.I("Add SESSION START event");
|
|
|
|
// Send event right away
|
|
ProcessEvents(categorySessionStart, false);
|
|
}
|
|
|
|
public static void AddSessionEndEvent()
|
|
{
|
|
if(!GAState.IsEventSubmissionEnabled)
|
|
{
|
|
return;
|
|
}
|
|
|
|
long session_start_ts = GAState.SessionStart;
|
|
long client_ts_adjusted = GAState.GetClientTsAdjusted();
|
|
long sessionLength = client_ts_adjusted - session_start_ts;
|
|
|
|
if(sessionLength < 0)
|
|
{
|
|
// Should never happen.
|
|
// Could be because of edge cases regarding time altering on device.
|
|
GALogger.W("Session length was calculated to be less then 0. Should not be possible. Resetting to 0.");
|
|
sessionLength = 0;
|
|
}
|
|
|
|
// Event specific data
|
|
JSONObject eventDict = new JSONObject();
|
|
eventDict["category"] = CategorySessionEnd;
|
|
eventDict.Add("length", new JSONNumber(sessionLength));
|
|
|
|
// Add custom dimensions
|
|
AddDimensionsToEvent(eventDict);
|
|
|
|
// Add to store
|
|
AddEventToStore(eventDict);
|
|
|
|
// Log
|
|
GALogger.I("Add SESSION END event.");
|
|
|
|
// Send all event right away
|
|
ProcessEvents("", false);
|
|
}
|
|
|
|
public static void AddBusinessEvent(
|
|
string currency,
|
|
int amount,
|
|
string itemType,
|
|
string itemId,
|
|
string cartType,
|
|
IDictionary<string, object> fields
|
|
)
|
|
{
|
|
if(!GAState.IsEventSubmissionEnabled)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Validate event params
|
|
if (!GAValidator.ValidateBusinessEvent(currency, amount, cartType, itemType, itemId))
|
|
{
|
|
//GAHTTPApi.Instance.SendSdkErrorEvent(EGASdkErrorType.Rejected);
|
|
return;
|
|
}
|
|
|
|
// Create empty eventData
|
|
JSONObject eventDict = new JSONObject();
|
|
|
|
// Increment transaction number and persist
|
|
GAState.IncrementTransactionNum();
|
|
GAStore.SetState(GAState.TransactionNumKey, GAState.TransactionNum.ToString(CultureInfo.InvariantCulture));
|
|
|
|
// Required
|
|
eventDict["event_id"] = itemType + ":" + itemId;
|
|
eventDict["category"] = CategoryBusiness;
|
|
eventDict["currency"] = currency;
|
|
eventDict.Add("amount", new JSONNumber(amount));
|
|
eventDict.Add(GAState.TransactionNumKey, new JSONNumber(GAState.TransactionNum));
|
|
|
|
// Optional
|
|
if (!string.IsNullOrEmpty(cartType))
|
|
{
|
|
eventDict.Add("cart_type", cartType);
|
|
}
|
|
|
|
// Add custom dimensions
|
|
AddDimensionsToEvent(eventDict);
|
|
|
|
// Add custom fields
|
|
AddFieldsToEvent(eventDict, GAState.ValidateAndCleanCustomFields(fields));
|
|
|
|
// Log
|
|
GALogger.I("Add BUSINESS event: {currency:" + currency + ", amount:" + amount + ", itemType:" + itemType + ", itemId:" + itemId + ", cartType:" + cartType + "}");
|
|
|
|
// Send to store
|
|
AddEventToStore(eventDict);
|
|
}
|
|
|
|
public static void AddResourceEvent(EGAResourceFlowType flowType, string currency, double amount, string itemType, string itemId, IDictionary<string, object> fields)
|
|
{
|
|
if(!GAState.IsEventSubmissionEnabled)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Validate event params
|
|
if (!GAValidator.ValidateResourceEvent(flowType, currency, (long)amount, itemType, itemId))
|
|
{
|
|
//GAHTTPApi.Instance.SendSdkErrorEvent(EGASdkErrorType.Rejected);
|
|
return;
|
|
}
|
|
|
|
// If flow type is sink reverse amount
|
|
if (flowType == EGAResourceFlowType.Sink)
|
|
{
|
|
amount *= -1;
|
|
}
|
|
|
|
// Create empty eventData
|
|
JSONObject eventDict = new JSONObject();
|
|
|
|
// insert event specific values
|
|
string flowTypeString = ResourceFlowTypeToString(flowType);
|
|
eventDict["event_id"] = flowTypeString + ":" + currency + ":" + itemType + ":" + itemId;
|
|
eventDict["category"] = CategoryResource;
|
|
eventDict.Add("amount", new JSONNumber(amount));
|
|
|
|
// Add custom dimensions
|
|
AddDimensionsToEvent(eventDict);
|
|
|
|
// Add custom fields
|
|
AddFieldsToEvent(eventDict, GAState.ValidateAndCleanCustomFields(fields));
|
|
|
|
// Log
|
|
GALogger.I("Add RESOURCE event: {currency:" + currency + ", amount:" + amount + ", itemType:" + itemType + ", itemId:" + itemId + "}");
|
|
|
|
// Send to store
|
|
AddEventToStore(eventDict);
|
|
}
|
|
|
|
public static void AddProgressionEvent(EGAProgressionStatus progressionStatus, string progression01, string progression02, string progression03, double score, bool sendScore, IDictionary<string, object> fields)
|
|
{
|
|
if(!GAState.IsEventSubmissionEnabled)
|
|
{
|
|
return;
|
|
}
|
|
|
|
string progressionStatusString = ProgressionStatusToString(progressionStatus);
|
|
|
|
// Validate event params
|
|
if (!GAValidator.ValidateProgressionEvent(progressionStatus, progression01, progression02, progression03))
|
|
{
|
|
//GAHTTPApi.Instance.SendSdkErrorEvent(EGASdkErrorType.Rejected);
|
|
return;
|
|
}
|
|
|
|
// Create empty eventData
|
|
JSONObject eventDict = new JSONObject();
|
|
|
|
// Progression identifier
|
|
string progressionIdentifier;
|
|
|
|
if (string.IsNullOrEmpty(progression02))
|
|
{
|
|
progressionIdentifier = progression01;
|
|
}
|
|
else if (string.IsNullOrEmpty(progression03))
|
|
{
|
|
progressionIdentifier = progression01 + ":" + progression02;
|
|
}
|
|
else
|
|
{
|
|
progressionIdentifier = progression01 + ":" + progression02 + ":" + progression03;
|
|
}
|
|
|
|
// Append event specifics
|
|
eventDict["category"] = CategoryProgression;
|
|
eventDict["event_id"] = progressionStatusString + ":" + progressionIdentifier;
|
|
|
|
// Attempt
|
|
double attempt_num = 0;
|
|
|
|
// Add score if specified and status is not start
|
|
if (sendScore && progressionStatus != EGAProgressionStatus.Start)
|
|
{
|
|
eventDict.Add("score", new JSONNumber(score));
|
|
}
|
|
|
|
// Count attempts on each progression fail and persist
|
|
if (progressionStatus == EGAProgressionStatus.Fail)
|
|
{
|
|
// Increment attempt number
|
|
GAState.IncrementProgressionTries(progressionIdentifier);
|
|
}
|
|
|
|
// increment and add attempt_num on complete and delete persisted
|
|
if (progressionStatus == EGAProgressionStatus.Complete)
|
|
{
|
|
// Increment attempt number
|
|
GAState.IncrementProgressionTries(progressionIdentifier);
|
|
|
|
// Add to event
|
|
attempt_num = GAState.GetProgressionTries(progressionIdentifier);
|
|
eventDict.Add("attempt_num", new JSONNumber(attempt_num));
|
|
|
|
// Clear
|
|
GAState.ClearProgressionTries(progressionIdentifier);
|
|
}
|
|
|
|
// Add custom dimensions
|
|
AddDimensionsToEvent(eventDict);
|
|
|
|
// Add custom fields
|
|
AddFieldsToEvent(eventDict, GAState.ValidateAndCleanCustomFields(fields));
|
|
|
|
// Log
|
|
GALogger.I("Add PROGRESSION event: {status:" + progressionStatusString + ", progression01:" + progression01 + ", progression02:" + progression02 + ", progression03:" + progression03 + ", score:" + score + ", attempt:" + attempt_num + "}");
|
|
|
|
// Send to store
|
|
AddEventToStore(eventDict);
|
|
}
|
|
|
|
public static void AddDesignEvent(string eventId, double value, bool sendValue, IDictionary<string, object> fields)
|
|
{
|
|
if(!GAState.IsEventSubmissionEnabled)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Validate
|
|
if (!GAValidator.ValidateDesignEvent(eventId, value))
|
|
{
|
|
//GAHTTPApi.Instance.SendSdkErrorEvent(EGASdkErrorType.Rejected);
|
|
return;
|
|
}
|
|
|
|
// Create empty eventData
|
|
JSONObject eventData = new JSONObject();
|
|
|
|
// Append event specifics
|
|
eventData["category"] = CategoryDesign;
|
|
eventData["event_id"] = eventId;
|
|
|
|
if(sendValue)
|
|
{
|
|
eventData.Add("value", new JSONNumber(value));
|
|
}
|
|
|
|
// Add custom dimensions
|
|
AddDimensionsToEvent(eventData);
|
|
|
|
// Add custom fields
|
|
AddFieldsToEvent(eventData, GAState.ValidateAndCleanCustomFields(fields));
|
|
|
|
// Log
|
|
GALogger.I("Add DESIGN event: {eventId:" + eventId + ", value:" + value + "}");
|
|
|
|
// Send to store
|
|
AddEventToStore(eventData);
|
|
}
|
|
|
|
public static void AddErrorEvent(EGAErrorSeverity severity, string message, IDictionary<string, object> fields)
|
|
{
|
|
if(!GAState.IsEventSubmissionEnabled)
|
|
{
|
|
return;
|
|
}
|
|
|
|
string severityString = ErrorSeverityToString(severity);
|
|
|
|
// Validate
|
|
if (!GAValidator.ValidateErrorEvent(severity, message))
|
|
{
|
|
//GAHTTPApi.Instance.SendSdkErrorEvent(EGASdkErrorType.Rejected);
|
|
return;
|
|
}
|
|
|
|
// Create empty eventData
|
|
JSONObject eventData = new JSONObject();
|
|
|
|
// Append event specifics
|
|
eventData["category"] = CategoryError;
|
|
eventData["severity"] = severityString;
|
|
eventData["message"] = message;
|
|
|
|
// Add custom dimensions
|
|
AddDimensionsToEvent(eventData);
|
|
|
|
// Add custom fields
|
|
AddFieldsToEvent(eventData, GAState.ValidateAndCleanCustomFields(fields));
|
|
|
|
// Log
|
|
GALogger.I("Add ERROR event: {severity:" + severityString + ", message:" + message + "}");
|
|
|
|
// Send to store
|
|
AddEventToStore(eventData);
|
|
}
|
|
|
|
#endregion // Public methods
|
|
|
|
#region Private methods
|
|
|
|
private static void ProcessEventQueue()
|
|
{
|
|
ProcessEvents("", true);
|
|
if(Instance.keepRunning)
|
|
{
|
|
GAThreading.ScheduleTimer(ProcessEventsIntervalInSeconds, "processEventQueue", ProcessEventQueue);
|
|
}
|
|
else
|
|
{
|
|
Instance.isRunning = false;
|
|
}
|
|
}
|
|
|
|
#if WINDOWS_UWP || WINDOWS_WSA
|
|
private async static void ProcessEvents(string category, bool performCleanUp)
|
|
#else
|
|
private static void ProcessEvents(string category, bool performCleanUp)
|
|
#endif
|
|
{
|
|
if(!GAState.IsEventSubmissionEnabled)
|
|
{
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
string requestIdentifier = Guid.NewGuid().ToString();
|
|
|
|
string selectSql;
|
|
string updateSql;
|
|
string deleteSql = "DELETE FROM ga_events WHERE status = '" + requestIdentifier + "'";
|
|
string putbackSql = "UPDATE ga_events SET status = 'new' WHERE status = '" + requestIdentifier + "';";
|
|
|
|
// Cleanup
|
|
if(performCleanUp)
|
|
{
|
|
CleanupEvents();
|
|
FixMissingSessionEndEvents();
|
|
}
|
|
|
|
// Prepare SQL
|
|
string andCategory = "";
|
|
if(!string.IsNullOrEmpty(category))
|
|
{
|
|
andCategory = " AND category='" + category + "' ";
|
|
}
|
|
selectSql = "SELECT event FROM ga_events WHERE status = 'new' " + andCategory + ";";
|
|
updateSql = "UPDATE ga_events SET status = '" + requestIdentifier + "' WHERE status = 'new' " + andCategory + ";";
|
|
|
|
// Get events to process
|
|
JSONArray events = GAStore.ExecuteQuerySync(selectSql);
|
|
|
|
// Check for errors or empty
|
|
if(events == null || events.Count == 0)
|
|
{
|
|
GALogger.I("Event queue: No events to send");
|
|
UpdateSessionTime();
|
|
return;
|
|
}
|
|
|
|
// Check number of events and take some action if there are too many?
|
|
if(events.Count > MaxEventCount)
|
|
{
|
|
// Make a limit request
|
|
selectSql = "SELECT client_ts FROM ga_events WHERE status = 'new' " + andCategory + " ORDER BY client_ts ASC LIMIT 0," + MaxEventCount + ";";
|
|
events = GAStore.ExecuteQuerySync(selectSql);
|
|
if(events == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Get last timestamp
|
|
JSONNode lastItem = events[events.Count - 1];
|
|
string lastTimestamp = lastItem["client_ts"].Value;
|
|
|
|
// Select again
|
|
selectSql = "SELECT event FROM ga_events WHERE status = 'new' " + andCategory + " AND client_ts<='" + lastTimestamp + "';";
|
|
events = GAStore.ExecuteQuerySync(selectSql);
|
|
if (events == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Update sql
|
|
updateSql = "UPDATE ga_events SET status='" + requestIdentifier + "' WHERE status='new' " + andCategory + " AND client_ts<='" + lastTimestamp + "';";
|
|
}
|
|
|
|
// Log
|
|
GALogger.I("Event queue: Sending " + events.Count + " events.");
|
|
|
|
// Set status of events to 'sending' (also check for error)
|
|
if (GAStore.ExecuteQuerySync(updateSql) == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Create payload data from events
|
|
List<JSONNode> payloadArray = new List<JSONNode>();
|
|
|
|
for(int i = 0; i < events.Count; ++i)
|
|
{
|
|
JSONNode ev = events[i];
|
|
JSONNode eventDict = null;
|
|
|
|
try
|
|
{
|
|
eventDict = JSONNode.LoadFromBinaryBase64(ev["event"].Value);
|
|
}
|
|
catch(Exception)
|
|
{
|
|
//GALogger.E("ProcessEvents: Error decoding json, " + e);
|
|
}
|
|
|
|
if (eventDict != null && eventDict.Count != 0)
|
|
{
|
|
payloadArray.Add(eventDict);
|
|
}
|
|
}
|
|
|
|
// send events
|
|
#if WINDOWS_UWP || WINDOWS_WSA
|
|
KeyValuePair<EGAHTTPApiResponse, JSONNode> result = await GAHTTPApi.Instance.SendEventsInArray(payloadArray);
|
|
#else
|
|
KeyValuePair<EGAHTTPApiResponse, JSONNode> result = GAHTTPApi.Instance.SendEventsInArray(payloadArray);
|
|
#endif
|
|
|
|
ProcessEvents(result.Key, result.Value, putbackSql, deleteSql, payloadArray.Count);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
GALogger.E("Error during ProcessEvents(): " + e);
|
|
}
|
|
}
|
|
|
|
public static void ProcessEvents(EGAHTTPApiResponse responseEnum, JSONNode dataDict, string putbackSql, string deleteSql, int eventCount)
|
|
{
|
|
if(responseEnum == EGAHTTPApiResponse.Ok)
|
|
{
|
|
// Delete events
|
|
GAStore.ExecuteQuerySync(deleteSql);
|
|
GALogger.I("Event queue: " + eventCount + " events sent.");
|
|
}
|
|
else
|
|
{
|
|
// Put events back (Only in case of no response)
|
|
if(responseEnum == EGAHTTPApiResponse.NoResponse)
|
|
{
|
|
GALogger.W("Event queue: Failed to send events to collector - Retrying next time");
|
|
GAStore.ExecuteQuerySync(putbackSql);
|
|
// Delete events (When getting some anwser back always assume events are processed)
|
|
}
|
|
else
|
|
{
|
|
if(dataDict != null)
|
|
{
|
|
JSONNode json = null;
|
|
IEnumerator<JSONNode> enumerator = dataDict.Children.GetEnumerator();
|
|
if(enumerator.MoveNext())
|
|
{
|
|
json = enumerator.Current;
|
|
}
|
|
|
|
if(responseEnum == EGAHTTPApiResponse.BadRequest && json is JSONArray)
|
|
{
|
|
GALogger.W("Event queue: " + eventCount + " events sent. " + dataDict.Count + " events failed GA server validation.");
|
|
}
|
|
else
|
|
{
|
|
GALogger.W("Event queue: Failed to send events.");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GALogger.W("Event queue: Failed to send events.");
|
|
}
|
|
|
|
GAStore.ExecuteQuerySync(deleteSql);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void CleanupEvents()
|
|
{
|
|
GAStore.ExecuteQuerySync("UPDATE ga_events SET status = 'new';");
|
|
}
|
|
|
|
private static void FixMissingSessionEndEvents()
|
|
{
|
|
if(!GAState.IsEventSubmissionEnabled)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Get all sessions that are not current
|
|
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
|
parameters.Add("$session_id", GAState.SessionId);
|
|
|
|
|
|
string sql = "SELECT timestamp, event FROM ga_session WHERE session_id != $session_id;";
|
|
JSONArray sessions = GAStore.ExecuteQuerySync(sql, parameters);
|
|
|
|
if (sessions == null || sessions.Count == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
GALogger.I(sessions.Count + " session(s) located with missing session_end event.");
|
|
|
|
// Add missing session_end events
|
|
for (int i = 0; i < sessions.Count; ++i)
|
|
{
|
|
JSONNode session = sessions[i];
|
|
JSONNode sessionEndEvent = null;
|
|
|
|
try
|
|
{
|
|
sessionEndEvent = JSONNode.LoadFromBinaryBase64(session["event"].Value);
|
|
}
|
|
catch(Exception)
|
|
{
|
|
//GALogger.E("FixMissingSessionEndEvents: Error decoding json, " + e);
|
|
}
|
|
|
|
if(sessionEndEvent != null)
|
|
{
|
|
long event_ts = sessionEndEvent["client_ts"].AsLong;
|
|
long start_ts = session["timestamp"].AsLong;
|
|
|
|
long length = event_ts - start_ts;
|
|
length = Math.Max(0, length);
|
|
|
|
GALogger.D("fixMissingSessionEndEvents length calculated: " + length);
|
|
|
|
sessionEndEvent["category"] = CategorySessionEnd;
|
|
sessionEndEvent.Add("length", new JSONNumber(length));
|
|
|
|
// Add to store
|
|
AddEventToStore(sessionEndEvent.AsObject);
|
|
}
|
|
else
|
|
{
|
|
GALogger.I("Problem decoding session_end event. Skipping this session_end event.");
|
|
}
|
|
}
|
|
}
|
|
|
|
#if WINDOWS_WSA
|
|
private async static void AddEventToStore(JSONObject eventData)
|
|
#else
|
|
private static void AddEventToStore(JSONObject eventData)
|
|
#endif
|
|
{
|
|
// Check if datastore is available
|
|
if (!GAStore.IsTableReady)
|
|
{
|
|
GALogger.W("Could not add event: SDK datastore error");
|
|
return;
|
|
}
|
|
|
|
// Check if we are initialized
|
|
if (!GAState.Initialized)
|
|
{
|
|
GALogger.W("Could not add event: SDK is not initialized");
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
// Check db size limits (10mb)
|
|
// If database is too large block all except user, session and business
|
|
if (GAStore.IsDbTooLargeForEvents && !GAUtilities.StringMatch(eventData["category"].Value, "^(user|session_end|business)$"))
|
|
{
|
|
GALogger.W("Database too large. Event has been blocked.");
|
|
return;
|
|
}
|
|
|
|
// Get default annotations
|
|
JSONObject ev = GAState.GetEventAnnotations();
|
|
|
|
// Create json with only default annotations
|
|
string jsonDefaults = ev.SaveToBinaryBase64();
|
|
|
|
// Merge with eventData
|
|
foreach(KeyValuePair<string,JSONNode> pair in eventData)
|
|
{
|
|
ev.Add(pair.Key, pair.Value);
|
|
}
|
|
|
|
// Create json string representation
|
|
string json = ev.ToString();
|
|
|
|
// output if VERBOSE LOG enabled
|
|
|
|
GALogger.II("Event added to queue: " + json);
|
|
|
|
// Add to store
|
|
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
|
parameters.Add("$status", "new");
|
|
parameters.Add("$category", ev["category"].Value);
|
|
parameters.Add("$session_id", ev["session_id"].Value);
|
|
parameters.Add("$client_ts", ev["client_ts"].Value);
|
|
parameters.Add("$event", ev.SaveToBinaryBase64());
|
|
string sql = "INSERT INTO ga_events (status, category, session_id, client_ts, event) VALUES($status, $category, $session_id, $client_ts, $event);";
|
|
|
|
GAStore.ExecuteQuerySync(sql, parameters);
|
|
|
|
// Add to session store if not last
|
|
if (eventData["category"].Value.Equals(CategorySessionEnd))
|
|
{
|
|
parameters.Clear();
|
|
parameters.Add("$session_id", ev["session_id"].Value);
|
|
sql = "DELETE FROM ga_session WHERE session_id = $session_id;";
|
|
GAStore.ExecuteQuerySync(sql, parameters);
|
|
}
|
|
else
|
|
{
|
|
sql = "INSERT OR REPLACE INTO ga_session(session_id, timestamp, event) VALUES($session_id, $timestamp, $event);";
|
|
parameters.Clear();
|
|
parameters.Add("$session_id", ev["session_id"].Value);
|
|
parameters.Add("$timestamp", GAState.SessionStart);
|
|
parameters.Add("$event", jsonDefaults);
|
|
GAStore.ExecuteQuerySync(sql, parameters);
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
GALogger.E("addEventToStoreWithEventData: error using json");
|
|
GALogger.E(e.ToString());
|
|
}
|
|
}
|
|
|
|
private static void AddDimensionsToEvent(JSONObject eventData)
|
|
{
|
|
if (eventData == null)
|
|
{
|
|
return;
|
|
}
|
|
// add to dict (if not nil)
|
|
if (!string.IsNullOrEmpty(GAState.CurrentCustomDimension01))
|
|
{
|
|
eventData["custom_01"] = GAState.CurrentCustomDimension01;
|
|
}
|
|
if (!string.IsNullOrEmpty(GAState.CurrentCustomDimension02))
|
|
{
|
|
eventData["custom_02"] = GAState.CurrentCustomDimension02;
|
|
}
|
|
if (!string.IsNullOrEmpty(GAState.CurrentCustomDimension03))
|
|
{
|
|
eventData["custom_03"] = GAState.CurrentCustomDimension03;
|
|
}
|
|
}
|
|
|
|
private static void AddFieldsToEvent(JSONObject eventData, JSONObject fields)
|
|
{
|
|
if (eventData == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(fields != null && fields.Count > 0)
|
|
{
|
|
eventData["custom_fields"] = fields;
|
|
}
|
|
}
|
|
|
|
private static string ResourceFlowTypeToString(EGAResourceFlowType value)
|
|
{
|
|
switch(value)
|
|
{
|
|
case EGAResourceFlowType.Source:
|
|
{
|
|
return "Source";
|
|
}
|
|
|
|
case EGAResourceFlowType.Sink:
|
|
{
|
|
return "Sink";
|
|
}
|
|
|
|
default:
|
|
{
|
|
return "";
|
|
}
|
|
}
|
|
}
|
|
|
|
private static string ProgressionStatusToString(EGAProgressionStatus value)
|
|
{
|
|
switch(value)
|
|
{
|
|
case EGAProgressionStatus.Start:
|
|
{
|
|
return "Start";
|
|
}
|
|
|
|
case EGAProgressionStatus.Complete:
|
|
{
|
|
return "Complete";
|
|
}
|
|
|
|
case EGAProgressionStatus.Fail:
|
|
{
|
|
return "Fail";
|
|
}
|
|
|
|
default:
|
|
{
|
|
return "";
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void UpdateSessionTime()
|
|
{
|
|
if(GAState.SessionIsStarted())
|
|
{
|
|
JSONObject ev = GAState.GetEventAnnotations();
|
|
string jsonDefaults = ev.SaveToBinaryBase64();
|
|
string sql = "INSERT OR REPLACE INTO ga_session(session_id, timestamp, event) VALUES($session_id, $timestamp, $event);";
|
|
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
|
parameters.Add("$session_id", ev["session_id"].Value);
|
|
parameters.Add("$timestamp", GAState.SessionStart);
|
|
parameters.Add("$event", jsonDefaults);
|
|
GAStore.ExecuteQuerySync(sql, parameters);
|
|
}
|
|
}
|
|
|
|
private static string ErrorSeverityToString(EGAErrorSeverity value)
|
|
{
|
|
switch(value)
|
|
{
|
|
case EGAErrorSeverity.Debug:
|
|
{
|
|
return "debug";
|
|
}
|
|
|
|
case EGAErrorSeverity.Info:
|
|
{
|
|
return "info";
|
|
}
|
|
|
|
case EGAErrorSeverity.Warning:
|
|
{
|
|
return "warning";
|
|
}
|
|
|
|
case EGAErrorSeverity.Error:
|
|
{
|
|
return "error";
|
|
}
|
|
|
|
case EGAErrorSeverity.Critical:
|
|
{
|
|
return "critical";
|
|
}
|
|
|
|
default:
|
|
{
|
|
return "";
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion // Private methods
|
|
}
|
|
}
|