Beispiel #1
0
        /// <summary>
        /// Handles the response bundle and calls registered callbacks.
        /// </summary>
        /// <param name="in_jsonData">The received message bundle.</param>
        private void HandleResponseBundle(string in_jsonData)
        {
            m_brainCloudClientRef.Log("INCOMING: " + in_jsonData);

            JsonResponseBundleV2 bundleObj = JsonReader.Deserialize <JsonResponseBundleV2>(in_jsonData);
            long receivedPacketId          = (long)bundleObj.packetId;

            if (m_expectedIncomingPacketId == NO_PACKET_EXPECTED || m_expectedIncomingPacketId != receivedPacketId)
            {
                m_brainCloudClientRef.Log("Dropping duplicate packet");
                return;
            }
            m_expectedIncomingPacketId = NO_PACKET_EXPECTED;

            Dictionary <string, object>[] responseBundle = bundleObj.responses;
            Dictionary <string, object>   response       = null;
            Exception firstThrownException = null;
            int       numExceptionsThrown  = 0;

            for (int j = 0; j < responseBundle.Length; ++j)
            {
                response = responseBundle[j];
                int    statusCode = (int)response["status"];
                string data       = "";

                //
                // It's important to note here that a user error callback *might* call
                // ResetCommunications() based on the error being returned.
                // ResetCommunications will clear the m_serviceCallsInProgress List
                // effectively removing all registered callbacks for this message bundle.
                // It's also likely that the developer will want to call authenticate next.
                // We need to ensure that this is supported as it's the best way to
                // reset the brainCloud communications after a session invalid or network
                // error is triggered.
                //
                // This is safe to do from the main thread but just in case someone
                // calls this method from another thread, we lock on m_serviceCallsWaiting
                //
                ServerCall sc = null;
                lock (m_serviceCallsWaiting)
                {
                    if (m_serviceCallsInProgress.Count > 0)
                    {
                        sc = m_serviceCallsInProgress[0] as ServerCall;
                        m_serviceCallsInProgress.RemoveAt(0);
                    }
                }

                // its a success response
                if (statusCode == 200)
                {
                    if (response[OperationParam.ServiceMessageData.Value] != null)
                    {
                        Dictionary <string, object> responseData = (Dictionary <string, object>)response[OperationParam.ServiceMessageData.Value];

                        // send the data back as not formatted
                        data = JsonWriter.Serialize(response);

                        // save the session ID
                        try
                        {
                            if (getJsonString(responseData, OperationParam.ServiceMessageSessionId.Value, null) != null)
                            {
                                m_sessionID       = (string)responseData[OperationParam.ServiceMessageSessionId.Value];
                                m_isAuthenticated = true;  // TODO confirm authentication
                            }

                            // save the profile ID
                            if (getJsonString(responseData, OperationParam.ServiceMessageProfileId.Value, null) != null)
                            {
                                m_brainCloudClientRef.AuthenticationService.ProfileId = (string)responseData[OperationParam.ServiceMessageProfileId.Value];
                            }
                        }
                        catch (Exception e)
                        {
                            m_brainCloudClientRef.Log("SessionId or ProfileId do not exist " + e.ToString());
                        }
                    }

                    // now try to execute the callback
                    if (sc != null)
                    {
                        if (sc.GetService().Equals(ServiceName.PlayerState.Value) &&
                            (sc.GetOperation().Equals(ServiceOperation.FullReset.Value) ||
                             sc.GetOperation().Equals(ServiceOperation.Reset.Value) ||
                             sc.GetOperation().Equals(ServiceOperation.Logout.Value)))

                        {
                            // we reset the current player or logged out
                            // we are no longer authenticated
                            m_isAuthenticated = false;
                            m_brainCloudClientRef.AuthenticationService.ProfileId = null;
                        }
                        else if (sc.GetService().Equals(ServiceName.Authenticate.Value) &&
                                 sc.GetOperation().Equals(ServiceOperation.Authenticate.Value))
                        {
                            ProcessAuthenticate(data);
                        }

                        // // only process callbacks that are real
                        if (sc.GetCallback() != null)
                        {
                            try
                            {
                                sc.GetCallback().OnSuccessCallback(data);
                            }
                            catch (Exception e)
                            {
                                m_brainCloudClientRef.Log(e.StackTrace);
                                ++numExceptionsThrown;
                                if (firstThrownException == null)
                                {
                                    firstThrownException = e;
                                }
                            }
                        }
                    }
                }
                else if (statusCode >= 400 || statusCode == 202)
                {
                    object reasonCodeObj = null, statusMessageObj = null;
                    int    reasonCode    = 0;
                    string statusMessage = "";

                    if (response.TryGetValue("reason_code", out reasonCodeObj))
                    {
                        reasonCode = (int)reasonCodeObj;
                    }
                    if (response.TryGetValue("status_message", out statusMessageObj))
                    {
                        statusMessage = (string)statusMessageObj;
                    }

                    if (reasonCode == ReasonCodes.SESSION_EXPIRED ||
                        reasonCode == ReasonCodes.SESSION_NOT_FOUND_ERROR)
                    {
                        m_isAuthenticated = false;
                        m_brainCloudClientRef.Log("Received session expired or not found, need to re-authenticate");
                    }

                    // now try to execute the callback
                    if (sc != null && sc.GetCallback() != null)
                    {
                        try
                        {
                            sc.GetCallback().OnErrorCallback(statusCode, reasonCode, statusMessage);
                        }
                        catch (Exception e)
                        {
                            m_brainCloudClientRef.Log(e.StackTrace);
                            ++numExceptionsThrown;
                            if (firstThrownException == null)
                            {
                                firstThrownException = e;
                            }
                        }
                    }
                }
            }

            if (firstThrownException != null)
            {
                m_activeRequest = null; // to make sure we don't reprocess this message

                throw new Exception("User callback handlers threw " + numExceptionsThrown + " exception(s)."
                                    + " See the Unity log for callstacks or inner exception for first exception thrown.",
                                    firstThrownException);
            }
        }
Beispiel #2
0
        /// <summary>
        /// The update method needs to be called periodically to send/receive responses
        /// and run the associated callbacks.
        /// </summary>
        public void Update()
        {
            // basic flow here is to:
            // 1- process existing requests
            // 2- send next request
            // 3- handle heartbeat/timeouts

            if (!m_initialized)
            {
                return;
            }
            if (!m_enabled)
            {
                return;
            }

            // process current request
            if (m_activeRequest != null)
            {
                eWebRequestStatus status = GetWebRequestStatus(m_activeRequest);
                if (status == eWebRequestStatus.STATUS_ERROR)
                {
                    // do nothing with the error right now - let the timeout code handle it
                }
                else if (status == eWebRequestStatus.STATUS_DONE)
                {
                    ResetIdleTimer();

                    // note that active request is set to null if exception is to be thrown
                    HandleResponseBundle(GetWebRequestResponse(m_activeRequest));

                    m_activeRequest = null;
                }
            }

            // send the next message if we're ready
            if (m_activeRequest == null)
            {
                m_activeRequest = CreateAndSendNextRequestBundle();
            }

            // is it time for a retry?
            if (m_activeRequest != null)
            {
                if (DateTime.Now.Subtract(m_activeRequest.TimeSent) >= GetPacketTimeout(m_activeRequest.Retries))
                {
                    if (!ResendMessage(m_activeRequest))
                    {
                        // we've reached the retry limit - send timeout error to all client callbacks

                        eWebRequestStatus status = GetWebRequestStatus(m_activeRequest);
                        if (status == eWebRequestStatus.STATUS_ERROR)
                        {
                            m_brainCloudClientRef.Log("Timeout with network error: " + GetWebRequestResponse(m_activeRequest));
                        }
                        else
                        {
                            m_brainCloudClientRef.Log("Timeout no reply from server");
                        }

                        m_activeRequest = null;

                        // Fake a message bundle to keep the callback logic in one place
                        TriggerCommsError(StatusCodes.CLIENT_NETWORK_ERROR, ReasonCodes.CLIENT_NETWORK_ERROR_TIMEOUT, "Timeout trying to reach brainCloud server");
                    }
                }
            }

            // is it time for a heartbeat?
            if (Authenticated)
            {
                if (DateTime.Now.Subtract(m_lastTimePacketSent) >= m_idleTimeout)
                {
                    SendHeartbeat();
                }
            }
        }
Beispiel #3
0
        /// <summary>
        /// Creates the request state object and sends the message bundle
        /// </summary>
        /// <returns>The and send next request bundle.</returns>
        private RequestState CreateAndSendNextRequestBundle()
        {
            RequestState requestState = null;

            lock (m_serviceCallsWaiting)
            {
                if (m_serviceCallsWaiting.Count > 0)
                {
                    int numMessagesWaiting = m_serviceCallsWaiting.Count;
                    if (numMessagesWaiting > MAX_MESSAGES_IN_BUNDLE)
                    {
                        numMessagesWaiting = MAX_MESSAGES_IN_BUNDLE;
                    }

                    if (m_serviceCallsInProgress.Count > 0)
                    {
                        // this should never happen
                        m_brainCloudClientRef.Log("ERROR - in progress queue is not empty but we're ready for the next message!");
                        m_serviceCallsInProgress.Clear();
                    }

                    m_serviceCallsInProgress = m_serviceCallsWaiting.GetRange(0, numMessagesWaiting);
                    m_serviceCallsWaiting.RemoveRange(0, numMessagesWaiting);
                }

                if (m_serviceCallsInProgress.Count > 0)
                {
                    requestState = new RequestState();

                    // prepare json data for server
                    List <object> messageList = new List <object>();

                    ServerCall scIndex;
                    for (int i = 0; i < m_serviceCallsInProgress.Count; ++i)
                    {
                        scIndex = m_serviceCallsInProgress[i] as ServerCall;

                        Dictionary <string, object> message = new Dictionary <string, object>();
                        message[OperationParam.ServiceMessageService.Value]   = scIndex.Service;
                        message[OperationParam.ServiceMessageOperation.Value] = scIndex.Operation;
                        message[OperationParam.ServiceMessageData.Value]      = scIndex.GetJsonData();

                        messageList.Add(message);

                        if (scIndex.GetOperation().Equals(ServiceOperation.Authenticate.Value))
                        {
                            requestState.PacketNoRetry = true;
                        }

                        if (scIndex.GetOperation().Equals(ServiceOperation.FullReset.Value) ||
                            scIndex.GetOperation().Equals(ServiceOperation.Logout.Value))
                        {
                            requestState.PacketRequiresLongTimeout = true;
                        }
                    }

                    SendMessage(requestState, messageList);
                }
            } // unlock m_serviceCallsWaiting

            return(requestState);
        }
Beispiel #4
0
        /// <summary>
        /// Method staggers the packet timeout value based on the currentRetry
        /// </summary>
        /// <returns>The packet timeout.</returns>
        /// <param name="currentRetryNumber">Current retry number.</param>
        private TimeSpan GetPacketTimeout(RequestState in_requestState)
        {
            int      currentRetry = in_requestState.Retries;
            TimeSpan ret;

            // if this is a delete player or logout we change the
            // timeout behaviour
            if (in_requestState.IsSessionTerminatingPacket)
            {
                switch (currentRetry)
                {
                case 0:
                    ret = TimeSpan.FromSeconds(15);
                    break;

                case 1:
                    ret = TimeSpan.FromSeconds(15);
                    break;

                case 2:
                    ret = TimeSpan.FromSeconds(2);
                    break;

                case 3:
                    ret = TimeSpan.FromSeconds(2);
                    break;

                case 4:
                default:
                    ret = TimeSpan.FromSeconds(1);
                    break;
                }
            }
            else
            {
                switch (currentRetry)
                {
                case 0:
                    ret = TimeSpan.FromSeconds(3);
                    break;

                case 1:
                    ret = TimeSpan.FromSeconds(5);
                    break;

                case 2:
                    ret = TimeSpan.FromSeconds(5);
                    break;

                case 3:
                    ret = TimeSpan.FromSeconds(10);
                    break;

                case 4:
                default:
                    ret = TimeSpan.FromSeconds(10);
                    break;
                }
            }

            return(ret);
        }
Beispiel #5
0
        /// <summary>
        /// Handles the response bundle and calls registered callbacks.
        /// </summary>
        /// <param name="in_jsonData">The received message bundle.</param>
        private void HandleResponseBundle(string in_jsonData)
        {
            m_brainCloudClientRef.Log("INCOMING: " + in_jsonData);

            JsonResponseBundleV2 bundleObj = JsonReader.Deserialize <JsonResponseBundleV2>(in_jsonData);
            long receivedPacketId          = (long)bundleObj.packetId;

            if (m_expectedIncomingPacketId == NO_PACKET_EXPECTED || m_expectedIncomingPacketId != receivedPacketId)
            {
                m_brainCloudClientRef.Log("Dropping duplicate packet");
                return;
            }
            m_expectedIncomingPacketId = NO_PACKET_EXPECTED;

            Dictionary <string, object>[] responseBundle = bundleObj.responses;
            Dictionary <string, object>   response       = null;
            IList <Exception>             exceptions     = new List <Exception>();

            for (int j = 0; j < responseBundle.Length; ++j)
            {
                response = responseBundle[j];
                int    statusCode = (int)response["status"];
                string data       = "";

                //
                // It's important to note here that a user error callback *might* call
                // ResetCommunications() based on the error being returned.
                // ResetCommunications will clear the m_serviceCallsInProgress List
                // effectively removing all registered callbacks for this message bundle.
                // It's also likely that the developer will want to call authenticate next.
                // We need to ensure that this is supported as it's the best way to
                // reset the brainCloud communications after a session invalid or network
                // error is triggered.
                //
                // This is safe to do from the main thread but just in case someone
                // calls this method from another thread, we lock on m_serviceCallsWaiting
                //
                ServerCall sc = null;
                lock (m_serviceCallsWaiting)
                {
                    if (m_serviceCallsInProgress.Count > 0)
                    {
                        sc = m_serviceCallsInProgress[0] as ServerCall;
                        m_serviceCallsInProgress.RemoveAt(0);
                    }
                }

                // its a success response
                if (statusCode == 200)
                {
                    Dictionary <string, object> responseData = null;
                    if (response[OperationParam.ServiceMessageData.Value] != null)
                    {
                        responseData = (Dictionary <string, object>)response[OperationParam.ServiceMessageData.Value];

                        // send the data back as not formatted
                        data = JsonWriter.Serialize(response);

                        // save the session ID
                        try
                        {
                            if (getJsonString(responseData, OperationParam.ServiceMessageSessionId.Value, null) != null)
                            {
                                m_sessionID       = (string)responseData[OperationParam.ServiceMessageSessionId.Value];
                                m_isAuthenticated = true;  // TODO confirm authentication
                            }

                            // save the profile ID
                            if (getJsonString(responseData, OperationParam.ServiceMessageProfileId.Value, null) != null)
                            {
                                m_brainCloudClientRef.AuthenticationService.ProfileId = (string)responseData[OperationParam.ServiceMessageProfileId.Value];
                            }
                        }
                        catch (Exception e)
                        {
                            m_brainCloudClientRef.Log("SessionId or ProfileId do not exist " + e.ToString());
                        }
                    }

                    // now try to execute the callback
                    if (sc != null)
                    {
                        if (sc.GetService().Equals(ServiceName.PlayerState.Value) &&
                            (sc.GetOperation().Equals(ServiceOperation.FullReset.Value) ||
                             sc.GetOperation().Equals(ServiceOperation.Logout.Value)))
                        {
                            // we reset the current player or logged out
                            // we are no longer authenticated
                            m_isAuthenticated = false;
                            m_brainCloudClientRef.AuthenticationService.ClearSavedProfileID();
                        }
                        else if (sc.GetService().Equals(ServiceName.Authenticate.Value) &&
                                 sc.GetOperation().Equals(ServiceOperation.Authenticate.Value))
                        {
                            ProcessAuthenticate(data);
                        }

                        // // only process callbacks that are real
                        if (sc.GetCallback() != null)
                        {
                            try
                            {
                                sc.GetCallback().OnSuccessCallback(data);
                            }
                            catch (Exception e)
                            {
                                m_brainCloudClientRef.Log(e.StackTrace);
                                exceptions.Add(e);
                            }
                        }

                        // now deal with rewards
                        if (m_rewardCallback != null && responseData != null)
                        {
                            try
                            {
                                Dictionary <string, object> rewards = null;

                                // it's an operation that return a reward
                                if (sc.GetService().Equals(ServiceName.Authenticate.Value) &&
                                    sc.GetOperation().Equals(ServiceOperation.Authenticate.Value))
                                {
                                    object objRewards = null;
                                    if (responseData.TryGetValue("rewards", out objRewards))
                                    {
                                        Dictionary <string, object> outerRewards = (Dictionary <string, object>)objRewards;
                                        if (outerRewards.TryGetValue("rewards", out objRewards))
                                        {
                                            Dictionary <string, object> innerRewards = (Dictionary <string, object>)objRewards;
                                            if (innerRewards.Count > 0)
                                            {
                                                // we found rewards
                                                rewards = outerRewards;
                                            }
                                        }
                                    }
                                }
                                else if ((sc.GetService().Equals(ServiceName.PlayerStatistics.Value) &&
                                          sc.GetOperation().Equals(ServiceOperation.Update.Value)) ||
                                         (sc.GetService().Equals(ServiceName.PlayerStatisticsEvent.Value) &&
                                          (sc.GetOperation().Equals(ServiceOperation.Trigger.Value) ||
                                           sc.GetOperation().Equals(ServiceOperation.TriggerMultiple.Value))))
                                {
                                    object objRewards = null;
                                    if (responseData.TryGetValue("rewards", out objRewards))
                                    {
                                        Dictionary <string, object> innerRewards = (Dictionary <string, object>)objRewards;
                                        if (innerRewards.Count > 0)
                                        {
                                            // we found rewards
                                            rewards = responseData;
                                        }
                                    }
                                }

                                if (rewards != null)
                                {
                                    Dictionary <string, object> theReward = new Dictionary <string, object>();
                                    theReward["rewards"]   = rewards;
                                    theReward["service"]   = sc.GetService();
                                    theReward["operation"] = sc.GetOperation();
                                    Dictionary <string, object> apiRewards = new Dictionary <string, object>();
                                    List <object> rewardList = new List <object>();
                                    rewardList.Add(theReward);
                                    apiRewards["apiRewards"] = rewardList;

                                    string rewardsAsJson = JsonWriter.Serialize(apiRewards);
                                    m_rewardCallback(rewardsAsJson);
                                }
                            }
                            catch (Exception e)
                            {
                                m_brainCloudClientRef.Log(e.StackTrace);
                                exceptions.Add(e);
                            }
                        }
                    }
                }
                else if (statusCode >= 400 || statusCode == 202)
                {
                    object reasonCodeObj = null, statusMessageObj = null;
                    int    reasonCode = 0;
                    string errorJson  = "";

                    if (response.TryGetValue("reason_code", out reasonCodeObj))
                    {
                        reasonCode = (int)reasonCodeObj;
                    }
                    if (m_oldStyleStatusResponseInErrorCallback)
                    {
                        if (response.TryGetValue("status_message", out statusMessageObj))
                        {
                            errorJson = (string)statusMessageObj;
                        }
                    }
                    else
                    {
                        errorJson = JsonWriter.Serialize(response);
                    }

                    if (reasonCode == ReasonCodes.PLAYER_SESSION_EXPIRED ||
                        reasonCode == ReasonCodes.NO_SESSION)
                    {
                        m_isAuthenticated = false;
                        m_brainCloudClientRef.Log("Received session expired or not found, need to re-authenticate");
                    }

                    if (sc != null && sc.GetOperation().Equals(ServiceOperation.Logout.Value))
                    {
                        if (reasonCode == ReasonCodes.CLIENT_NETWORK_ERROR_TIMEOUT)
                        {
                            m_isAuthenticated = false;
                            m_brainCloudClientRef.Log("Could not communicate with the server on logout due to network timeout");
                        }
                    }

                    // now try to execute the callback
                    if (sc != null && sc.GetCallback() != null)
                    {
                        try
                        {
                            sc.GetCallback().OnErrorCallback(statusCode, reasonCode, errorJson);
                        }
                        catch (Exception e)
                        {
                            m_brainCloudClientRef.Log(e.StackTrace);
                            exceptions.Add(e);
                        }
                    }
                }
            }

            if (bundleObj.events != null && m_eventCallback != null)
            {
                Dictionary <string, Dictionary <string, object>[]> eventsJsonObj = new Dictionary <string, Dictionary <string, object>[]>();
                eventsJsonObj["events"] = bundleObj.events;
                string eventsAsJson = JsonWriter.Serialize(eventsJsonObj);
                try
                {
                    m_eventCallback(eventsAsJson);
                }
                catch (Exception e)
                {
                    m_brainCloudClientRef.Log(e.StackTrace);
                    exceptions.Add(e);
                }
            }

            if (exceptions.Count > 0)
            {
                m_activeRequest = null; // to make sure we don't reprocess this message

                throw new Exception("User callback handlers threw " + exceptions.Count + " exception(s)."
                                    + " See the Unity log for callstacks or inner exception for first exception thrown.",
                                    exceptions[0]);
            }
        }