public void _request(string endPoint, RequestData requestData)
        {
            isSending = true;

            LastRequest             = new LastRequest();
            LastRequest.EndPoint    = endPoint;
            LastRequest.RequestData = requestData;

            long tmpNonce = nonce;

            //assign general request data
            requestData.version    = Version;
            requestData.versionKey = VersionKey;
            requestData.timestamp  = PredictedServerTimestamp;

            // post
            Byte[] payload       = Encoding.UTF8.GetBytes(JsonUtility.ToJson(requestData));
            string payloadBase64 = Convert.ToBase64String(localSendInvalidRequestData?
                                                          _encryptionHelper.Encrypt_Fake(payload, nonce) :
                                                          _encryptionHelper.Encrypt(payload, nonce));
            var postForm = new RawJsonForm();

            postForm.AddField("payloadBase64", payloadBase64);
            postForm.AddField("nonce", localSendInvalidRequestData? "0":nonce.ToString());

            // signature
            Byte[] digest = md5.ComputeHash(localSendInvalidRequestData?
                                            _encryptionHelper.Encrypt_Fake(payload, nonce) :
                                            _encryptionHelper.Encrypt(payload, nonce));
            Byte[] nonceByte   = BitConverter.GetBytes(nonce);
            Byte[] signMessage = new Byte[digest.Length + nonceByte.Length];
            Array.Copy(nonceByte, signMessage, nonceByte.Length);
            if (!localSendInvalidSignBase64)
            {
                Array.Copy(digest, 0, signMessage, nonceByte.Length, digest.Length);
            }
            string signedBase64 = Convert.ToBase64String(_encryptionHelper.SignMessage(signMessage));

            // query
            Dictionary <string, string> queryDict = new Dictionary <string, string>();

            queryDict.Add("signedBase64", signedBase64);
            queryDict.Add("token", token);
            queryDict.Add("remoteTimeout", remoteTimeout? "true" : "false");
            queryDict.Add("remoteSendInvalidPayload", remoteSendInvalidPayload? "true" : "false");
            var query = getQuery(queryDict);

            // send request
            var url = $"{Host}" + endPoint + $"?{query}";

            SetTimer(Timeout);
            RespondData = new RespondData();
            HTTPRequest request = new HTTPRequest(new Uri(url), HTTPMethods.Post, (originalRequest, response) =>
            {
                if (response.Data.Length == 10)
                {
                    RespondData.errorCode = RespondData.errorCode == 0? ErrorCode.FailedToDecryptServerPayload : RespondData.errorCode;
                }
                else if (response.HasHeaderWithValue("Content-Encoding", "encrypted"))
                {
                    var decrypted = _encryptionHelper.Decrypt(response.Data, tmpNonce);
                    RespondData   = JsonUtility.FromJson <RespondData>(Encoding.UTF8.GetString(Decompress(decrypted)));
                }
                else
                {
                    RespondData = JsonUtility.FromJson <RespondData>(response.DataAsText);
                }

                //assign user
                user.userId   = RespondData.user.userId == 0 ? user.userId : RespondData.user.userId;
                user.deviceId = RespondData.user.deviceId == null ? user.deviceId : RespondData.user.deviceId;
                user.session  = RespondData.user.session == null ? user.session : RespondData.user.session;

                //assign other server return value
                cards             = RespondData.body.cards == null ? cards : RespondData.body.cards;
                card              = RespondData.body.card;
                serverTimestamp   = RespondData.timestamp;
                receivedTimestamp = CurrentTimestamp;
                token             = RespondData.token == null ? token : RespondData.token;

                isSending = false;
            });

            request.SetForm(postForm);
            request.Send();

            nonce++;
        }
        public void _request(string endPoint, RequestData requestData)
        {
            RespondData      respondData      = new RespondData();
            EncryptionHelper encryptionHelper = new EncryptionHelper();

            {
                requestData.version    = Version;
                requestData.versionKey = VersionKey;
                requestData.timestamp  = CurrentTimestamp;
                requestData.session    = user.session;
                requestData.cacheKey   = requestData.cacheKey;
                requestData.cardId     = requestData.cardId;
                requestData.monsterId  = requestData.monsterId;
                requestData.exp        = requestData.exp;


                //login use only
                requestData.deviceId = DeviceId;
            }

            Byte[] payload       = JsonUtility.ToJson(requestData).GetASCIIBytes();
            byte[] encryptData   = encryptionHelper.Encrypt(payload, nonce, localSendInvalidRequestData);
            string payloadBase64 = Convert.ToBase64String(encryptData);
            var    postForm      = new RawJsonForm();

            postForm.AddField("payloadBase64", payloadBase64);

            // signature
            MD5 md5 = System.Security.Cryptography.MD5.Create();

            Byte[] digest       = md5.ComputeHash(encryptionHelper.Encrypt(payload, nonce, localSendInvalidRequestData)); //new Byte[100]; // md5(payload);
            Byte[] nonceByte    = BitConverter.GetBytes(nonce);                                                           //new Byte[8]; // nonce to byte
            Byte[] signMessage  = nonceByte.Concat(digest).ToArray();                                                     // nonceByte + digest
            string signedBase64 = Convert.ToBase64String(encryptionHelper.SignMessage(signMessage));

            if (localSendInvalidSignBase64)
            {
                signedBase64 = ":asdfjhasldkj" + signedBase64;
            }
            // query
            string tokenStr = "";

            if (string.IsNullOrEmpty(this.token))
            {
                this.token = "";
            }
            Dictionary <string, string> queryDict = new Dictionary <string, string>();

            queryDict.Add("signedBase64", signedBase64);
            queryDict.Add("token", this.token);
            queryDict.Add("remoteTimeout", this.remoteTimeout.ToString());
            queryDict.Add("remoteSendInvalidPayload", remoteSendInvalidPayload.ToString());
            var query = this.getQuery(queryDict);


            // send request
            var         url     = $"{_host}{endPoint}?{query}";
            HTTPRequest request = new HTTPRequest(new Uri(url), HTTPMethods.Post, (originalRequest, response) =>
            {
                bool contentEncrypted = false;
                switch (originalRequest.State)
                {
                case HTTPRequestStates.ConnectionTimedOut:
                case HTTPRequestStates.TimedOut:
                    this.RespondData.errorCode = ErrorCode.Timeout;
                    break;

                default:
                    if (response.Headers.ContainsKey("content-encoding"))
                    {
                        List <string> tmpOutput = response.Headers["content-encoding"];
                        if (tmpOutput.Contains("encrypted"))
                        {
                            contentEncrypted = true;
                        }
                    }
                    if (contentEncrypted)
                    {
                        try
                        {
                            var compressedStream = new MemoryStream(encryptionHelper.Decrypt(response.Data, nonce));
                            var zipStream        = new GZipStream(compressedStream, CompressionMode.Decompress);
                            var resultStream     = new MemoryStream();
                            zipStream.CopyTo(resultStream);
                            string outputString    = Encoding.UTF8.GetString(resultStream.ToArray());
                            respondData            = JsonUtility.FromJson <RespondData>(outputString);
                            this.receivedTimestamp = respondData.timestamp;

                            if ((this.CurrentTimestamp - this.serverTimestamp) > 3600 &&
                                !originalRequest.Uri.ToString().Contains("/login"))
                            {
                                this.RespondData.errorCode = ErrorCode.InvalidTimestamp;
                            }
                            else
                            {
                                this.RespondData = respondData;
                                if (!string.IsNullOrEmpty(respondData.token))
                                {
                                    this.token = respondData.token;
                                }

                                this.user            = respondData.user;
                                this.card            = respondData.body.card;
                                this.cards           = respondData.body.cards;
                                this.serverTimestamp = respondData.timestamp;
                            }
                        }
                        catch (Exception exception)
                        {
                            this.RespondData.errorCode = ErrorCode.FailedToDecryptServerPayload;
                            isSending = false;
                        }
                    }
                    else
                    {
                        try
                        {
                            string outputString        = Encoding.UTF8.GetString(response.Data);
                            respondData                = JsonUtility.FromJson <RespondData>(outputString);
                            this.RespondData.errorCode = respondData.errorCode;
                            isSending = false;
                        }
                        catch (Exception exception)
                        {
                            this.RespondData.errorCode = ErrorCode.FailedToDecryptServerPayload;
                            isSending = false;
                        }
                    }
                    break;
                }

                isSending = false;
            });

            request.SetForm(postForm);
            request.Timeout = new TimeSpan(0, 0, 0, this.Timeout);
            request.Send();


            LastRequest             = new LastRequest();
            LastRequest.EndPoint    = endPoint;
            LastRequest.RequestData = requestData;
        }