#pragma warning disable 0162 public static void SetState(string key, string value) { if (value == null) { if (InMemory) { #if UNITY if (UnityEngine.PlayerPrefs.HasKey(State.GAState.InMemoryPrefix + key)) { UnityEngine.PlayerPrefs.DeleteKey(State.GAState.InMemoryPrefix + key); } #else GALogger.W("SetState: No implementation yet for InMemory=true"); #endif } else { Dictionary <string, object> parameterArray = new Dictionary <string, object>(); parameterArray.Add("$key", key); ExecuteQuerySync("DELETE FROM ga_state WHERE key = $key;", parameterArray); } } else { if (InMemory) { #if UNITY UnityEngine.PlayerPrefs.SetString(State.GAState.InMemoryPrefix + key, value); #else GALogger.W("SetState: No implementation yet for InMemory=true"); #endif } else { Dictionary <string, object> parameterArray = new Dictionary <string, object>(); parameterArray.Add("$key", key); parameterArray.Add("$value", value); ExecuteQuerySync("INSERT OR REPLACE INTO ga_state (key, value) VALUES($key, $value);", parameterArray, true); } } }
private EGAHTTPApiResponse ProcessRequestResponse(HttpStatusCode responseCode, string responseMessage, string body, string requestId) { // if no result - often no connection if (string.IsNullOrEmpty(body)) { GALogger.D(requestId + " request. failed. Might be no connection. Description: " + responseMessage + ", Status code: " + responseCode); return(EGAHTTPApiResponse.NoResponse); } // ok if (responseCode == HttpStatusCode.OK) { return(EGAHTTPApiResponse.Ok); } // ok if (responseCode == HttpStatusCode.Created) { return(EGAHTTPApiResponse.Created); } // 401 can return 0 status if (responseCode == (HttpStatusCode)0 || responseCode == HttpStatusCode.Unauthorized) { GALogger.D(requestId + " request. 401 - Unauthorized."); return(EGAHTTPApiResponse.Unauthorized); } if (responseCode == HttpStatusCode.BadRequest) { GALogger.D(requestId + " request. 400 - Bad Request."); return(EGAHTTPApiResponse.BadRequest); } if (responseCode == HttpStatusCode.InternalServerError) { GALogger.D(requestId + " request. 500 - Internal Server Error."); return(EGAHTTPApiResponse.InternalServerError); } return(EGAHTTPApiResponse.UnknownResponseCode); }
public void SendSdkErrorEvent(EGASdkErrorType type) { string gameKey = GAState.GameKey; string secretKey = GAState.GameSecret; // Validate if (!GAValidator.ValidateSdkErrorEvent(gameKey, secretKey, type)) { return; } // Generate URL string url = baseUrl + "/" + gameKey + "/" + eventsUrlPath; GALogger.D("Sending 'events' URL: " + url); string payloadJSONString = ""; JSONClass json = GAState.GetSdkErrorEventAnnotations(); string typeString = SdkErrorTypeToString(type); json.Add("type", typeString); List <JSONNode> eventArray = new List <JSONNode>(); eventArray.Add(json); payloadJSONString = GAUtilities.ArrayOfObjectsToJsonString(eventArray); if (string.IsNullOrEmpty(payloadJSONString)) { GALogger.W("sendSdkErrorEvent: JSON encoding failed."); return; } GALogger.D("sendSdkErrorEvent json: " + payloadJSONString); byte[] payloadData = Encoding.UTF8.GetBytes(payloadJSONString); SdkErrorTask sdkErrorTask = new SdkErrorTask(type, payloadData, secretKey); sdkErrorTask.Execute(url); }
public static void ConfigureGameEngineVersion(string gameEngineVersion) { if (_endThread) { return; } GAThreading.PerformTaskOnGAThread("configureGameEngineVersion", () => { if (IsSdkReady(true, false)) { return; } if (!GAValidator.ValidateEngineVersion(gameEngineVersion)) { GALogger.I("Validation fail - configure sdk version: Sdk version not supported. String: " + gameEngineVersion); return; } GADevice.GameEngineVersion = gameEngineVersion; }); }
private static void ValidateAndFixCurrentDimensions() { // validate that there are no current dimension01 not in list if (!GAValidator.ValidateDimension01(CurrentCustomDimension01)) { GALogger.D("Invalid dimension01 found in variable. Setting to nil. Invalid dimension: " + CurrentCustomDimension01); SetCustomDimension01(""); } // validate that there are no current dimension02 not in list if (!GAValidator.ValidateDimension02(CurrentCustomDimension02)) { GALogger.D("Invalid dimension02 found in variable. Setting to nil. Invalid dimension: " + CurrentCustomDimension02); SetCustomDimension02(""); } // validate that there are no current dimension03 not in list if (!GAValidator.ValidateDimension03(CurrentCustomDimension03)) { GALogger.D("Invalid dimension03 found in variable. Setting to nil. Invalid dimension: " + CurrentCustomDimension03); SetCustomDimension03(""); } }
public static void SetEnabledEventSubmission(bool flag) { if (_endThread) { return; } GAThreading.PerformTaskOnGAThread("setEnabledEventSubmission", () => { if (flag) { GAState.SetEnabledEventSubmission(flag); GALogger.I("Event submission enabled"); } else { GALogger.I("Event submission disabled"); GAState.SetEnabledEventSubmission(flag); } }); }
#pragma warning disable 0162 public static void ClearProgressionTries(string progression) { Dictionary <string, int> progressionTries = Instance.progressionTries; if (progressionTries.ContainsKey(progression)) { progressionTries.Remove(progression); } if (GAStore.InMemory) { GALogger.D("Trying to ClearProgressionTries with InMemory=true - cannot. Skipping."); } else { // Delete Dictionary <string, object> parms = new Dictionary <string, object>(); parms.Add("$progression", progression); GAStore.ExecuteQuerySync("DELETE FROM ga_progression WHERE progression = $progression;", parms); } }
public static void SetEnabledVerboseLog(bool flag) { if (_endThread) { return; } GAThreading.PerformTaskOnGAThread("setEnabledVerboseLog", () => { if (flag) { GALogger.VerboseLog = flag; GALogger.I("Verbose logging enabled"); } else { GALogger.I("Verbose logging disabled"); GALogger.VerboseLog = flag; } }); }
public static void ConfigureBuild(string build) { if (_endThread) { return; } GAThreading.PerformTaskOnGAThread("configureBuild", () => { if (IsSdkReady(true, false)) { GALogger.W("Build version must be set before SDK is initialized."); return; } if (!GAValidator.ValidateBuild(build)) { GALogger.I("Validation fail - configure build: Cannot be null, empty or above 32 length. String: " + build); return; } GAState.Build = build; }); }
public static JSONClass ValidateAndCleanInitRequestResponse(JSONNode initResponse) { // make sure we have a valid dict if (initResponse == null) { GALogger.W("validateInitRequestResponse failed - no response dictionary."); return(null); } JSONClass validatedDict = new JSONClass(); // validate enabled field try { validatedDict.Add("enabled", new JSONData(initResponse.HasKey("enabled") ? initResponse["enabled"].AsBool : true)); } catch (Exception) { GALogger.W("validateInitRequestResponse failed - invalid type in 'enabled' field."); return(null); } // validate server_ts try { long serverTsNumber = initResponse.HasKey("server_ts") ? initResponse["server_ts"].AsLong : -1; if (serverTsNumber > 0) { validatedDict.Add("server_ts", new JSONData(serverTsNumber)); } } catch (Exception e) { GALogger.W("validateInitRequestResponse failed - invalid type in 'server_ts' field. type=" + initResponse["server_ts"].GetType() + ", value=" + initResponse["server_ts"] + ", " + e); return(null); } return(validatedDict); }
private static void FixMissingSessionEndEvents() { // 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) { 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 = JSONNode.LoadFromBase64(session["event"].AsString); 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 JSONData(length)); // Add to store AddEventToStore(sessionEndEvent.AsObject); } }
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 ConfigureUserId(string uId) { if (_endThread) { return; } GAThreading.PerformTaskOnGAThread("configureUserId", () => { if (IsSdkReady(true, false)) { GALogger.W("A custom user id must be set before SDK is initialized."); return; } if (!GAValidator.ValidateUserId(uId)) { GALogger.I("Validation fail - configure user_id: Cannot be null, empty or above 64 length. Will use default user_id method. Used string: " + uId); return; } GAState.UserId = uId; }); }
private static void CacheIdentifier() { if (!string.IsNullOrEmpty(GAState.UserId)) { GAState.Identifier = GAState.UserId; } #if WINDOWS_UWP else if (!string.IsNullOrEmpty(GADevice.AdvertisingId)) { GAState.Identifier = GADevice.AdvertisingId; } else if (!string.IsNullOrEmpty(GADevice.DeviceId)) { GAState.Identifier = GADevice.DeviceId; } #endif else if (!string.IsNullOrEmpty(Instance.DefaultUserId)) { GAState.Identifier = Instance.DefaultUserId; } GALogger.D("identifier, {clean:" + GAState.Identifier + "}"); }
private static string GetOSVersionString() { string osVersion = SystemInfo.operatingSystem; GALogger.D("GetOSVersionString: " + osVersion); // Capture and process OS version information // For Windows Match regexResult = Regex.Match(osVersion, @"Windows.*?\((\d{0,5}\.\d{0,5}\.(\d{0,5}))\)"); if (regexResult.Success) { string versionNumberString = regexResult.Groups[1].Value; string buildNumberString = regexResult.Groups[2].Value; // Fix a bug in older versions of Unity where Windows 10 isn't recognised properly int buildNumber = 0; Int32.TryParse(buildNumberString, out buildNumber); if (buildNumber > 10000) { versionNumberString = "10.0." + buildNumberString; } return("windows " + versionNumberString); } // For OS X regexResult = Regex.Match(osVersion, @"Mac OS X (\d{0,5}\.\d{0,5}\.\d{0,5})"); if (regexResult.Success) { return("mac_osx " + regexResult.Captures[0].Value.Replace("Mac OS X ", "")); } regexResult = Regex.Match(osVersion, @"Mac OS X (\d{0,5}_\d{0,5}_\d{0,5})"); if (regexResult.Success) { return("mac_osx " + regexResult.Captures[0].Value.Replace("Mac OS X ", "").Replace("_", ".")); } // Not supporting other OS yet. The default version string won't be accepted by GameAnalytics return(UnityRuntimePlatformToString(Application.platform) + " 0.0.0"); }
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 AddResourceEvent(EGAResourceFlowType flowType, string currency, double amount, string itemType, string itemId, IDictionary <string, object> fields) { // 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 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); }
public static void Initialize(string gameKey, string gameSecret) { if (_endThread) { return; } #if WINDOWS_UWP || WINDOWS_WSA CoreApplication.Suspending += OnSuspending; CoreApplication.Resuming += OnResuming; #endif GADevice.UpdateConnectionType(); GAThreading.PerformTaskOnGAThread("initialize", () => { if (IsSdkReady(true, false)) { GALogger.W("SDK already initialized. Can only be called once."); return; } if (!GAValidator.ValidateKeys(gameKey, gameSecret)) { GALogger.W("SDK failed initialize. Game key or secret key is invalid. Can only contain characters A-z 0-9, gameKey is 32 length, gameSecret is 40 length. Failed keys - gameKey: " + gameKey + ", secretKey: " + gameSecret); return; } GAState.SetKeys(gameKey, gameSecret); if (!GAStore.EnsureDatabase(false, gameKey)) { GALogger.W("Could not ensure/validate local event database: " + GADevice.WritablePath); } GAState.InternalInitialize(); }); }
private static bool IsSdkReady(bool needsInitialized, bool warn, String message) { if (!string.IsNullOrEmpty(message)) { message = message + ": "; } // Make sure database is ready if (!GAStore.IsTableReady) { if (warn) { GALogger.W(message + "Datastore not initialized"); } return(false); } // Is SDK initialized if (needsInitialized && !GAState.Initialized) { if (warn) { GALogger.W(message + "SDK is not initialized"); } return(false); } // Is SDK enabled if (needsInitialized && !GAState.IsEnabled()) { if (warn) { GALogger.W(message + "SDK is disabled"); } return(false); } return(true); }
public KeyValuePair <EGAHTTPApiResponse, JSONClass> RequestInitReturningDict() #endif { JSONClass json; EGAHTTPApiResponse result = EGAHTTPApiResponse.NoResponse; string gameKey = GAState.GameKey; // Generate URL string url = baseUrl + "/" + gameKey + "/" + initializeUrlPath; GALogger.D("Sending 'init' URL: " + url); JSONClass initAnnotations = GAState.GetInitAnnotations(); // make JSON string from data string JSONstring = initAnnotations.ToString(); if (string.IsNullOrEmpty(JSONstring)) { result = EGAHTTPApiResponse.JsonEncodeFailed; json = null; return(new KeyValuePair <EGAHTTPApiResponse, JSONClass>(result, json)); } string body = ""; HttpStatusCode responseCode = (HttpStatusCode)0; string responseDescription = ""; string authorization = ""; try { byte[] payloadData = CreatePayloadData(JSONstring, useGzip); HttpWebRequest request = CreateRequest(url, payloadData, useGzip); authorization = request.Headers[HttpRequestHeader.Authorization]; #if WINDOWS_UWP || WINDOWS_WSA using (Stream dataStream = await request.GetRequestStreamAsync()) #else using (Stream dataStream = request.GetRequestStream()) #endif { dataStream.Write(payloadData, 0, payloadData.Length); } #if WINDOWS_UWP || WINDOWS_WSA using (HttpWebResponse response = await request.GetResponseAsync() as HttpWebResponse) #else using (HttpWebResponse response = request.GetResponse() as HttpWebResponse) #endif { using (Stream dataStream = response.GetResponseStream()) { using (StreamReader reader = new StreamReader(dataStream)) { string responseString = reader.ReadToEnd(); responseCode = response.StatusCode; responseDescription = response.StatusDescription; // print result body = responseString; } } } } catch (WebException e) { if (e.Response != null) { using (HttpWebResponse response = (HttpWebResponse)e.Response) { using (Stream streamResponse = response.GetResponseStream()) { using (StreamReader streamRead = new StreamReader(streamResponse)) { string responseString = streamRead.ReadToEnd(); responseCode = response.StatusCode; responseDescription = response.StatusDescription; body = responseString; } } } } } catch (Exception e) { GALogger.E(e.ToString()); } // process the response GALogger.D("init request content : " + body); JSONNode requestJsonDict = JSON.Parse(body); EGAHTTPApiResponse requestResponseEnum = ProcessRequestResponse(responseCode, responseDescription, body, "Init"); // if not 200 result if (requestResponseEnum != EGAHTTPApiResponse.Ok && requestResponseEnum != EGAHTTPApiResponse.BadRequest) { GALogger.D("Failed Init Call. URL: " + url + ", Authorization: " + authorization + ", JSONString: " + JSONstring); result = requestResponseEnum; json = null; return(new KeyValuePair <EGAHTTPApiResponse, JSONClass>(result, json)); } if (requestJsonDict == null) { GALogger.D("Failed Init Call. Json decoding failed"); result = EGAHTTPApiResponse.JsonDecodeFailed; json = null; return(new KeyValuePair <EGAHTTPApiResponse, JSONClass>(result, json)); } // print reason if bad request if (requestResponseEnum == EGAHTTPApiResponse.BadRequest) { GALogger.D("Failed Init Call. Bad request. Response: " + requestJsonDict.AsObject.ToString()); // return bad request result result = requestResponseEnum; json = null; return(new KeyValuePair <EGAHTTPApiResponse, JSONClass>(result, json)); } // validate Init call values JSONClass validatedInitValues = GAValidator.ValidateAndCleanInitRequestResponse(requestJsonDict); if (validatedInitValues == null) { result = EGAHTTPApiResponse.BadResponse; json = null; return(new KeyValuePair <EGAHTTPApiResponse, JSONClass>(result, json)); } // all ok result = EGAHTTPApiResponse.Ok; json = validatedInitValues; return(new KeyValuePair <EGAHTTPApiResponse, JSONClass>(result, json)); }
private static void AddEventToStore(JSONClass 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"].AsString, "^(user|session_end|business)$")) { GALogger.W("Database too large. Event has been blocked."); return; } // Get default annotations JSONClass ev = GAState.GetEventAnnotations(); // Create json with only default annotations string jsonDefaults = ev.SaveToBase64(); // 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.SaveToBase64()); 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"].AsString.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 ProcessEvents(string category, bool performCleanUp) #endif { 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) { GALogger.I("Event queue: No events to send"); 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"].AsString; // 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 = JSONNode.LoadFromBase64(ev["event"].AsString); if (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 AddProgressionEvent(EGAProgressionStatus progressionStatus, string progression01, string progression02, string progression03, double score, bool sendScore) { string progressionStatusString = ProgressionStatusToString(progressionStatus); // Validate event params if (!GAValidator.ValidateProgressionEvent(progressionStatus, progression01, progression02, progression03)) { GAHTTPApi.Instance.SendSdkErrorEvent(EGASdkErrorType.Rejected); return; } // Create empty eventData JSONClass eventDict = new JSONClass(); // 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 JSONData(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 JSONData(attempt_num)); // Clear GAState.ClearProgressionTries(progressionIdentifier); } // Add custom dimensions AddDimensionsToEvent(eventDict); // 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 StartNewSession(EGAHTTPApiResponse initResponse, JSONObject initResponseDict) { // init is ok if (initResponse == EGAHTTPApiResponse.Ok && initResponseDict != null) { // set the time offset - how many seconds the local time is different from servertime long timeOffsetSeconds = 0; if (initResponseDict["server_ts"] != null) { long serverTs = initResponseDict["server_ts"].AsLong; timeOffsetSeconds = CalculateServerTimeOffset(serverTs); } initResponseDict.Add("time_offset", new JSONNumber(timeOffsetSeconds)); // insert new config in sql lite cross session storage GAStore.SetState(SdkConfigCachedKey, initResponseDict.SaveToBinaryBase64()); // set new config and cache in memory Instance.sdkConfigCached = initResponseDict; Instance.sdkConfig = initResponseDict; Instance.InitAuthorized = true; } else if (initResponse == EGAHTTPApiResponse.Unauthorized) { GALogger.W("Initialize SDK failed - Unauthorized"); Instance.InitAuthorized = false; } else { // log the status if no connection if (initResponse == EGAHTTPApiResponse.NoResponse || initResponse == EGAHTTPApiResponse.RequestTimeout) { GALogger.I("Init call (session start) failed - no response. Could be offline or timeout."); } else if (initResponse == EGAHTTPApiResponse.BadResponse || initResponse == EGAHTTPApiResponse.JsonEncodeFailed || initResponse == EGAHTTPApiResponse.JsonDecodeFailed) { GALogger.I("Init call (session start) failed - bad response. Could be bad response from proxy or GA servers."); } else if (initResponse == EGAHTTPApiResponse.BadRequest || initResponse == EGAHTTPApiResponse.UnknownResponseCode) { GALogger.I("Init call (session start) failed - bad request or unknown response."); } // init call failed (perhaps offline) if (Instance.sdkConfig == null) { if (Instance.sdkConfigCached != null) { GALogger.I("Init call (session start) failed - using cached init values."); // set last cross session stored config init values Instance.sdkConfig = Instance.sdkConfigCached; } else { GALogger.I("Init call (session start) failed - using default init values."); // set default init values Instance.sdkConfig = Instance.sdkConfigDefault; } } else { GALogger.I("Init call (session start) failed - using cached init values."); } Instance.InitAuthorized = true; } { JSONNode currentSdkConfig = SdkConfig; if (currentSdkConfig["enabled"].IsBoolean && !currentSdkConfig["enabled"].AsBool) { Instance.Enabled = false; } else if (!Instance.InitAuthorized) { Instance.Enabled = false; } else { Instance.Enabled = true; } } // set offset in state (memory) from current config (config could be from cache etc.) Instance.ClientServerTimeOffset = SdkConfig["time_offset"] != null ? SdkConfig["time_offset"].AsLong : 0; // populate configurations PopulateConfigurations(SdkConfig); // if SDK is disabled in config if (!IsEnabled()) { GALogger.W("Could not start session: SDK is disabled."); // stop event queue // + make sure it's able to restart if another session detects it's enabled again GAEvents.StopEventQueue(); return; } else { GAEvents.EnsureEventQueueIsRunning(); } // generate the new session string newSessionId = Guid.NewGuid().ToString(); string newSessionIdLowercase = newSessionId.ToLowerInvariant(); // Set session id SessionId = newSessionIdLowercase; // Set session start SessionStart = GetClientTsAdjusted(); // Add session start event GAEvents.AddSessionStartEvent(); }
#pragma warning disable 0162 private static void EnsurePersistedStates() { if (GAStore.InMemory) { #if UNITY GALogger.D("retrieving persisted states from local PlayerPrefs"); GAState instance = GAState.Instance; instance.DefaultUserId = UnityEngine.PlayerPrefs.GetString(InMemoryPrefix + SessionNumKey, Guid.NewGuid().ToString()); { int tmp; int.TryParse(UnityEngine.PlayerPrefs.GetString(InMemoryPrefix + SessionNumKey, "0"), out tmp); SessionNum = tmp; } { int tmp; int.TryParse(UnityEngine.PlayerPrefs.GetString(InMemoryPrefix + TransactionNumKey, "0"), out tmp); TransactionNum = tmp; } if (!string.IsNullOrEmpty(instance.FacebookId)) { UnityEngine.PlayerPrefs.SetString(InMemoryPrefix + FacebookIdKey, instance.FacebookId); } else { instance.FacebookId = UnityEngine.PlayerPrefs.GetString(InMemoryPrefix + FacebookIdKey, ""); } if (!string.IsNullOrEmpty(instance.Gender)) { UnityEngine.PlayerPrefs.SetString(InMemoryPrefix + GenderKey, instance.Gender); } else { instance.Gender = UnityEngine.PlayerPrefs.GetString(InMemoryPrefix + GenderKey, ""); } if (instance.BirthYear != 0) { UnityEngine.PlayerPrefs.SetString(InMemoryPrefix + BirthYearKey, instance.BirthYear.ToString()); } else { int tmp; int.TryParse(UnityEngine.PlayerPrefs.GetString(InMemoryPrefix + BirthYearKey, "0"), out tmp); instance.BirthYear = tmp; } if (!string.IsNullOrEmpty(CurrentCustomDimension01)) { UnityEngine.PlayerPrefs.SetString(InMemoryPrefix + Dimension01Key, CurrentCustomDimension01); } else { CurrentCustomDimension01 = UnityEngine.PlayerPrefs.GetString(InMemoryPrefix + Dimension01Key, ""); } if (!string.IsNullOrEmpty(CurrentCustomDimension02)) { UnityEngine.PlayerPrefs.SetString(InMemoryPrefix + Dimension02Key, CurrentCustomDimension02); } else { CurrentCustomDimension02 = UnityEngine.PlayerPrefs.GetString(InMemoryPrefix + Dimension02Key, ""); } if (!string.IsNullOrEmpty(CurrentCustomDimension03)) { UnityEngine.PlayerPrefs.SetString(InMemoryPrefix + Dimension03Key, CurrentCustomDimension03); } else { CurrentCustomDimension03 = UnityEngine.PlayerPrefs.GetString(InMemoryPrefix + Dimension03Key, ""); } string sdkConfigCachedString = UnityEngine.PlayerPrefs.GetString(InMemoryPrefix + SdkConfigCachedKey, ""); if (!string.IsNullOrEmpty(sdkConfigCachedString)) { // decode JSON JSONNode sdkConfigCached = null; try { sdkConfigCached = JSONNode.LoadFromBinaryBase64(sdkConfigCachedString); } catch (Exception) { //GALogger.E("EnsurePersistedStates: Error decoding json, " + e); } if (sdkConfigCached != null && sdkConfigCached.Count != 0) { instance.SdkConfigCached = sdkConfigCached; } } #else GALogger.W("EnsurePersistedStates: No implementation yet for InMemory=true"); #endif } else { // get and extract stored states JSONObject state_dict = new JSONObject(); JSONArray results_ga_state = GAStore.ExecuteQuerySync("SELECT * FROM ga_state;"); if (results_ga_state != null && results_ga_state.Count != 0) { for (int i = 0; i < results_ga_state.Count; ++i) { JSONNode result = results_ga_state[i]; state_dict.Add(result["key"], result["value"]); } } // insert into GAState instance GAState instance = GAState.Instance; instance.DefaultUserId = state_dict[DefaultUserIdKey] != null ? state_dict[DefaultUserIdKey].Value : Guid.NewGuid().ToString(); SessionNum = state_dict[SessionNumKey] != null ? state_dict[SessionNumKey].AsInt : 0; TransactionNum = state_dict[TransactionNumKey] != null ? state_dict[TransactionNumKey].AsInt : 0; // restore cross session user values if (!string.IsNullOrEmpty(instance.FacebookId)) { GAStore.SetState(FacebookIdKey, instance.FacebookId); } else { instance.FacebookId = state_dict[FacebookIdKey] != null ? state_dict[FacebookIdKey].Value : ""; if (!string.IsNullOrEmpty(instance.FacebookId)) { GALogger.D("facebookid found in DB: " + instance.FacebookId); } } if (!string.IsNullOrEmpty(instance.Gender)) { GAStore.SetState(GenderKey, instance.Gender); } else { instance.Gender = state_dict[GenderKey] != null ? state_dict[GenderKey].Value : ""; if (!string.IsNullOrEmpty(instance.Gender)) { GALogger.D("gender found in DB: " + instance.Gender); } } if (instance.BirthYear != 0) { GAStore.SetState(BirthYearKey, instance.BirthYear.ToString()); } else { instance.BirthYear = state_dict[BirthYearKey] != null ? state_dict[BirthYearKey].AsInt : 0; if (instance.BirthYear != 0) { GALogger.D("birthYear found in DB: " + instance.BirthYear); } } // restore dimension settings if (!string.IsNullOrEmpty(CurrentCustomDimension01)) { GAStore.SetState(Dimension01Key, CurrentCustomDimension01); } else { CurrentCustomDimension01 = state_dict[Dimension01Key] != null ? state_dict[Dimension01Key].Value : ""; if (!string.IsNullOrEmpty(CurrentCustomDimension01)) { GALogger.D("Dimension01 found in cache: " + CurrentCustomDimension01); } } if (!string.IsNullOrEmpty(CurrentCustomDimension02)) { GAStore.SetState(Dimension02Key, CurrentCustomDimension02); } else { CurrentCustomDimension02 = state_dict[Dimension02Key] != null ? state_dict[Dimension02Key].Value : ""; if (!string.IsNullOrEmpty(CurrentCustomDimension02)) { GALogger.D("Dimension02 found in cache: " + CurrentCustomDimension02); } } if (!string.IsNullOrEmpty(CurrentCustomDimension03)) { GAStore.SetState(Dimension03Key, CurrentCustomDimension03); } else { CurrentCustomDimension03 = state_dict[Dimension03Key] != null ? state_dict[Dimension03Key].Value : ""; if (!string.IsNullOrEmpty(CurrentCustomDimension03)) { GALogger.D("Dimension03 found in cache: " + CurrentCustomDimension03); } } // get cached init call values string sdkConfigCachedString = state_dict[SdkConfigCachedKey] != null ? state_dict[SdkConfigCachedKey].Value : ""; if (!string.IsNullOrEmpty(sdkConfigCachedString)) { // decode JSON JSONNode sdkConfigCached = null; try { sdkConfigCached = JSONNode.LoadFromBinaryBase64(sdkConfigCachedString); } catch (Exception) { //GALogger.E("EnsurePersistedStates: Error decoding json, " + e); } if (sdkConfigCached != null && sdkConfigCached.Count != 0) { instance.SdkConfigCached = sdkConfigCached; } } JSONArray results_ga_progression = GAStore.ExecuteQuerySync("SELECT * FROM ga_progression;"); if (results_ga_progression != null && results_ga_progression.Count != 0) { for (int i = 0; i < results_ga_progression.Count; ++i) { JSONNode result = results_ga_progression[i]; if (result != null && result.Count != 0) { instance.progressionTries[result["progression"].Value] = result["tries"].AsInt; } } } } }
public static JSONObject ValidateAndCleanCustomFields(IDictionary <string, object> fields) { JSONObject result = new JSONObject(); if (fields != null) { int count = 0; foreach (KeyValuePair <string, object> entry in fields) { if (entry.Key == null || entry.Value == null) { GALogger.W("ValidateAndCleanCustomFields: entry with key=" + entry.Key + ", value=" + entry.Value + " has been omitted because its key or value is null"); } else if (count < MaxCustomFieldsCount) { if (GAUtilities.StringMatch(entry.Key, "^[a-zA-Z0-9_]{1," + MaxCustomFieldsKeyLength + "}$")) { if (entry.Value is string || entry.Value is char) { string value = Convert.ToString(entry.Value); if (value.Length <= MaxCustomFieldsValueStringLength && value.Length > 0) { result[entry.Key] = value; ++count; } else { GALogger.W("ValidateAndCleanCustomFields: entry with key=" + entry.Key + ", value=" + entry.Value + " has been omitted because its value is an empty string or exceeds the max number of characters (" + MaxCustomFieldsValueStringLength + ")"); } } else if (entry.Value is double) { result[entry.Key] = new JSONNumber((double)entry.Value); ++count; } else if (entry.Value is float) { result[entry.Key] = new JSONNumber((float)entry.Value); ++count; } else if (entry.Value is long || entry.Value is ulong) { result[entry.Key] = new JSONNumber(Convert.ToInt64(entry.Value)); ++count; } else if (entry.Value is int || entry.Value is byte || entry.Value is sbyte || entry.Value is byte || entry.Value is uint || entry.Value is short || entry.Value is ushort) { result[entry.Key] = new JSONNumber(Convert.ToInt32(entry.Value)); ++count; } else { GALogger.W("ValidateAndCleanCustomFields: entry with key=" + entry.Key + ", value=" + entry.Value + " has been omitted because its value is not a string or number"); } } else { GALogger.W("ValidateAndCleanCustomFields: entry with key=" + entry.Key + ", value=" + entry.Value + " has been omitted because its key illegal characters, an empty or exceeds the max number of characters (" + MaxCustomFieldsKeyLength + ")"); } } else { GALogger.W("ValidateAndCleanCustomFields: entry with key=" + entry.Key + ", value=" + entry.Value + " has been omitted because it exceeds the max number of custom fields (" + MaxCustomFieldsCount + ")"); } } } return(result); }
public KeyValuePair <EGAHTTPApiResponse, JSONNode> SendEventsInArray(List <JSONNode> eventArray) #endif { JSONNode json; if (eventArray.Count == 0) { GALogger.D("sendEventsInArray called with missing eventArray"); } EGAHTTPApiResponse result = EGAHTTPApiResponse.NoResponse; string gameKey = GAState.GameKey; // Generate URL string url = baseUrl + "/" + gameKey + "/" + eventsUrlPath; GALogger.D("Sending 'events' URL: " + url); // make JSON string from data string JSONstring = GAUtilities.ArrayOfObjectsToJsonString(eventArray); if (JSONstring.Length == 0) { GALogger.D("sendEventsInArray JSON encoding failed of eventArray"); json = null; result = EGAHTTPApiResponse.JsonEncodeFailed; return(new KeyValuePair <EGAHTTPApiResponse, JSONNode>(result, json)); } string body = ""; HttpStatusCode responseCode = (HttpStatusCode)0; string responseDescription = ""; string authorization = ""; try { byte[] payloadData = CreatePayloadData(JSONstring, useGzip); HttpWebRequest request = CreateRequest(url, payloadData, useGzip); authorization = request.Headers[HttpRequestHeader.Authorization]; #if WINDOWS_UWP || WINDOWS_WSA using (Stream dataStream = await request.GetRequestStreamAsync()) #else using (Stream dataStream = request.GetRequestStream()) #endif { dataStream.Write(payloadData, 0, payloadData.Length); } #if WINDOWS_UWP || WINDOWS_WSA using (HttpWebResponse response = await request.GetResponseAsync() as HttpWebResponse) #else using (HttpWebResponse response = request.GetResponse() as HttpWebResponse) #endif { using (Stream dataStream = response.GetResponseStream()) { using (StreamReader reader = new StreamReader(dataStream)) { string responseString = reader.ReadToEnd(); responseCode = response.StatusCode; responseDescription = response.StatusDescription; // print result body = responseString; } } } } catch (WebException e) { if (e.Response != null) { using (HttpWebResponse response = (HttpWebResponse)e.Response) { using (Stream streamResponse = response.GetResponseStream()) { using (StreamReader streamRead = new StreamReader(streamResponse)) { string responseString = streamRead.ReadToEnd(); responseCode = response.StatusCode; responseDescription = response.StatusDescription; body = responseString; } } } } } catch (Exception e) { GALogger.E(e.ToString()); } GALogger.D("events request content: " + body); EGAHTTPApiResponse requestResponseEnum = ProcessRequestResponse(responseCode, responseDescription, body, "Events"); // if not 200 result if (requestResponseEnum != EGAHTTPApiResponse.Ok && requestResponseEnum != EGAHTTPApiResponse.BadRequest) { GALogger.D("Failed events Call. URL: " + url + ", Authorization: " + authorization + ", JSONString: " + JSONstring); json = null; result = requestResponseEnum; return(new KeyValuePair <EGAHTTPApiResponse, JSONNode>(result, json)); } // decode JSON JSONNode requestJsonDict = JSON.Parse(body); if (requestJsonDict == null) { json = null; result = EGAHTTPApiResponse.JsonDecodeFailed; return(new KeyValuePair <EGAHTTPApiResponse, JSONNode>(result, json)); } // print reason if bad request if (requestResponseEnum == EGAHTTPApiResponse.BadRequest) { GALogger.D("Failed Events Call. Bad request. Response: " + requestJsonDict.ToString()); } // return response json = requestJsonDict; result = requestResponseEnum; return(new KeyValuePair <EGAHTTPApiResponse, JSONNode>(result, json)); }
public static void SetManualSessionHandling(bool flag) { UseManualSessionHandling = flag; GALogger.I("Use manual session handling: " + flag); }
public static void AddProgressionEvent(EGAProgressionStatus progressionStatus, string progression01, string progression02, string progression03, double score, bool sendScore, IDictionary <string, object> fields, bool mergeFields) { 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); IDictionary <string, object> fieldsToUse = new Dictionary <string, object>(fields != null && fields.Count > 0 ? fields : GAState.CurrentGlobalCustomEventFields); if (mergeFields && fields != null && fields.Count > 0) { foreach (KeyValuePair <string, object> pair in GAState.CurrentGlobalCustomEventFields) { if (!fieldsToUse.ContainsKey(pair.Key)) { fieldsToUse.Add(pair.Key, pair.Value); } } } // Add custom fields AddFieldsToEvent(eventDict, GAState.ValidateAndCleanCustomFields(fieldsToUse)); // Log GALogger.I("Add PROGRESSION event: {status:" + progressionStatusString + ", progression01:" + progression01 + ", progression02:" + progression02 + ", progression03:" + progression03 + ", score:" + score + ", attempt:" + attempt_num + "}"); // Send to store AddEventToStore(eventDict); }