From 7bb2495d6ca6f734468ebc7114dabe43a6b45107 Mon Sep 17 00:00:00 2001 From: pixelshade Date: Mon, 21 Mar 2016 17:34:28 +0100 Subject: [PATCH 01/14] Added timestamp ssanity check, added double culture to storage --- .../Scripts/InfinarioSDK/PersistentStorage.cs | 5 +++-- source/Assets/Scripts/InfinarioSDK/Utils.cs | 14 ++++++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/source/Assets/Scripts/InfinarioSDK/PersistentStorage.cs b/source/Assets/Scripts/InfinarioSDK/PersistentStorage.cs index 9194ee6..634e57c 100644 --- a/source/Assets/Scripts/InfinarioSDK/PersistentStorage.cs +++ b/source/Assets/Scripts/InfinarioSDK/PersistentStorage.cs @@ -4,6 +4,7 @@ using Infinario.MiniJSON; using System; using System.Linq; +using System.Globalization; namespace Infinario.Storage { @@ -61,7 +62,7 @@ public void SaveSessionStart(double timestamp, Dictionary proper { lock (lockAccess) { - PlayerPrefs.SetString (Constants.PROPERTY_SESSION_START_TIMESTAMP, timestamp.ToString()); + PlayerPrefs.SetString (Constants.PROPERTY_SESSION_START_TIMESTAMP, timestamp.ToString("R", CultureInfo.InvariantCulture)); PlayerPrefs.SetString (Constants.PROPERTY_SESSION_START_PROPERTIES, Json.Serialize(properties)); } } @@ -87,7 +88,7 @@ public void SaveSessionEnd(double timestamp, Dictionary properti { lock (lockAccess) { - PlayerPrefs.SetString (Constants.PROPERTY_SESSION_END_TIMESTAMP, timestamp.ToString()); + PlayerPrefs.SetString (Constants.PROPERTY_SESSION_END_TIMESTAMP, timestamp.ToString("R", CultureInfo.InvariantCulture)); PlayerPrefs.SetString (Constants.PROPERTY_SESSION_END_PROPERTIES, Json.Serialize(properties)); } } diff --git a/source/Assets/Scripts/InfinarioSDK/Utils.cs b/source/Assets/Scripts/InfinarioSDK/Utils.cs index 111310d..f0668bd 100644 --- a/source/Assets/Scripts/InfinarioSDK/Utils.cs +++ b/source/Assets/Scripts/InfinarioSDK/Utils.cs @@ -10,8 +10,18 @@ public class Utils public static double GetCurrentTimestamp() { var t0 = DateTime.UtcNow; - var tEpoch = new DateTime(1970, 1, 1, 0, 0, 0); - return t0.Subtract(tEpoch).TotalMilliseconds / 1000.0; + + var tEpoch = new DateTime(1970, 1, 1, 0, 0, 0); + var tTime = t0.Subtract(tEpoch).TotalMilliseconds / 1000.0; + + var tSanityDateTime = new DateTime(2020, 1, 1, 0, 0, 0); + var tSanity = (tSanityDateTime.Subtract(tEpoch)).TotalMilliseconds / 1000.0; + while(tTime > tSanity) + { + tTime = tTime / 10.0; + } + + return tTime; } public static string GenerateCookieId() From 73cb7730a0a2d7878271b54c337990706d3789d6 Mon Sep 17 00:00:00 2001 From: Martin Strapko Date: Sat, 2 Apr 2016 17:31:03 +0200 Subject: [PATCH 02/14] Added support for dual identifiers --- .../Assets/Scripts/InfinarioSDK/Constants.cs | 5 ++-- .../Scripts/InfinarioSDK/InfinarioUnitySDK.cs | 28 +++++++++++++------ .../Scripts/InfinarioSDK/PersistentStorage.cs | 25 +++++++++++++++-- 3 files changed, 46 insertions(+), 12 deletions(-) diff --git a/source/Assets/Scripts/InfinarioSDK/Constants.cs b/source/Assets/Scripts/InfinarioSDK/Constants.cs index 196b17e..10d6845 100644 --- a/source/Assets/Scripts/InfinarioSDK/Constants.cs +++ b/source/Assets/Scripts/InfinarioSDK/Constants.cs @@ -13,8 +13,9 @@ internal class Constants */ public static string ID_REGISTERED = "registered"; public static string ID_COOKIE = "cookie"; - - public static string EVENT_SESSION_START = "session_start"; + public static string ID_USER = "user_id"; + + public static string EVENT_SESSION_START = "session_start"; public static string EVENT_SESSION_END = "session_end"; public static string EVENT_IDENTIFICATION = "identification"; public static string EVENT_VIRTUAL_PAYMENT = "virtual_payment"; diff --git a/source/Assets/Scripts/InfinarioSDK/InfinarioUnitySDK.cs b/source/Assets/Scripts/InfinarioSDK/InfinarioUnitySDK.cs index 6fe12e0..0fef159 100644 --- a/source/Assets/Scripts/InfinarioSDK/InfinarioUnitySDK.cs +++ b/source/Assets/Scripts/InfinarioSDK/InfinarioUnitySDK.cs @@ -38,14 +38,26 @@ public override void Initialize(string projectToken, string appVersion, string t public override void Identify(Dictionary customer, Dictionary properties) { - if (customer.ContainsKey (Constants.ID_REGISTERED) && customer[Constants.ID_REGISTERED] != null) - { - customerIds[Constants.ID_REGISTERED] = customer[Constants.ID_REGISTERED]; - - if (!customer[Constants.ID_REGISTERED].Equals(storage.GetRegisteredId())) - { - storage.SaveRegisteredId(customer[Constants.ID_REGISTERED].ToString()); - Dictionary mergedProperties = MergeAutomaticProperties(customer); + if ((customer.ContainsKey (Constants.ID_REGISTERED) && customer[Constants.ID_REGISTERED] != null) || (customer.ContainsKey(Constants.ID_USER) && customer[Constants.ID_USER] != null)) + { + if (customer.ContainsKey(Constants.ID_REGISTERED)) customerIds[Constants.ID_REGISTERED] = customer[Constants.ID_REGISTERED]; + else + { + if (customerIds.ContainsKey(Constants.ID_REGISTERED)) customerIds.Remove(Constants.ID_REGISTERED); + } + if (customer.ContainsKey(Constants.ID_USER)) customerIds[Constants.ID_USER] = customer[Constants.ID_USER]; + else + { + if (customerIds.ContainsKey(Constants.ID_USER)) customerIds.Remove(Constants.ID_USER); + } + + if ((customer.ContainsKey(Constants.ID_REGISTERED) && !customer[Constants.ID_REGISTERED].Equals(storage.GetRegisteredId())) || (customer.ContainsKey(Constants.ID_USER) && !customer[Constants.ID_USER].Equals(storage.GetUserId()))) + { + if (customer.ContainsKey(Constants.ID_REGISTERED)) storage.SaveRegisteredId(customer[Constants.ID_REGISTERED].ToString()); + else storage.SaveRegisteredId(null); + if (customer.ContainsKey(Constants.ID_USER)) storage.SaveUserId(customer[Constants.ID_USER].ToString()); + else storage.SaveUserId(null); + Dictionary mergedProperties = MergeAutomaticProperties(customer); Track (Constants.EVENT_IDENTIFICATION, mergedProperties, double.NaN); if (properties != null) diff --git a/source/Assets/Scripts/InfinarioSDK/PersistentStorage.cs b/source/Assets/Scripts/InfinarioSDK/PersistentStorage.cs index 634e57c..8b726e3 100644 --- a/source/Assets/Scripts/InfinarioSDK/PersistentStorage.cs +++ b/source/Assets/Scripts/InfinarioSDK/PersistentStorage.cs @@ -58,7 +58,24 @@ public string GetRegisteredId() } } - public void SaveSessionStart(double timestamp, Dictionary properties) + public void SaveUserId(string userId) + { + lock (lockAccess) + { + PlayerPrefs.SetString(Constants.ID_USER, userId); + } + } + + public string GetUserId() + { + lock (lockAccess) + { + var userId = PlayerPrefs.GetString(Constants.ID_USER); + return (String.IsNullOrEmpty(userId) ? null : userId); + } + } + + public void SaveSessionStart(double timestamp, Dictionary properties) { lock (lockAccess) { @@ -130,7 +147,11 @@ public Dictionary GetIds() var registered = GetRegisteredId (); if (!string.IsNullOrEmpty (registered)) ids.Add(Constants.ID_REGISTERED, registered); - return ids; + + var userid = GetUserId(); + if (!string.IsNullOrEmpty(userid)) + ids.Add(Constants.ID_USER, userid); + return ids; } } } From f91cc0a78c2fd0722aae38c9bbc0c2fb2436df7f Mon Sep 17 00:00:00 2001 From: Martin Strapko Date: Sat, 2 Apr 2016 17:31:03 +0200 Subject: [PATCH 03/14] Added support for dual identifiers --- .../Scripts/InfinarioSDK/InfinarioUnitySDK.cs | 50 +++++++++++++++---- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/source/Assets/Scripts/InfinarioSDK/InfinarioUnitySDK.cs b/source/Assets/Scripts/InfinarioSDK/InfinarioUnitySDK.cs index 0fef159..6f6143c 100644 --- a/source/Assets/Scripts/InfinarioSDK/InfinarioUnitySDK.cs +++ b/source/Assets/Scripts/InfinarioSDK/InfinarioUnitySDK.cs @@ -38,30 +38,58 @@ public override void Initialize(string projectToken, string appVersion, string t public override void Identify(Dictionary customer, Dictionary properties) { - if ((customer.ContainsKey (Constants.ID_REGISTERED) && customer[Constants.ID_REGISTERED] != null) || (customer.ContainsKey(Constants.ID_USER) && customer[Constants.ID_USER] != null)) + if ((customer.ContainsKey (Constants.ID_REGISTERED) && customer[Constants.ID_REGISTERED] != null) || + (customer.ContainsKey(Constants.ID_USER) && customer[Constants.ID_USER] != null)) { - if (customer.ContainsKey(Constants.ID_REGISTERED)) customerIds[Constants.ID_REGISTERED] = customer[Constants.ID_REGISTERED]; + if (customer.ContainsKey(Constants.ID_REGISTERED)) + { + customerIds[Constants.ID_REGISTERED] = customer[Constants.ID_REGISTERED]; + } else { - if (customerIds.ContainsKey(Constants.ID_REGISTERED)) customerIds.Remove(Constants.ID_REGISTERED); + if (customerIds.ContainsKey(Constants.ID_REGISTERED)) + { + customerIds.Remove(Constants.ID_REGISTERED); + } } - if (customer.ContainsKey(Constants.ID_USER)) customerIds[Constants.ID_USER] = customer[Constants.ID_USER]; + if (customer.ContainsKey(Constants.ID_USER)) + { + customerIds[Constants.ID_USER] = customer[Constants.ID_USER]; + } else { - if (customerIds.ContainsKey(Constants.ID_USER)) customerIds.Remove(Constants.ID_USER); + if (customerIds.ContainsKey(Constants.ID_USER)) + { + customerIds.Remove(Constants.ID_USER); + } } - if ((customer.ContainsKey(Constants.ID_REGISTERED) && !customer[Constants.ID_REGISTERED].Equals(storage.GetRegisteredId())) || (customer.ContainsKey(Constants.ID_USER) && !customer[Constants.ID_USER].Equals(storage.GetUserId()))) + if ((customer.ContainsKey(Constants.ID_REGISTERED) && !customer[Constants.ID_REGISTERED].Equals(storage.GetRegisteredId())) || + (customer.ContainsKey(Constants.ID_USER) && !customer[Constants.ID_USER].Equals(storage.GetUserId()))) { - if (customer.ContainsKey(Constants.ID_REGISTERED)) storage.SaveRegisteredId(customer[Constants.ID_REGISTERED].ToString()); - else storage.SaveRegisteredId(null); - if (customer.ContainsKey(Constants.ID_USER)) storage.SaveUserId(customer[Constants.ID_USER].ToString()); - else storage.SaveUserId(null); + if (customer.ContainsKey(Constants.ID_REGISTERED)) + { + storage.SaveRegisteredId(customer[Constants.ID_REGISTERED].ToString()); + } + else + { + storage.SaveRegisteredId(null); + } + if (customer.ContainsKey(Constants.ID_USER)) + { + storage.SaveUserId(customer[Constants.ID_USER].ToString()); + } + else + { + storage.SaveUserId(null); + } Dictionary mergedProperties = MergeAutomaticProperties(customer); Track (Constants.EVENT_IDENTIFICATION, mergedProperties, double.NaN); - if (properties != null) + if (properties != null) + { Update(properties); + } } } } From bcaa38b7ef0fe02f12d13e16bd33e197d8d83229 Mon Sep 17 00:00:00 2001 From: Martin Strapko Date: Sat, 2 Apr 2016 18:47:59 +0200 Subject: [PATCH 04/14] updated release version --- source/Assets/Scripts/InfinarioSDK/Constants.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/Assets/Scripts/InfinarioSDK/Constants.cs b/source/Assets/Scripts/InfinarioSDK/Constants.cs index 10d6845..a0b52bd 100644 --- a/source/Assets/Scripts/InfinarioSDK/Constants.cs +++ b/source/Assets/Scripts/InfinarioSDK/Constants.cs @@ -6,7 +6,7 @@ internal class Constants * SDK */ public static string SDK = "Unity SDK"; - public static string VERSION = "2.0.2"; + public static string VERSION = "2.0.3"; /** * Tracking ids, events and properties From d7bcc2302c331158f9237c0fad44d071252ce655 Mon Sep 17 00:00:00 2001 From: Osama Hassanein Date: Mon, 17 Oct 2016 20:52:38 +0200 Subject: [PATCH 05/14] Fix warning by using a derived class from MonoBehaviour in the AddComponent method --- source/Assets/Scripts/InfinarioSDK/Sender.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/source/Assets/Scripts/InfinarioSDK/Sender.cs b/source/Assets/Scripts/InfinarioSDK/Sender.cs index da26433..fc1cda1 100644 --- a/source/Assets/Scripts/InfinarioSDK/Sender.cs +++ b/source/Assets/Scripts/InfinarioSDK/Sender.cs @@ -7,6 +7,10 @@ namespace Infinario.Sender { + class InfinarioMonoBehaviour : MonoBehaviour + { + } + class Sender { public Sender(string target, PersistentBulkCommandQueue commandQueue) @@ -22,7 +26,7 @@ protected void StartCoroutine(IEnumerator coroutine) { var go = new GameObject("Infinario Coroutines"); UnityEngine.Object.DontDestroyOnLoad(go); - _coroutineObject = go.AddComponent(); + _coroutineObject = go.AddComponent(); } _coroutineObject.StartCoroutine (coroutine); } From 08cc2d351ce617f0fc75f3cb0a0c311a822d04be Mon Sep 17 00:00:00 2001 From: pixelshade Date: Mon, 28 Nov 2016 23:47:31 +0100 Subject: [PATCH 06/14] Get Segment Feature working --- .../Assets/Scripts/InfinarioSDK/Constants.cs | 7 +- .../Scripts/InfinarioSDK/ExponeaSegment.cs | 39 +++ .../Assets/Scripts/InfinarioSDK/Infinario.cs | 10 +- .../InfinarioSDK/InfinarioInterface.cs | 4 +- .../Scripts/InfinarioSDK/InfinarioUnitySDK.cs | 13 +- source/Assets/Scripts/InfinarioSDK/Sender.cs | 316 +++++++++++------- 6 files changed, 264 insertions(+), 125 deletions(-) create mode 100644 source/Assets/Scripts/InfinarioSDK/ExponeaSegment.cs diff --git a/source/Assets/Scripts/InfinarioSDK/Constants.cs b/source/Assets/Scripts/InfinarioSDK/Constants.cs index a0b52bd..461d333 100644 --- a/source/Assets/Scripts/InfinarioSDK/Constants.cs +++ b/source/Assets/Scripts/InfinarioSDK/Constants.cs @@ -43,10 +43,13 @@ internal class Constants public static long BULK_MAX = 60 * 20; public static double SESSION_TIMEOUT = 60; - - public static string DEFAULT_TARGET = "https://api.infinario.com"; + + public static string DEFAULT_SECRET = "X-Infinario-Secret"; + public static string DEFAULT_TARGET = "https://api.infinario.com"; public static string BULK_URL = "/bulk"; + public static string GET_SEGMENT_URL = "/analytics/segmentation-for"; + public static string ENDPOINT_UPDATE = "crm/customers"; public static string ENDPOINT_TRACK = "crm/events"; } diff --git a/source/Assets/Scripts/InfinarioSDK/ExponeaSegment.cs b/source/Assets/Scripts/InfinarioSDK/ExponeaSegment.cs new file mode 100644 index 0000000..84ff44d --- /dev/null +++ b/source/Assets/Scripts/InfinarioSDK/ExponeaSegment.cs @@ -0,0 +1,39 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; +using System; + +namespace Infinario +{ + class ExponeaSegment + { + private string _name; + private string _analysis_name; + private int _index; + + public ExponeaSegment(string name, string analysisName, int index){ + this._name = name; + this._analysis_name = analysisName; + this._index = index; + } + + public string GetName(){ + return this._name; + } + + public string GetSegmentationName() + { + return this._analysis_name; + } + + public int? GetSegmentIndex() + { + return this._index; + } + + public override string ToString() + { + return "Segment: " + _name + ", Segment Index: " + _index + ", Segmentation name: " + _analysis_name; + } + } +} diff --git a/source/Assets/Scripts/InfinarioSDK/Infinario.cs b/source/Assets/Scripts/InfinarioSDK/Infinario.cs index 2a62c6d..39a5210 100644 --- a/source/Assets/Scripts/InfinarioSDK/Infinario.cs +++ b/source/Assets/Scripts/InfinarioSDK/Infinario.cs @@ -1,3 +1,4 @@ +using System; using System.Collections; using System.Collections.Generic; using Infinario.Interface; @@ -32,8 +33,8 @@ public void Initialize(string projectToken) { Initialize (projectToken, null, null); } - - public void Initialize(string projectToken, string appVersion) + + public void Initialize(string projectToken, string appVersion) { Initialize (projectToken, appVersion, null); } @@ -125,5 +126,10 @@ public void SessionStatus(bool paused, Dictionary properties) } } + public void GetCurrentSegment(string projectSecret, string segmentationId, Action onSegmentReceiveCallback) + { + implementation.GetCurrentSegment(projectSecret, segmentationId, onSegmentReceiveCallback); + } + } } diff --git a/source/Assets/Scripts/InfinarioSDK/InfinarioInterface.cs b/source/Assets/Scripts/InfinarioSDK/InfinarioInterface.cs index 02747f8..939e0cf 100644 --- a/source/Assets/Scripts/InfinarioSDK/InfinarioInterface.cs +++ b/source/Assets/Scripts/InfinarioSDK/InfinarioInterface.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; namespace Infinario.Interface { @@ -11,5 +12,6 @@ abstract class IInfinario public abstract void TrackSessionStart (Dictionary properties); public abstract void TrackSessionEnd (Dictionary properties); public abstract void TrackVirtualPayment (string currency, long amount, string itemName, string itemType); + public abstract void GetCurrentSegment (string projectSecret, string segmentaionId, Action onSegmentReceiveCallback); } } \ No newline at end of file diff --git a/source/Assets/Scripts/InfinarioSDK/InfinarioUnitySDK.cs b/source/Assets/Scripts/InfinarioSDK/InfinarioUnitySDK.cs index 6f6143c..5e93b3e 100644 --- a/source/Assets/Scripts/InfinarioSDK/InfinarioUnitySDK.cs +++ b/source/Assets/Scripts/InfinarioSDK/InfinarioUnitySDK.cs @@ -1,4 +1,5 @@ +using System; using System.Text; using System.Collections; using System.Collections.Generic; @@ -16,6 +17,7 @@ class Unity : IInfinario private string appVersion = null; private Dictionary deviceProperties = null; Dictionary customerIds = null; + private Sender.Sender sender; private static object initializeFinalizeLock = new object(); private static object sessionLock = new object(); @@ -33,7 +35,7 @@ public override void Initialize(string projectToken, string appVersion, string t commandQueue = new PersistentBulkCommandQueue ("events", Constants.BULK_LIMIT); - new Sender.Sender ((target != null) ? target : Constants.DEFAULT_TARGET, commandQueue); + sender = new Sender.Sender ((target != null) ? target : Constants.DEFAULT_TARGET, commandQueue); } public override void Identify(Dictionary customer, Dictionary properties) @@ -168,7 +170,12 @@ public override void TrackVirtualPayment(string currency, long amount, string it this.Track(Constants.EVENT_VIRTUAL_PAYMENT, properties, double.NaN); } - private Dictionary MergeAutomaticProperties(Dictionary properties) + public override void GetCurrentSegment(string projectSecret, string segmentaionId, Action onSegmentReceiveCallback) + { + sender.GetCurrentSegment(customerIds, projectSecret, segmentaionId, onSegmentReceiveCallback); + } + + private Dictionary MergeAutomaticProperties(Dictionary properties) { lock (initializeFinalizeLock) { @@ -191,5 +198,7 @@ private void ScheduleCommand(Command command) lst.Add (command.Execute()); commandQueue.MultiEnqueue(lst); } + + } } diff --git a/source/Assets/Scripts/InfinarioSDK/Sender.cs b/source/Assets/Scripts/InfinarioSDK/Sender.cs index fc1cda1..136f42d 100644 --- a/source/Assets/Scripts/InfinarioSDK/Sender.cs +++ b/source/Assets/Scripts/InfinarioSDK/Sender.cs @@ -4,128 +4,208 @@ using Infinario.Storage; using Infinario.MiniJSON; using System.Text; +using System; -namespace Infinario.Sender +namespace Infinario.Sender { - class InfinarioMonoBehaviour : MonoBehaviour + class InfinarioMonoBehaviour : MonoBehaviour { } - class Sender - { - public Sender(string target, PersistentBulkCommandQueue commandQueue) - { - this.StartCoroutine (APISendLoop(target, commandQueue)); - } - - protected MonoBehaviour _coroutineObject; - - protected void StartCoroutine(IEnumerator coroutine) - { - if (_coroutineObject == null) - { - var go = new GameObject("Infinario Coroutines"); - UnityEngine.Object.DontDestroyOnLoad(go); - _coroutineObject = go.AddComponent(); - } - _coroutineObject.StartCoroutine (coroutine); - } - - /// - /// Periodically performs the following steps: - /// 0. keep alive the session - // 1. collect the freshest command bulk - // 2. try-send bulk - // 3. validate response - // 4. parse response and enqueue for retry if needed - // 5. wait for N seconds (N grows with the number of consecutive connection failures) - /// - /// The send loop enumerator. - private IEnumerator APISendLoop(string target, PersistentBulkCommandQueue commandQueue) - { - const int WAIT_FOR_DEFAULT = 3; - var httpTarget = target + Constants.BULK_URL; - int consecutiveFailedRequests = 0; - - while (true) - { - // Decide if we process retry commands or new commands in this round - List commands = commandQueue.BulkDequeue(true); - - if (commands.Count > 0) - { - // 1B: Prepare the http components - var httpBody = Json.Serialize(new Dictionary {{"commands", commands}}); - byte[] httpBodyBytes = Encoding.UTF8.GetBytes(httpBody); - Dictionary httpHeaders = new Dictionary{ {"Content-type", "application/json"} }; - - // 2. Send the bulk API request - WWW req = new WWW(httpTarget, httpBodyBytes, httpHeaders); //TODO: we could add a timeout functionality - yield return req; - - // 3A: Check response for errors - if (!string.IsNullOrEmpty(req.error)) - { - consecutiveFailedRequests++; - } - else - { - // 3B. Parse the API response - var responseBody = req.text; - Dictionary apiResponse = (Dictionary) Json.Deserialize(responseBody); - bool success = (bool) apiResponse["success"]; - if(success) - { - consecutiveFailedRequests = 0; - - // 4A: extract retry-commands and queue them back (if any) - var retryCommands = ExtractRetryCommands(apiResponse,commands); - commandQueue.MultiDequeue(commands.Count); //remove every command from this request - commandQueue.MultiPush(retryCommands); //re-add failed commands with the highest priority - } - else - { - consecutiveFailedRequests++; - } - } - - } - - // 5. Detemine wait time and go idle. - float waitSeconds = (float)System.Math.Pow(WAIT_FOR_DEFAULT, System.Math.Sqrt(consecutiveFailedRequests+1)); - if(consecutiveFailedRequests == 0 && commandQueue.ElementCount > 0) - { - waitSeconds = 0f; - } - waitSeconds = System.Math.Min (waitSeconds, Constants.BULK_MAX - 3f); - - yield return new WaitForSeconds(waitSeconds); - } - } - - /// - /// Walks through the API response and returns all commands that should be retried. - /// - /// A list of retry command objects. - /// API response dictionary object. - /// Request dictionary object. - private List ExtractRetryCommands(Dictionary response,List sentCommands) - { - List commandResponses = response ["results"] as List; - - List retryCommands = new List (); - int idx = 0; - foreach (var cmdResponse in commandResponses) - { - var cmdResponseDict = (Dictionary)cmdResponse; - string status = (cmdResponseDict ["status"] as string).ToLower (); - if (status.Equals ("retry")) - { - retryCommands.Add (sentCommands[idx]); - } - idx++; - } - return retryCommands; - } + class Sender + { + private string _target; + + public Sender(string target, PersistentBulkCommandQueue commandQueue) + { + this.StartCoroutine(APISendLoop(target, commandQueue)); + _target = target; + } + + protected MonoBehaviour _coroutineObject; + + protected void StartCoroutine(IEnumerator coroutine) + { + if (_coroutineObject == null) + { + var go = new GameObject("Infinario Coroutines"); + UnityEngine.Object.DontDestroyOnLoad(go); + _coroutineObject = go.AddComponent(); + } + _coroutineObject.StartCoroutine(coroutine); + } + + /// + /// Periodically performs the following steps: + /// 0. keep alive the session + // 1. collect the freshest command bulk + // 2. try-send bulk + // 3. validate response + // 4. parse response and enqueue for retry if needed + // 5. wait for N seconds (N grows with the number of consecutive connection failures) + /// + /// The send loop enumerator. + private IEnumerator APISendLoop(string target, PersistentBulkCommandQueue commandQueue) + { + const int WAIT_FOR_DEFAULT = 3; + var httpTarget = target + Constants.BULK_URL; + int consecutiveFailedRequests = 0; + + while (true) + { + // Decide if we process retry commands or new commands in this round + List commands = commandQueue.BulkDequeue(true); + + if (commands.Count > 0) + { + // 1B: Prepare the http components + var httpBody = Json.Serialize(new Dictionary {{"commands", commands}}); + byte[] httpBodyBytes = Encoding.UTF8.GetBytes(httpBody); + Dictionary httpHeaders = new Dictionary + { + {"Content-type", "application/json"} + }; + + // 2. Send the bulk API request + WWW req = new WWW(httpTarget, httpBodyBytes, httpHeaders); + //TODO: we could add a timeout functionality + yield return req; + + // 3A: Check response for errors + if (!string.IsNullOrEmpty(req.error)) + { + consecutiveFailedRequests++; + } + else + { + // 3B. Parse the API response + var responseBody = req.text; + Dictionary apiResponse = + (Dictionary) Json.Deserialize(responseBody); + bool success = (bool) apiResponse["success"]; + if (success) + { + consecutiveFailedRequests = 0; + + // 4A: extract retry-commands and queue them back (if any) + var retryCommands = ExtractRetryCommands(apiResponse, commands); + commandQueue.MultiDequeue(commands.Count); //remove every command from this request + commandQueue.MultiPush(retryCommands); //re-add failed commands with the highest priority + } + else + { + consecutiveFailedRequests++; + } + } + + } + + // 5. Detemine wait time and go idle. + float waitSeconds = + (float) System.Math.Pow(WAIT_FOR_DEFAULT, System.Math.Sqrt(consecutiveFailedRequests + 1)); + if (consecutiveFailedRequests == 0 && commandQueue.ElementCount > 0) + { + waitSeconds = 0f; + } + waitSeconds = System.Math.Min(waitSeconds, Constants.BULK_MAX - 3f); + + yield return new WaitForSeconds(waitSeconds); + } + } + + /// + /// Walks through the API response and returns all commands that should be retried. + /// + /// A list of retry command objects. + /// API response dictionary object. + /// Request dictionary object. + private List ExtractRetryCommands(Dictionary response, List sentCommands) + { + List commandResponses = response["results"] as List; + + List retryCommands = new List(); + int idx = 0; + foreach (var cmdResponse in commandResponses) + { + var cmdResponseDict = (Dictionary) cmdResponse; + string status = (cmdResponseDict["status"] as string).ToLower(); + if (status.Equals("retry")) + { + retryCommands.Add(sentCommands[idx]); + } + idx++; + } + return retryCommands; + } + + + private IEnumerator GetCurrentSegmentCoroutine(Dictionary customerIds, string projectSecret, + string segmentationId, Action onSegmentReceiveCallback) + { + + + var httpTarget = (_target ?? Constants.DEFAULT_TARGET) + Constants.GET_SEGMENT_URL; + + // var httpBody = Json.Serialize(new Dictionary {{"commands", commands}}); + + + var body = new Dictionary() + { + {"customer_ids", customerIds}, + {"analysis_id", segmentationId} + }; + + var httpBody = Json.Serialize(body); + + byte[] httpBodyBytes = Encoding.UTF8.GetBytes(httpBody); + Dictionary httpHeaders = new Dictionary + { + {"Accept", "application/json"}, + {"Content-type", "application/json"}, + {Constants.DEFAULT_SECRET, projectSecret} // this needs to be project secret not project token + }; + + WWW req = new WWW(httpTarget, httpBodyBytes, httpHeaders); //TODO: we could add a timeout functionality + yield return req; + + // Check response for errors + if (!string.IsNullOrEmpty(req.error)) + { + onSegmentReceiveCallback(false, null, req.error + "\n " + req.text); + } + else + { + // Parse the API response + var responseBody = req.text; + Dictionary apiResponse = (Dictionary) Json.Deserialize(responseBody); + bool success = (bool) apiResponse["success"]; + if (success) + { + var segmentName = apiResponse["segment"] as string; + var segmentationName = apiResponse["analysis_name"] as string; + var c = apiResponse["segment_index"]; + string error = ""; + int segmentIndex = -1; + try + { + segmentIndex = Convert.ToInt32(c); + } + catch (Exception exception) + { + error += exception.Message; + } + onSegmentReceiveCallback(true, new ExponeaSegment(segmentName, segmentationName, segmentIndex), error); + } + else + { + onSegmentReceiveCallback(false, null, "Unsuccessful segmentation request. Response text:\n"+req.text); + } + } + } + + public void GetCurrentSegment(Dictionary customerIds, string projectSecret, string segmentaionId, Action onSegmentReceiveCallback) + { + StartCoroutine(GetCurrentSegmentCoroutine(customerIds,projectSecret,segmentaionId,onSegmentReceiveCallback)); + } } } From 1a702260f56742e5fe4c981964e5248e20ffe125 Mon Sep 17 00:00:00 2001 From: pixelshade Date: Tue, 29 Nov 2016 00:05:33 +0100 Subject: [PATCH 07/14] ExponeaSegment renamed to InfinarioSegment --- source/Assets/Scripts/InfinarioSDK/Infinario.cs | 2 +- source/Assets/Scripts/InfinarioSDK/InfinarioInterface.cs | 2 +- .../InfinarioSDK/{ExponeaSegment.cs => InfinarioSegment.cs} | 4 ++-- source/Assets/Scripts/InfinarioSDK/InfinarioUnitySDK.cs | 2 +- source/Assets/Scripts/InfinarioSDK/Sender.cs | 6 +++--- 5 files changed, 8 insertions(+), 8 deletions(-) rename source/Assets/Scripts/InfinarioSDK/{ExponeaSegment.cs => InfinarioSegment.cs} (88%) diff --git a/source/Assets/Scripts/InfinarioSDK/Infinario.cs b/source/Assets/Scripts/InfinarioSDK/Infinario.cs index 39a5210..62ea51a 100644 --- a/source/Assets/Scripts/InfinarioSDK/Infinario.cs +++ b/source/Assets/Scripts/InfinarioSDK/Infinario.cs @@ -126,7 +126,7 @@ public void SessionStatus(bool paused, Dictionary properties) } } - public void GetCurrentSegment(string projectSecret, string segmentationId, Action onSegmentReceiveCallback) + public void GetCurrentSegment(string projectSecret, string segmentationId, Action onSegmentReceiveCallback) { implementation.GetCurrentSegment(projectSecret, segmentationId, onSegmentReceiveCallback); } diff --git a/source/Assets/Scripts/InfinarioSDK/InfinarioInterface.cs b/source/Assets/Scripts/InfinarioSDK/InfinarioInterface.cs index 939e0cf..8dff0f5 100644 --- a/source/Assets/Scripts/InfinarioSDK/InfinarioInterface.cs +++ b/source/Assets/Scripts/InfinarioSDK/InfinarioInterface.cs @@ -12,6 +12,6 @@ abstract class IInfinario public abstract void TrackSessionStart (Dictionary properties); public abstract void TrackSessionEnd (Dictionary properties); public abstract void TrackVirtualPayment (string currency, long amount, string itemName, string itemType); - public abstract void GetCurrentSegment (string projectSecret, string segmentaionId, Action onSegmentReceiveCallback); + public abstract void GetCurrentSegment (string projectSecret, string segmentaionId, Action onSegmentReceiveCallback); } } \ No newline at end of file diff --git a/source/Assets/Scripts/InfinarioSDK/ExponeaSegment.cs b/source/Assets/Scripts/InfinarioSDK/InfinarioSegment.cs similarity index 88% rename from source/Assets/Scripts/InfinarioSDK/ExponeaSegment.cs rename to source/Assets/Scripts/InfinarioSDK/InfinarioSegment.cs index 84ff44d..a923986 100644 --- a/source/Assets/Scripts/InfinarioSDK/ExponeaSegment.cs +++ b/source/Assets/Scripts/InfinarioSDK/InfinarioSegment.cs @@ -5,13 +5,13 @@ namespace Infinario { - class ExponeaSegment + class InfinarioSegment { private string _name; private string _analysis_name; private int _index; - public ExponeaSegment(string name, string analysisName, int index){ + public InfinarioSegment(string name, string analysisName, int index){ this._name = name; this._analysis_name = analysisName; this._index = index; diff --git a/source/Assets/Scripts/InfinarioSDK/InfinarioUnitySDK.cs b/source/Assets/Scripts/InfinarioSDK/InfinarioUnitySDK.cs index 5e93b3e..f665d45 100644 --- a/source/Assets/Scripts/InfinarioSDK/InfinarioUnitySDK.cs +++ b/source/Assets/Scripts/InfinarioSDK/InfinarioUnitySDK.cs @@ -170,7 +170,7 @@ public override void TrackVirtualPayment(string currency, long amount, string it this.Track(Constants.EVENT_VIRTUAL_PAYMENT, properties, double.NaN); } - public override void GetCurrentSegment(string projectSecret, string segmentaionId, Action onSegmentReceiveCallback) + public override void GetCurrentSegment(string projectSecret, string segmentaionId, Action onSegmentReceiveCallback) { sender.GetCurrentSegment(customerIds, projectSecret, segmentaionId, onSegmentReceiveCallback); } diff --git a/source/Assets/Scripts/InfinarioSDK/Sender.cs b/source/Assets/Scripts/InfinarioSDK/Sender.cs index 136f42d..2b3e99b 100644 --- a/source/Assets/Scripts/InfinarioSDK/Sender.cs +++ b/source/Assets/Scripts/InfinarioSDK/Sender.cs @@ -140,7 +140,7 @@ private List ExtractRetryCommands(Dictionary response, L private IEnumerator GetCurrentSegmentCoroutine(Dictionary customerIds, string projectSecret, - string segmentationId, Action onSegmentReceiveCallback) + string segmentationId, Action onSegmentReceiveCallback) { @@ -194,7 +194,7 @@ private IEnumerator GetCurrentSegmentCoroutine(Dictionary custom { error += exception.Message; } - onSegmentReceiveCallback(true, new ExponeaSegment(segmentName, segmentationName, segmentIndex), error); + onSegmentReceiveCallback(true, new InfinarioSegment(segmentName, segmentationName, segmentIndex), error); } else { @@ -203,7 +203,7 @@ private IEnumerator GetCurrentSegmentCoroutine(Dictionary custom } } - public void GetCurrentSegment(Dictionary customerIds, string projectSecret, string segmentaionId, Action onSegmentReceiveCallback) + public void GetCurrentSegment(Dictionary customerIds, string projectSecret, string segmentaionId, Action onSegmentReceiveCallback) { StartCoroutine(GetCurrentSegmentCoroutine(customerIds,projectSecret,segmentaionId,onSegmentReceiveCallback)); } From fa237f1edb80fd67715925b88e9d6f0ec8c42733 Mon Sep 17 00:00:00 2001 From: pixelshade Date: Tue, 29 Nov 2016 00:07:20 +0100 Subject: [PATCH 08/14] Added section in readme --- README.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/README.md b/README.md index e4656bc..76bbfc1 100644 --- a/README.md +++ b/README.md @@ -110,6 +110,31 @@ infinario.Track("my_player_action", ); infinario.Track("my_player_action", , ); ``` +### Get Segment for player +To obtain players segment information form segmentations you can use method GetCurrentSegment. +You have to specify projectSecret (this is different than projectToken - you can find it in project overview). +The second parameter is segmentationId (obtained from last part of url, when creating or viewing segments). +The last one is your callback method with 3 parameters: +- boolean type specifing if retrieving of segment was successfull +- ExponeaSegment type with the our +- string information about errors that occured +``` + infinario.GetCurrentSegment(projectSecret, segmentationId, OnSegmentReceiveCallback); + + private void OnSegmentReceiveCallback(bool success, ExponeaSegment exponeaSegment, string error) + { + if (success) + { + Debug.Log(exponeaSegment); + // Do stuff according to segment type + } + else + { + Debug.LogError(error); + } + } +``` + ### Offline Behavior From 523a3545e14ddab18a2769e2d92065440c43c1b3 Mon Sep 17 00:00:00 2001 From: pixelshade Date: Tue, 29 Nov 2016 00:10:00 +0100 Subject: [PATCH 09/14] Readme - Added parentheses --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 76bbfc1..679cb3f 100644 --- a/README.md +++ b/README.md @@ -111,7 +111,7 @@ infinario.Track("my_player_action", , ); ``` ### Get Segment for player -To obtain players segment information form segmentations you can use method GetCurrentSegment. +To obtain player's segment information form segmentations you can use method GetCurrentSegment. You have to specify projectSecret (this is different than projectToken - you can find it in project overview). The second parameter is segmentationId (obtained from last part of url, when creating or viewing segments). The last one is your callback method with 3 parameters: From 3c85653b593fe33791ced1240cd402f8a71f7a01 Mon Sep 17 00:00:00 2001 From: pixelshade Date: Fri, 9 Dec 2016 11:15:44 +0100 Subject: [PATCH 10/14] readme fix - Added info about infinario segment --- README.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 679cb3f..cb8fc2f 100644 --- a/README.md +++ b/README.md @@ -116,16 +116,16 @@ You have to specify projectSecret (this is different than projectToken - you can The second parameter is segmentationId (obtained from last part of url, when creating or viewing segments). The last one is your callback method with 3 parameters: - boolean type specifing if retrieving of segment was successfull -- ExponeaSegment type with the our +- InfinarioSegment type with the our - string information about errors that occured ``` infinario.GetCurrentSegment(projectSecret, segmentationId, OnSegmentReceiveCallback); - private void OnSegmentReceiveCallback(bool success, ExponeaSegment exponeaSegment, string error) + private void OnSegmentReceiveCallback(bool success, InfinarioSegment infinarioSegment, string error) { if (success) { - Debug.Log(exponeaSegment); + Debug.Log(infinarioSegment); // Do stuff according to segment type } else @@ -134,8 +134,12 @@ The last one is your callback method with 3 parameters: } } ``` +InfinarioSegment class object returned in OnSegmentReceiveCallback contains public methods: +- GetName() returning string name of the segment where player belongs +- GetSegmentationName() returning string name of segmentation +- GetSegmentIndex() returns integer identifying the order of current segment in segmentation (starting with 0) - + ### Offline Behavior Once instantized, the SDK collects and sends all tracked events continuously to the Infinario servers. From 4e85108ae5a3aa96f5ad5248d83e68199c75ab1f Mon Sep 17 00:00:00 2001 From: pixelshade Date: Fri, 9 Dec 2016 11:20:07 +0100 Subject: [PATCH 11/14] readme - sentence fix --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cb8fc2f..200e572 100644 --- a/README.md +++ b/README.md @@ -116,7 +116,7 @@ You have to specify projectSecret (this is different than projectToken - you can The second parameter is segmentationId (obtained from last part of url, when creating or viewing segments). The last one is your callback method with 3 parameters: - boolean type specifing if retrieving of segment was successfull -- InfinarioSegment type with the our +- InfinarioSegment type with the our desired information about players segment - string information about errors that occured ``` infinario.GetCurrentSegment(projectSecret, segmentationId, OnSegmentReceiveCallback); From 006e1cf51db625ec3458734be7b43129670ec487 Mon Sep 17 00:00:00 2001 From: pixelshade Date: Fri, 9 Dec 2016 11:22:20 +0100 Subject: [PATCH 12/14] readme - highlighting --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 200e572..49837c9 100644 --- a/README.md +++ b/README.md @@ -115,9 +115,9 @@ To obtain player's segment information form segmentations you can use method Get You have to specify projectSecret (this is different than projectToken - you can find it in project overview). The second parameter is segmentationId (obtained from last part of url, when creating or viewing segments). The last one is your callback method with 3 parameters: -- boolean type specifing if retrieving of segment was successfull -- InfinarioSegment type with the our desired information about players segment -- string information about errors that occured +- `boolean` type specifing if retrieving of segment was successfull +- `InfinarioSegment` type with the our desired information about players segment +- `string` information about errors that occured ``` infinario.GetCurrentSegment(projectSecret, segmentationId, OnSegmentReceiveCallback); @@ -135,9 +135,9 @@ The last one is your callback method with 3 parameters: } ``` InfinarioSegment class object returned in OnSegmentReceiveCallback contains public methods: -- GetName() returning string name of the segment where player belongs -- GetSegmentationName() returning string name of segmentation -- GetSegmentIndex() returns integer identifying the order of current segment in segmentation (starting with 0) +- `GetName()` returning string name of the segment where player belongs +- `GetSegmentationName()` returning string name of segmentation +- `GetSegmentIndex()` returns integer identifying the order of current segment in segmentation (starting with 0) ### Offline Behavior From 7ee68b13ad7a29eadbdef1f00e61ccf40c7d665b Mon Sep 17 00:00:00 2001 From: peter-sulik Date: Thu, 10 Jan 2019 21:14:04 +0100 Subject: [PATCH 13/14] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 49837c9..8b1c5c2 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,8 @@ To start tracking, you need to know your `projectToken`. To initialize the track var infinario = Infinario.Infinario.GetInstance(); infinario.Initialize("projectToken"); -//or if you want to track app version as well -infinario.Initilize("projectToken", "1.0.0"); +//or if you want to track app version as well, third parameter is instance +infinario.Initilize("projectToken", "1.0.0", "https://api.infinario.com"); ``` Now you can track events by calling the ```Track``` method: @@ -148,4 +148,4 @@ However, if your application goes offline, the SDK guarantees you to re-send the ## Final Remarks - Make sure you create at most one instance of ```Infinario``` during your application lifetime. -- If you wish to override some of the capabilities (e.g. session management), please note that we will not be able to give you any guarantees. \ No newline at end of file +- If you wish to override some of the capabilities (e.g. session management), please note that we will not be able to give you any guarantees. From 8fdaf489e044c8a75b7b837491bac95e1585fa40 Mon Sep 17 00:00:00 2001 From: Martin Miklis Date: Tue, 26 Feb 2019 20:19:29 +0100 Subject: [PATCH 14/14] rewrite WWW to UnityWebRequest and fix RuntimePlatform --- source/Assets/Scripts/InfinarioSDK/Device.cs | 8 ++-- source/Assets/Scripts/InfinarioSDK/Sender.cs | 43 +++++++++++--------- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/source/Assets/Scripts/InfinarioSDK/Device.cs b/source/Assets/Scripts/InfinarioSDK/Device.cs index 983dfac..83db5d1 100644 --- a/source/Assets/Scripts/InfinarioSDK/Device.cs +++ b/source/Assets/Scripts/InfinarioSDK/Device.cs @@ -22,6 +22,7 @@ public static Dictionary GetProperties() private static string GetPlatform() { var platform = Application.platform; + var dict = new Dictionary { {RuntimePlatform.Android, "Android"}, {RuntimePlatform.IPhonePlayer, "iOS"}, @@ -29,14 +30,11 @@ private static string GetPlatform() {RuntimePlatform.WSAPlayerARM, "Windows Phone"}, {RuntimePlatform.WSAPlayerX64, "Windows Store"}, {RuntimePlatform.WSAPlayerX86, "Windows Store"}, - {RuntimePlatform.OSXDashboardPlayer, "Mac OS X"}, - {RuntimePlatform.OSXEditor, "Mac OS X"}, {RuntimePlatform.OSXPlayer, "Mac OS X"}, - {RuntimePlatform.OSXWebPlayer, "Mac OS X"}, + {RuntimePlatform.OSXEditor, "Mac OS X"}, {RuntimePlatform.WindowsEditor, "Unity Editor"}, {RuntimePlatform.WindowsPlayer, "Windows Standalone"}, - {RuntimePlatform.WP8Player, "Windows Phone"}, - {RuntimePlatform.WindowsWebPlayer, "Web Player"} + {RuntimePlatform.WebGLPlayer, "Web Player"} }; return (dict.ContainsKey (platform) ? dict [platform] : "Other"); } diff --git a/source/Assets/Scripts/InfinarioSDK/Sender.cs b/source/Assets/Scripts/InfinarioSDK/Sender.cs index 2b3e99b..5869126 100644 --- a/source/Assets/Scripts/InfinarioSDK/Sender.cs +++ b/source/Assets/Scripts/InfinarioSDK/Sender.cs @@ -5,6 +5,7 @@ using Infinario.MiniJSON; using System.Text; using System; +using UnityEngine.Networking; namespace Infinario.Sender { @@ -58,18 +59,19 @@ private IEnumerator APISendLoop(string target, PersistentBulkCommandQueue comman if (commands.Count > 0) { + // 1B: Prepare the http components var httpBody = Json.Serialize(new Dictionary {{"commands", commands}}); byte[] httpBodyBytes = Encoding.UTF8.GetBytes(httpBody); - Dictionary httpHeaders = new Dictionary - { - {"Content-type", "application/json"} - }; // 2. Send the bulk API request - WWW req = new WWW(httpTarget, httpBodyBytes, httpHeaders); - //TODO: we could add a timeout functionality - yield return req; + UnityWebRequest req = new UnityWebRequest(httpTarget, "POST"); + req.uploadHandler = (UploadHandler) new UploadHandlerRaw(httpBodyBytes); + req.downloadHandler = (DownloadHandler) new DownloadHandlerBuffer(); + req.SetRequestHeader("Content-Type", "application/json"); + + yield return req.SendWebRequest(); + // 3A: Check response for errors if (!string.IsNullOrEmpty(req.error)) @@ -79,7 +81,7 @@ private IEnumerator APISendLoop(string target, PersistentBulkCommandQueue comman else { // 3B. Parse the API response - var responseBody = req.text; + var responseBody = req.downloadHandler.text; Dictionary apiResponse = (Dictionary) Json.Deserialize(responseBody); bool success = (bool) apiResponse["success"]; @@ -156,27 +158,28 @@ private IEnumerator GetCurrentSegmentCoroutine(Dictionary custom }; var httpBody = Json.Serialize(body); - byte[] httpBodyBytes = Encoding.UTF8.GetBytes(httpBody); - Dictionary httpHeaders = new Dictionary - { - {"Accept", "application/json"}, - {"Content-type", "application/json"}, - {Constants.DEFAULT_SECRET, projectSecret} // this needs to be project secret not project token - }; - WWW req = new WWW(httpTarget, httpBodyBytes, httpHeaders); //TODO: we could add a timeout functionality - yield return req; + // 2. Send the bulk API request + UnityWebRequest req = new UnityWebRequest(httpTarget, "POST"); + req.uploadHandler = (UploadHandler) new UploadHandlerRaw(httpBodyBytes); + req.downloadHandler = (DownloadHandler) new DownloadHandlerBuffer(); + req.SetRequestHeader("Accept", "application/json"); + req.SetRequestHeader("Content-Type", "application/json"); + req.SetRequestHeader(Constants.DEFAULT_SECRET, projectSecret); + + yield return req.SendWebRequest(); + // Check response for errors if (!string.IsNullOrEmpty(req.error)) { - onSegmentReceiveCallback(false, null, req.error + "\n " + req.text); + onSegmentReceiveCallback(false, null, req.error + "\n " + req.downloadHandler.text); } else { // Parse the API response - var responseBody = req.text; + var responseBody = req.downloadHandler.text; Dictionary apiResponse = (Dictionary) Json.Deserialize(responseBody); bool success = (bool) apiResponse["success"]; if (success) @@ -198,7 +201,7 @@ private IEnumerator GetCurrentSegmentCoroutine(Dictionary custom } else { - onSegmentReceiveCallback(false, null, "Unsuccessful segmentation request. Response text:\n"+req.text); + onSegmentReceiveCallback(false, null, "Unsuccessful segmentation request. Response text:\n"+req.downloadHandler.text); } } }