(61d00a474) v0.9.7.1
This commit is contained in:
@@ -0,0 +1,853 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user