/// <summary>
 /// Send an Object
 /// </summary>
 /// <typeparam name="T">Object type</typeparam>
 /// <param name="obj">Object</param>
 /// <param name="callback">Post-Send callback</param>
 public void SendObject <T>(T obj, Action callback = null)
 {
     SendPackage(new TcpBsonPackage
     {
         Type      = TcpBsonPackageType.Bson,
         DataType  = GetDataType(typeof(T)),
         DataBytes = BsonConvert.SerializeObject(obj),
         Callback  = callback
     });
 }
        private void DoReceiveBson(TcpBsonPackage package)
        {
            var dataType = Type.GetType(package.DataType);

            lock (mJsonHandlers)
            {
                foreach (var handler in mJsonHandlers)
                {
                    if (handler.Type == dataType)
                    {
                        handler.Callback.DynamicInvoke(BsonConvert.DeserializeObject(package.DataBytes, dataType), this);
                    }
                }
            }
        }
        private void DoReceiveRequest(TcpBsonPackage package)
        {
            var requestType = Type.GetType(package.DataType);
            var dataType    = typeof(TcpBsonRequest <>).MakeGenericType(requestType);

            var requestBody = BsonConvert.DeserializeObject(package.DataBytes, dataType) as TcpBsonRequest;
            var handler     = mReceiveRequestCallbacks.FirstOrDefault(c => c.URI.Equals(requestBody.URI, StringComparison.OrdinalIgnoreCase) && (c.RequestType == requestType || c.RequestType.IsAssignableFrom(requestType)));

            var responsePackage = new TcpBsonPackage {
                Type = TcpBsonPackageType.Response
            };
            object responseBody = null;

            if (handler == null)
            {
                responseBody = new TcpBsonResponse <string> {
                    Id = requestBody.Id, Object = "No handle this request"
                };
                responsePackage.DataType = "ERROR";
                return;
            }
            try
            {
                var response         = handler.Callback.DynamicInvoke(requestBody.Object, this);
                var responseDataType = response != null?response.GetType() : handler.ResponseType;

                var responseType = typeof(TcpBsonResponse <>).MakeGenericType(responseDataType);

                var responseData = responseType.GetConstructor(Type.EmptyTypes).Invoke(null);
                responseType.GetProperty("Id").SetValue(responseData, requestBody.Id, null);
                responseType.GetProperty("Object").SetValue(responseData, response, null);

                responsePackage.DataType = responseDataType.AssemblyQualifiedName;
                responseBody             = responseData;
            }
            catch (Exception e)
            {
                responseBody = new TcpBsonResponse <string> {
                    Id = requestBody.Id, Object = "Handle Exception - " + e.ToString()
                };
                responsePackage.DataType = "ERROR";
            }
            finally
            {
                responsePackage.DataBytes = BsonConvert.SerializeObject(responseBody);
                SendPackage(responsePackage);
            }
        }
        internal void Sync(TcpBsonPackage package)
        {
            var sync = BsonConvert.DeserializeObject <TcpBsonCookieSync>(package.DataBytes);

            lock (this)
            {
                switch (sync.Action)
                {
                case TcpBsonCookieSyncAction.Clear:
                    mCookies.Clear();
                    break;

                case TcpBsonCookieSyncAction.Add:
                case TcpBsonCookieSyncAction.Update:
                    mCookies[sync.Name] = sync.Value;
                    break;

                case TcpBsonCookieSyncAction.Remove:
                    mCookies.Remove(sync.Name);
                    break;
                }
            }
        }
 private void DoReceiveResponse(TcpBsonPackage package)
 {
     if (package.DataType == "ERROR")
     {
         var errorResponse = BsonConvert.DeserializeObject <TcpBsonResponse <string> >(package.DataBytes);
         var responseCxt   = mWaitResponseContexts.FirstOrDefault(r => r.Id == errorResponse.Id);
         if (responseCxt != null)
         {
             responseCxt.SetError(errorResponse.Object);
         }
     }
     else
     {
         var responseType = typeof(TcpBsonResponse <>).MakeGenericType(Type.GetType(package.DataType));
         var responseBody = BsonConvert.DeserializeObject(package.DataBytes, responseType);
         var id           = (Guid)responseType.GetProperty("Id").GetValue(responseBody, null);
         var responseCxt  = mWaitResponseContexts.FirstOrDefault(r => r.Id == id);
         if (responseCxt != null)
         {
             responseCxt.SetResponse(responseType.GetProperty("Object").GetValue(responseBody, null));
         }
     }
 }
        /// <summary>
        /// Sync Send an Request and wait Response
        /// </summary>
        /// <typeparam name="TRequest">Response Object Type</typeparam>
        /// <param name="uri">A request uri</param>
        /// <param name="obj">Request object</param>
        /// <param name="millisecondsTimeout">Response timeout milliseconds, Default is one Minute.</param>
        /// <returns>Response object</returns>
        public object SendRequest <TRequest>(string uri, TRequest obj, int millisecondsTimeout = 60000)
        {
            var data = new TcpBsonRequest <TRequest>
            {
                Id     = Guid.NewGuid(),
                URI    = uri,
                Object = obj
            };
            TcpBsonRequestContext cxt = new TcpBsonRequestContext(this, data.Id);

            SendPackage(new TcpBsonPackage
            {
                Type      = TcpBsonPackageType.Request,
                DataType  = typeof(TRequest).AssemblyQualifiedName,
                DataBytes = BsonConvert.SerializeObject(data)
            });
            mWaitResponseContexts.Add(cxt);
            try
            {
                if (cxt.WaitHandler.WaitOne(millisecondsTimeout))
                {
                    if (cxt.IsError)
                    {
                        throw new Exception(cxt.ErrorMessage);
                    }
                    return(cxt.Response);
                }
                else
                {
                    throw new TimeoutException("Response is Timeout!");
                }
            }
            finally
            {
                mWaitResponseContexts.Remove(cxt);
            }
        }
 /// <summary>
 /// End a init, This will restore cookie sync.
 /// </summary>
 public void EndInit()
 {
     mInInitMode = false;
     if (mInitSyncs.Any())
     {
         lock (mInitSyncs)
         {
             foreach (var sync in mInitSyncs)
             {
                 mClient.SendPackage(new TcpBsonPackage {
                     Type = TcpBsonPackageType.CookieSync, DataType = typeof(TcpBsonCookieSync).AssemblyQualifiedName, DataBytes = BsonConvert.SerializeObject(sync)
                 });
             }
             mInitSyncs.Clear();
         }
     }
 }
 private void SendSync(TcpBsonCookieSync sync)
 {
     if (mInInitMode)
     {
         lock (mInitSyncs)
         {
             mInitSyncs.Add(sync);
         }
     }
     else
     {
         mClient.SendPackage(new TcpBsonPackage {
             Type = TcpBsonPackageType.CookieSync, DataType = typeof(TcpBsonCookieSync).AssemblyQualifiedName, DataBytes = BsonConvert.SerializeObject(sync)
         });
     }
 }