/// <summary> Get the calibration time from the server. </summary> IEnumerator GetCalibrationTimeFromServer(string apiToken) { // Add slash in the end if needed if (CoolaDataTracker.endpointUrl[CoolaDataTracker.endpointUrl.Length - 1] != '/') { CoolaDataTracker.endpointUrl += '/'; } string finalAddress = CoolaDataTracker.endpointUrl + "egw/2/" + apiToken + "/config"; WWW w = new WWW(finalAddress); // Wait for response while (!w.isDone) { yield return(new WaitForSeconds(0.1f)); } // Check timeout if (!w.isDone) { Debug.Log("GetCalibrationTimeFromServer 408 (timeout)."); w.Dispose(); yield break; } if (!String.IsNullOrEmpty(w.error)) { Exception e = new Exception(w.error); Debug.Log("Error in the connection for " + finalAddress + ": " + e); yield break; } else { JSONObject responseDictionary = JSONObject.Parse(w.text); // Get the configuration JSONObject configurationJSON = responseDictionary.GetObject("configuration"); if (configurationJSON != null) { // Get the calibration time calibrationTimeMS = configurationJSON.GetNumber("calibrationTimestampMillis"); if (CoolaDataTracker.getInstance().operationComplete != null) { CoolaDataTracker.getInstance().operationComplete("Calibration time: " + calibrationTimeMS); } } else { if (CoolaDataTracker.getInstance().operationComplete != null) { CoolaDataTracker.getInstance().operationComplete("Can not find 'calibrationTimestampMillis' parameter"); } } } }
/// <summary> Tries to send the first bacth from batch queue to the server </summary> /// NOTE: should only be called from ManageBatchSending or BatchSendCallbackDelegate to prevent multiple competing calls that break the backoff interval times IEnumerator TrySendBacthFromQueue(int attemptsMadeSoFar) { // Make sure we comply with publishing backoff interval float publishBackoffInterval = float.Parse(defaults["eventsPublishBackoffIntervalMillis"]) / 1000f; if (lastBatchSendingCompletedTime < publishBackoffInterval) { yield return(publishBackoffInterval - lastBatchSendingCompletedTime); } // get batch and turn it into usable post data var batch = batchQueue.GetFirstBatch(); if (batch == null) { yield break; } // create the post data we need to send to the server string postDataString = ""; foreach (TrackEventParamaters item in batch) { postDataString += item.ToString(); postDataString += "\n,"; } postDataString = postDataString.Remove(postDataString.Length - 2); // removes the last NEWLINE and ',' we added string postDataStrNotEnc = "{\"events\":[" + postDataString + "]}"; string postDataStrEnc = WWW.EscapeURL(postDataStrNotEnc); string finalPostDataStr = "data=" + postDataStrEnc; byte[] postData = System.Text.Encoding.ASCII.GetBytes(finalPostDataStr); // System.Text.Encoding.UTF8.GetBytes(postDataString) // mark when we started the attempt so we can calculate how long we need to wait before a retry batchSendStartTime = Time.realtimeSinceStartup; if (CoolaDataTracker.getInstance().operationComplete != null) { CoolaDataTracker.getInstance().operationComplete("Trying to send " + batch.Count + " events to server"); } // try to send batch Send(string.Format("v1/{0}/track?r={1}", apiToken, UnityEngine.Random.Range(0, int.MaxValue)), postData , delegate(string arg1, Exception arg2) { StartCoroutine(BatchSendCallbackDelegate(arg1, arg2, attemptsMadeSoFar)); }, false, true); yield break; }
/// <summary> Add the specified eventName, userId, eventProperties, eventId and callback to the Queue </summary> /// <param name="eventName">Event name.</param> /// <param name="userID">User identifier.</param> /// <param name="eventProperties">Event properties.</param> /// <param name="eventId">Event identifier.</param> /// <param name="callback">Callback.</param> public void Add(string eventName, string userId, Dictionary <string, JSONValue> eventProperties, string eventId, Action <CoolaDataDeliveryResult> callback) { if (!AreArgumentsOkay(eventName, userId, eventProperties, eventId, callback)) { return; } CoolaDataTracker.TrackEventParamaters queuedItem = new CoolaDataTracker.TrackEventParamaters(eventName, userId, eventProperties, eventId, callback); if (string.IsNullOrEmpty(eventId) && callback == null) { items.Add(queuedItem); } else { callbackItems.Add(queuedItem); } ShrinkQueueDownToSize(); if (CoolaDataTracker.getInstance().operationComplete != null) { CoolaDataTracker.getInstance().operationComplete("Queue size: " + Count); } CheckIfQueueTriggeredBySize(); }
/// <summary> The callback for the batch we tried to send </summary> IEnumerator BatchSendCallbackDelegate(string response, Exception e, int attemptsMadeSoFar) { // note when we finished sending a batch so we can calculate how long to wait before trying to automatically publish again lastBatchSendingCompletedTime = Time.realtimeSinceStartup; // update number of attempts made attemptsMadeSoFar++; // check for errors and handle accordingly if (e != null) { // handel the error by type if (e.Message.StartsWith("403")) // "403" error code means the api token is incorrect { Debug.Log("BatchSendCallbackDelegate failed. 403"); setupState = SetupState.NotCalled; alreadyTryingToSendBatch = false; yield break; } // on all other error codes we reattempt to send unless limit reached else { Debug.Log("BatchSendCallbackDelegate failed. " + e.Message); // check if we have reached the retry limit if (attemptsMadeSoFar >= int.Parse(defaults["maxTotalRequestRetries"])) { // Let all callbacks in batch know that attempt failed and what error codes we got foreach (var item in batchQueue.GetFirstBatch()) { if ((!string.IsNullOrEmpty(item.eventId)) && item.callback != null) { // set the proper error paramaters to each CoolaData delivery result we need to return to each callback CoolaDataDeliveryResult coolaDataDeliveryResult = new CoolaDataDeliveryResult(); coolaDataDeliveryResult.eventId = item.eventId; coolaDataDeliveryResult.status = false; int indexOfFirstSpace = e.Message.IndexOf(" "); coolaDataDeliveryResult.deliveryStatusCode = int.Parse(e.Message.Substring(0, indexOfFirstSpace)); coolaDataDeliveryResult.deliveryStatusDescription = e.Message.Substring(indexOfFirstSpace + 1, e.Message.Length - indexOfFirstSpace - 1); // call the callback with the CoolaData delivery result item.callback(coolaDataDeliveryResult); } } // remove the first batch, and let the batch manager try again batchQueue.RemoveFirstBatch(); alreadyTryingToSendBatch = false; ManageBatchSending(); yield break; } // comply with failed attempt backoff interval float backoffTimeBeforeReattempt = float.Parse(defaults["eventsOutageBackoffIntervalMillis"]) / 1000f; if (Time.realtimeSinceStartup - batchSendStartTime < backoffTimeBeforeReattempt) { yield return(new WaitForSeconds(backoffTimeBeforeReattempt - Time.realtimeSinceStartup + batchSendStartTime)); } // try to send the batch again StartCoroutine(TrySendBacthFromQueue(attemptsMadeSoFar)); yield break; } } else { if (CoolaDataTracker.getInstance().operationComplete != null) { CoolaDataTracker.getInstance().operationComplete(response); } Debug.Log("BatchSendCallbackDelegate soccess. response: " + response); } // send was sucessful // collect all callback trackEvents we have Dictionary <string, Action <CoolaDataDeliveryResult> > callbacks = new Dictionary <string, Action <CoolaDataDeliveryResult> >(); foreach (var item in batchQueue.GetFirstBatch()) { if ((!string.IsNullOrEmpty(item.eventId)) && item.callback != null) { callbacks.Add(item.eventId, item.callback); } } // parse response into usable format JSONObject responseDictionary = JSONObject.Parse(response); // give the callbacks their answers foreach (var result in responseDictionary.GetObject("results")) { // Extract the specific CoolaData delivery result from the server response CoolaDataDeliveryResult coolaDataDeliveryResult = new CoolaDataDeliveryResult(); coolaDataDeliveryResult.eventId = result.Key; coolaDataDeliveryResult.status = responseDictionary.GetBoolean("status"); coolaDataDeliveryResult.deliveryStatusCode = 200; // succeffuly communication with server coolaDataDeliveryResult.deliveryStatusDescription = null; // The description of the status state. e.g. “Failed to send event due to network issues” coolaDataDeliveryResult.responseProperties = new Dictionary <string, string>(); foreach (var pair in result.Value.Obj) { coolaDataDeliveryResult.responseProperties.Add(pair.Key, pair.Value.ToString()); } // call the appropriate callback eith the Cooladata deliviery result callbacks[result.Key](coolaDataDeliveryResult); } // remove first batch which we have sucessfully sent batchQueue.RemoveFirstBatch(); // unlock batch sending alreadyTryingToSendBatch = false; }