Files
LuaCsForBarotraumaEP/Libraries/GameAnalytics/GA-SDK-MONO-SHARED/State/GAState.cs
2020-03-04 13:04:10 +01:00

1342 lines
48 KiB
C#

using System;
using System.Collections.Generic;
using GameAnalyticsSDK.Net.Device;
using GameAnalyticsSDK.Net.Logging;
using GameAnalyticsSDK.Net.Store;
using GameAnalyticsSDK.Net.Events;
using GameAnalyticsSDK.Net.Utilities;
using GameAnalyticsSDK.Net.Http;
using GameAnalyticsSDK.Net.Validators;
using GameAnalyticsSDK.Net.Threading;
namespace GameAnalyticsSDK.Net.State
{
internal class GAState
{
#region Fields and properties
private const String CategorySdkError = "sdk_error";
private const int MaxCustomFieldsCount = 50;
private const int MaxCustomFieldsKeyLength = 64;
private const int MaxCustomFieldsValueStringLength = 256;
private static readonly GAState _instance = new GAState();
private static GAState Instance
{
get
{
return _instance;
}
}
private string _userId;
public static string UserId
{
private get { return Instance._userId; }
set
{
Instance._userId = value == null ? "" : value;
CacheIdentifier();
}
}
private string _identifier;
public static string Identifier
{
get { return Instance._identifier; }
private set { Instance._identifier = value; }
}
private bool _initialized;
public static bool Initialized
{
get { return Instance._initialized; }
private set { Instance._initialized = value; }
}
private long _sessionStart;
public static long SessionStart
{
get { return Instance._sessionStart; }
private set { Instance._sessionStart = value; }
}
private int _sessionNum;
public static int SessionNum
{
get { return Instance._sessionNum; }
private set { Instance._sessionNum = value; }
}
private int _transactionNum;
public static int TransactionNum
{
get { return Instance._transactionNum; }
private set { Instance._transactionNum = value; }
}
private string _sessionId;
public static string SessionId
{
get { return Instance._sessionId; }
private set { Instance._sessionId = value; }
}
private string _currentCustomDimension01;
public static string CurrentCustomDimension01
{
get { return Instance._currentCustomDimension01; }
private set { Instance._currentCustomDimension01 = value; }
}
private string _currentCustomDimension02;
public static string CurrentCustomDimension02
{
get { return Instance._currentCustomDimension02; }
private set { Instance._currentCustomDimension02 = value; }
}
private string _currentCustomDimension03;
public static string CurrentCustomDimension03
{
get { return Instance._currentCustomDimension03; }
private set { Instance._currentCustomDimension03 = value; }
}
private string _gameKey;
public static string GameKey
{
get { return Instance._gameKey; }
private set { Instance._gameKey = value; }
}
private string _gameSecret;
public static string GameSecret
{
get { return Instance._gameSecret; }
private set { Instance._gameSecret = value; }
}
private string[] _availableCustomDimensions01 = new string[0];
public static string[] AvailableCustomDimensions01
{
get { return Instance._availableCustomDimensions01; }
set
{
// Validate
if (!GAValidator.ValidateCustomDimensions(value))
{
return;
}
Instance._availableCustomDimensions01 = value;
// validate current dimension values
ValidateAndFixCurrentDimensions();
GALogger.I("Set available custom01 dimension values: (" + GAUtilities.JoinStringArray(value, ", ") + ")");
}
}
private string[] _availableCustomDimensions02 = new string[0];
public static string[] AvailableCustomDimensions02
{
get { return Instance._availableCustomDimensions02; }
set
{
// Validate
if (!GAValidator.ValidateCustomDimensions(value))
{
return;
}
Instance._availableCustomDimensions02 = value;
// validate current dimension values
ValidateAndFixCurrentDimensions();
GALogger.I("Set available custom02 dimension values: (" + GAUtilities.JoinStringArray(value, ", ") + ")");
}
}
private string[] _availableCustomDimensions03 = new string[0];
public static string[] AvailableCustomDimensions03
{
get { return Instance._availableCustomDimensions03; }
set
{
// Validate
if (!GAValidator.ValidateCustomDimensions(value))
{
return;
}
Instance._availableCustomDimensions03 = value;
// validate current dimension values
ValidateAndFixCurrentDimensions();
GALogger.I("Set available custom03 dimension values: (" + GAUtilities.JoinStringArray(value, ", ") + ")");
}
}
private string[] _availableResourceCurrencies = new string[0];
public static string[] AvailableResourceCurrencies
{
get { return Instance._availableResourceCurrencies; }
set
{
// Validate
if (!GAValidator.ValidateResourceCurrencies(value))
{
return;
}
Instance._availableResourceCurrencies = value;
GALogger.I("Set available resource currencies: (" + GAUtilities.JoinStringArray(value, ", ") + ")");
}
}
private string[] _availableResourceItemTypes = new string[0];
public static string[] AvailableResourceItemTypes
{
get { return Instance._availableResourceItemTypes; }
set
{
// Validate
if (!GAValidator.ValidateResourceItemTypes(value))
{
return;
}
Instance._availableResourceItemTypes = value;
GALogger.I("Set available resource item types: (" + GAUtilities.JoinStringArray(value, ", ") + ")");
}
}
private string _build;
public static string Build
{
get { return Instance._build; }
set { Instance._build = value; }
}
private bool _useManualSessionHandling;
public static bool UseManualSessionHandling
{
get { return Instance._useManualSessionHandling; }
private set { Instance._useManualSessionHandling = value; }
}
private bool _isEventSubmissionEnabled = true;
public static bool IsEventSubmissionEnabled
{
get { return Instance._isEventSubmissionEnabled; }
private set { Instance._isEventSubmissionEnabled = value; }
}
private bool Enabled
{
get;
set;
}
private string FacebookId
{
get;
set;
}
private string Gender
{
get;
set;
}
private int BirthYear
{
get;
set;
}
private JSONNode SdkConfigCached
{
get;
set;
}
private bool InitAuthorized
{
get;
set;
}
private long ClientServerTimeOffset
{
get;
set;
}
private long SuspendBlockId
{
get;
set;
}
private string _defaultUserId;
private string DefaultUserId
{
get { return Instance._defaultUserId; }
set
{
Instance._defaultUserId = value == null ? "" : value;
CacheIdentifier();
}
}
private static JSONNode SdkConfig
{
get
{
if (Instance.sdkConfig.AsObject != null && Instance.sdkConfig.Count != 0)
{
return Instance.sdkConfig;
}
if (Instance.sdkConfigCached.AsObject != null && Instance.sdkConfigCached.Count != 0)
{
return Instance.sdkConfigCached;
}
return Instance.sdkConfigDefault;
}
}
private Dictionary<string, int> progressionTries = new Dictionary<string, int>();
private JSONNode sdkConfigDefault = new JSONObject();
private JSONNode sdkConfig = new JSONObject();
private JSONNode sdkConfigCached = new JSONObject();
private JSONNode configurations = new JSONObject();
private bool commandCenterIsReady;
private readonly List<ICommandCenterListener> commandCenterListeners = new List<ICommandCenterListener>();
private readonly object configurationsLock = new object();
public const string InMemoryPrefix = "in_memory_";
private const string DefaultUserIdKey = "default_user_id";
public const string SessionNumKey = "session_num";
public const string TransactionNumKey = "transaction_num";
private const string FacebookIdKey = "facebook_id";
private const string GenderKey = "gender";
private const string BirthYearKey = "birth_year";
private const string Dimension01Key = "dimension01";
private const string Dimension02Key = "dimension02";
private const string Dimension03Key = "dimension03";
private const string SdkConfigCachedKey = "sdk_config_cached";
#endregion // Fields and properties
private GAState()
{
Enabled = false;
}
~GAState()
{
EndSessionAndStopQueue(false);
}
#region Public methods
public static bool IsEnabled()
{
return Instance.Enabled;
}
public static void SetCustomDimension01(string dimension)
{
CurrentCustomDimension01 = dimension;
if(GAStore.IsTableReady)
{
GAStore.SetState(Dimension01Key, dimension);
}
GALogger.I("Set custom01 dimension value: " + dimension);
}
public static void SetCustomDimension02(string dimension)
{
CurrentCustomDimension02 = dimension;
if(GAStore.IsTableReady)
{
GAStore.SetState(Dimension02Key, dimension);
}
GALogger.I("Set custom02 dimension value: " + dimension);
}
public static void SetCustomDimension03(string dimension)
{
CurrentCustomDimension03 = dimension;
if(GAStore.IsTableReady)
{
GAStore.SetState(Dimension03Key, dimension);
}
GALogger.I("Set custom03 dimension value: " + dimension);
}
public static void SetFacebookId(string facebookId)
{
Instance.FacebookId = facebookId;
if(GAStore.IsTableReady)
{
GAStore.SetState(FacebookIdKey, facebookId);
}
GALogger.I("Set facebook id: " + facebookId);
}
public static void SetGender(EGAGender gender)
{
Instance.Gender = gender.ToString().ToLowerInvariant();
if(GAStore.IsTableReady)
{
GAStore.SetState(GenderKey, Instance.Gender);
}
GALogger.I("Set gender: " + gender);
}
public static void SetBirthYear(int birthYear)
{
Instance.BirthYear = birthYear;
if(GAStore.IsTableReady)
{
GAStore.SetState(BirthYearKey, birthYear.ToString());
}
GALogger.I("Set birth year: " + birthYear);
}
public static void IncrementSessionNum()
{
int sessionNumInt = SessionNum + 1;
SessionNum = sessionNumInt;
}
public static void IncrementTransactionNum()
{
int transactionNumInt = TransactionNum + 1;
TransactionNum = transactionNumInt;
}
#pragma warning disable 0162
public static void IncrementProgressionTries(string progression)
{
int tries = GetProgressionTries(progression) + 1;
Instance.progressionTries[progression] = tries;
if(GAStore.InMemory)
{
GALogger.D("Trying to IncrementProgressionTries with InMemory=true - cannot. Skipping.");
}
else
{
// Persist
Dictionary<string, object> parms = new Dictionary<string, object>();
parms.Add("$progression", progression);
parms.Add("$tries", tries);
GAStore.ExecuteQuerySync("INSERT OR REPLACE INTO ga_progression (progression, tries) VALUES($progression, $tries);", parms);
}
}
#pragma warning restore 0162
public static int GetProgressionTries(string progression)
{
if(Instance.progressionTries.ContainsKey(progression))
{
return Instance.progressionTries[progression];
}
else
{
return 0;
}
}
#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);
}
}
#pragma warning restore 0162
public static bool HasAvailableCustomDimensions01(string dimension1)
{
return GAUtilities.StringArrayContainsString(AvailableCustomDimensions01, dimension1);
}
public static bool HasAvailableCustomDimensions02(string dimension2)
{
return GAUtilities.StringArrayContainsString(AvailableCustomDimensions02, dimension2);
}
public static bool HasAvailableCustomDimensions03(string dimension3)
{
return GAUtilities.StringArrayContainsString(AvailableCustomDimensions03, dimension3);
}
public static bool HasAvailableResourceCurrency(string currency)
{
return GAUtilities.StringArrayContainsString(AvailableResourceCurrencies, currency);
}
public static bool HasAvailableResourceItemType(string itemType)
{
return GAUtilities.StringArrayContainsString(AvailableResourceItemTypes, itemType);
}
public static void SetKeys(string gameKey, string gameSecret)
{
GameKey = gameKey;
GameSecret = gameSecret;
}
public static void SetManualSessionHandling(bool flag)
{
UseManualSessionHandling = flag;
GALogger.I("Use manual session handling: " + flag);
}
public static void SetEnabledEventSubmission(bool flag)
{
IsEventSubmissionEnabled = flag;
}
#if WINDOWS_UWP || WINDOWS_WSA
public async static void InternalInitialize()
#else
public static void InternalInitialize()
#endif
{
// Make sure database is ready
if (!GAStore.IsTableReady)
{
return;
}
EnsurePersistedStates();
GAStore.SetState(DefaultUserIdKey, Instance.DefaultUserId);
Initialized = true;
#if WINDOWS_UWP || WINDOWS_WSA
await StartNewSession();
#else
StartNewSession();
#endif
if (IsEnabled())
{
GAEvents.EnsureEventQueueIsRunning();
}
}
public static void EndSessionAndStopQueue(bool endThread)
{
if(Initialized)
{
if (IsEnabled() && SessionIsStarted())
{
GALogger.I("Ending session.");
GAEvents.StopEventQueue();
GAEvents.AddSessionEndEvent();
SessionStart = 0;
}
}
if(endThread)
{
GAThreading.StopThread();
}
}
#if WINDOWS_UWP || WINDOWS_WSA
public async static void ResumeSessionAndStartQueue()
#else
public static void ResumeSessionAndStartQueue()
#endif
{
if(!Initialized)
{
return;
}
GALogger.I("Resuming session.");
if(!SessionIsStarted())
{
#if WINDOWS_UWP || WINDOWS_WSA
await StartNewSession();
#else
StartNewSession();
#endif
}
}
public static JSONObject GetEventAnnotations()
{
JSONObject annotations = new JSONObject();
// ---- REQUIRED ---- //
// collector event API version
annotations.Add("v", new JSONNumber(2));
// User identifier
annotations["user_id"] = Identifier;
// Client Timestamp (the adjusted timestamp)
annotations.Add("client_ts", new JSONNumber(GetClientTsAdjusted()));
// SDK version
annotations["sdk_version"] = GADevice.RelevantSdkVersion;
// Operation system version
annotations["os_version"] = GADevice.OSVersion;
// Device make (hardcoded to apple)
annotations["manufacturer"] = GADevice.DeviceManufacturer;
// Device version
annotations["device"] = GADevice.DeviceModel;
// Platform (operating system)
annotations["platform"] = GADevice.BuildPlatform;
// Session identifier
annotations["session_id"] = SessionId;
// Session number
annotations.Add(SessionNumKey, new JSONNumber(SessionNum));
// type of connection the user is currently on (add if valid)
string connection_type = GADevice.ConnectionType;
if (GAValidator.ValidateConnectionType(connection_type))
{
annotations["connection_type"] = connection_type;
}
if (!string.IsNullOrEmpty(GADevice.GameEngineVersion))
{
annotations["engine_version"] = GADevice.GameEngineVersion;
}
#if WINDOWS_UWP
if (!string.IsNullOrEmpty(GADevice.AdvertisingId))
{
annotations["uwp_aid"] = GADevice.AdvertisingId;
}
else if (!string.IsNullOrEmpty(GADevice.DeviceId))
{
annotations["uwp_id"] = GADevice.DeviceId;
}
#endif
// ---- CONDITIONAL ---- //
// App build version (use if not nil)
if (!string.IsNullOrEmpty(Build))
{
annotations["build"] = Build;
}
// ---- OPTIONAL cross-session ---- //
// facebook id (optional)
if (!string.IsNullOrEmpty(Instance.FacebookId))
{
annotations[FacebookIdKey] = Instance.FacebookId;
}
// gender (optional)
if (!string.IsNullOrEmpty(Instance.Gender))
{
annotations[GenderKey] = Instance.Gender;
}
// birth_year (optional)
if (Instance.BirthYear != 0)
{
annotations.Add(BirthYearKey, new JSONNumber(Instance.BirthYear));
}
return annotations;
}
public static JSONObject GetSdkErrorEventAnnotations()
{
JSONObject annotations = new JSONObject();
// ---- REQUIRED ---- //
// collector event API version
annotations.Add("v", new JSONNumber(2));
// Category
annotations["category"] = CategorySdkError;
// SDK version
annotations["sdk_version"] = GADevice.RelevantSdkVersion;
// Operation system version
annotations["os_version"] = GADevice.OSVersion;
// Device make (hardcoded to apple)
annotations["manufacturer"] = GADevice.DeviceManufacturer;
// Device version
annotations["device"] = GADevice.DeviceModel;
// Platform (operating system)
annotations["platform"] = GADevice.BuildPlatform;
// type of connection the user is currently on (add if valid)
string connection_type = GADevice.ConnectionType;
if (GAValidator.ValidateConnectionType(connection_type))
{
annotations["connection_type"] = connection_type;
}
if (!string.IsNullOrEmpty(GADevice.GameEngineVersion))
{
annotations["engine_version"] = GADevice.GameEngineVersion;
}
return annotations;
}
public static JSONObject GetInitAnnotations()
{
JSONObject initAnnotations = new JSONObject();
initAnnotations["user_id"] = GAState.Identifier;
// SDK version
initAnnotations["sdk_version"] = GADevice.RelevantSdkVersion;
// Operation system version
initAnnotations["os_version"] = GADevice.OSVersion;
// Platform (operating system)
initAnnotations["platform"] = GADevice.BuildPlatform;
return initAnnotations;
}
public static long GetClientTsAdjusted()
{
long clientTs = GAUtilities.TimeIntervalSince1970();
long clientTsAdjustedInteger = clientTs + Instance.ClientServerTimeOffset;
if(GAValidator.ValidateClientTs(clientTsAdjustedInteger))
{
return clientTsAdjustedInteger;
}
else
{
return clientTs;
}
}
public static bool SessionIsStarted()
{
return SessionStart != 0;
}
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 static string GetConfigurationStringValue(string key, string defaultValue)
{
lock (Instance.configurationsLock)
{
return !Instance.configurations[key].IsNull ? Instance.configurations[key].Value : defaultValue;
}
}
public static bool IsCommandCenterReady()
{
return Instance.commandCenterIsReady;
}
public static void AddCommandCenterListener(ICommandCenterListener listener)
{
if(!Instance.commandCenterListeners.Contains(listener))
{
Instance.commandCenterListeners.Add(listener);
}
}
public static void RemoveCommandCenterListener(ICommandCenterListener listener)
{
if(Instance.commandCenterListeners.Contains(listener))
{
Instance.commandCenterListeners.Remove(listener);
}
}
public static string GetConfigurationsAsString()
{
return Instance.configurations.ToString();
}
#endregion // Public methods
#region Private methods
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 + "}");
}
#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;
}
}
}
}
}
#pragma warning restore 0162
#if WINDOWS_UWP || WINDOWS_WSA
private async static System.Threading.Tasks.Task StartNewSession()
#else
private static void StartNewSession()
#endif
{
GALogger.I("Starting a new session.");
// make sure the current custom dimensions are valid
ValidateAndFixCurrentDimensions();
// call the init call
#if WINDOWS_UWP || WINDOWS_WSA
KeyValuePair<EGAHTTPApiResponse, JSONObject> initResponse = await GAHTTPApi.Instance.RequestInitReturningDict();
#else
KeyValuePair<EGAHTTPApiResponse, JSONObject> initResponse = GAHTTPApi.Instance.RequestInitReturningDict();
#endif
StartNewSession(initResponse.Key, initResponse.Value);
}
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();
}
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("");
}
}
private static long CalculateServerTimeOffset(long serverTs)
{
long clientTs = GAUtilities.TimeIntervalSince1970();
return serverTs - clientTs;
}
private static void PopulateConfigurations(JSONNode sdkConfig)
{
lock(Instance.configurationsLock)
{
JSONArray configurations = sdkConfig["configurations"].AsArray;
if(configurations != null)
{
for(int i = 0; i < configurations.Count; ++i)
{
JSONNode configuration = configurations[i];
if(configuration != null)
{
string key = configuration["key"].Value;
object value = null;
if(configuration["value"].IsNumber)
{
value = configuration["value"].AsDouble;
}
else
{
value = configuration["value"].Value;
}
long start_ts = configuration["start"].IsNumber ? configuration["start"].AsLong : long.MinValue;
long end_ts = configuration["end"].IsNumber ? configuration["end"].AsLong : long.MaxValue;
long client_ts_adjusted = GetClientTsAdjusted();
GALogger.D("PopulateConfigurations: key=" + key + ", value=" + value + ", start_ts=" + start_ts + ", end_ts=" + ", client_ts_adjusted=" + client_ts_adjusted);
if(key != null && value != null && client_ts_adjusted > start_ts && client_ts_adjusted < end_ts)
{
JSONObject json = new JSONObject();
if(configuration["value"].IsNumber)
{
Instance.configurations.Add(key, new JSONNumber(configuration["value"].AsDouble));
}
else
{
Instance.configurations.Add(key, configuration["value"].Value);
}
GALogger.D("configuration added: " + configuration);
}
}
}
}
Instance.commandCenterIsReady = true;
foreach(ICommandCenterListener listener in Instance.commandCenterListeners)
{
listener.OnCommandCenterUpdated();
}
}
}
#endregion // Private methods
}
}