Пример #1
0
        /// <summary>
        /// Ping
        /// </summary>
        /// <param name="request">request</param>
        /// <returns>response</returns>
        public ThriftSResponse Ping(ThriftSRequest request)
        {
            if (request == null)
            {
                ThriftSEnvirnment.Logger.Debug("Received ping.");
            }
            else
            {
                ThriftSEnvirnment.Logger.Debug(
                    string.Format("Received ping from {0} [{1}].", request.ClientHostName, request.ClientIP));
            }

            var xresponse = new ThriftSResponse()
            {
                Headers = new Dictionary <string, string>(),
                Result  = new ThriftSResult()
                {
                    Compression = ThriftSCompression.None,
                    ContentType = ContentTypes.Text,
                    Data        = Encoding.UTF8.GetBytes("pong")
                }
            };

            return(xresponse);
        }
Пример #2
0
        /// <summary>
        /// Hello
        /// </summary>
        /// <param name="request">request</param>
        /// <returns>response</returns>
        public ThriftSResponse Hello(ThriftSRequest request)
        {
            // 考虑是否需要抛出客户端连接事件到外部
            var serverProperties = new Dictionary <string, string>();

            serverProperties.Add("thrifts_server_version", Utils.Version);

            var xresponse = new ThriftSResponse()
            {
                Headers = serverProperties
            };

            return(xresponse);
        }
Пример #3
0
        /// <summary>
        /// Ping.
        /// </summary>
        public void Ping()
        {
            var pool = ConnectionPoolManager.GetPool(this.Host, this.Port, this.Timeout);
            ThriftSConnection connection = null;

            try
            {
                connection = pool.Borrow();

                var xrequest = new ThriftSRequest();
                xrequest.Headers        = new Dictionary <string, string>();
                xrequest.ClientHostName = Environment.MachineName;
                xrequest.ClientIP       = connection.LocalAddress.ToString();

                connection.Client.Ping(xrequest);
            }
            catch (TTransportException exception)
            {
                pool.ReportError(connection, exception);
                throw;
            }
            catch (TProtocolException exception)
            {
                pool.ReportError(connection, exception);
                throw;
            }
            catch (SocketException exception)
            {
                pool.ReportError(connection, exception);
                throw;
            }
            catch (IOException exception)
            {
                pool.ReportError(connection, exception);
                throw;
            }
            finally
            {
                pool.Release(connection);
            }
        }
Пример #4
0
 /// <summary>
 /// Handles the exception.
 /// </summary>
 /// <param name="exceptionName">Name of the exception.</param>
 /// <param name="invokeDesc">The invoke description.</param>
 /// <param name="request">The request.</param>
 /// <param name="exception">The exception.</param>
 private void HandleException(string exceptionName, string invokeDesc, ThriftSRequest request, Exception exception)
 {
     throw exception;
 }
Пример #5
0
        /// <summary>
        /// Invokes the specified message.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <returns>IMessage.</returns>
        public override IMessage Invoke(IMessage message)
        {
            var mcm = (IMethodCallMessage)message;
            IMethodReturnMessage returnMessage = null;

            if (mcm.MethodBase.IsDefined(typeof(ThriftSOperationAttribute), false) == false)
            {
                throw new ThriftSException(string.Format("Missing ThriftSOperationAttribute in '{0}.{1}'.", this.ServiceName, mcm.MethodName));
            }

            object returnValue = null;

            var stopwatch = new Stopwatch();

            string invokeDesc = string.Format("调用{0}契约的{1}方法", this.ServiceName, mcm.MethodName);

            // 构造请求
            var srequest = new ThriftSRequest()
            {
                ServiceName = this.ServiceName,
                MethodName  = Utils.GetMethodName((MethodInfo)mcm.MethodBase),
                Headers     = new Dictionary <string, string>(),
                Parameters  = new List <ThriftSParameter>()
            };

            srequest.Uri            = string.Format("thrift://{0}:{1}/{2}/{3}", this.Host, this.Port, this.ServiceShortName, srequest.MethodName);
            srequest.Version        = Utils.Version;
            srequest.ClientPid      = this.ClientPid;
            srequest.ClientHostName = this.ClientHostName;
            srequest.ClientRuntime  = ".NET " + Environment.Version.ToString();

            try
            {
                // 计时开始
                stopwatch.Start();
                if (mcm.Args != null)
                {
                    for (var i = 0; i < mcm.Args.Length; i++)
                    {
                        var argument = mcm.Args[i];

                        ThriftSParameter parameter = null;
                        if (argument == null)
                        {
                            parameter = new ThriftSParameter()
                            {
                                Index       = (sbyte)i,
                                Name        = string.Empty,
                                Type        = string.Empty,
                                Compression = ThriftSCompression.None,
                                ContentType = ContentTypes.Binary,
                                HasValue    = false
                            };
                        }
                        else
                        {
                            parameter = new ThriftSParameter()
                            {
                                Index       = (sbyte)i,
                                Name        = string.Empty,
                                Type        = string.Empty,
                                Compression = ThriftSCompression.None,
                                ContentType = ContentTypes.Thrift,
                                HasValue    = true,
                                Value       = ThriftSerializer.Serialize(argument)
                            };
                        }

                        // 大于10K开启压缩
                        if (parameter.Value != null && parameter.Value.Length > 10 * 1024)
                        {
                            parameter.Value       = Utils.GzipCompress(parameter.Value);
                            parameter.Compression = ThriftSCompression.Gzip;
                        }

                        srequest.Parameters.Add(parameter);
                    }
                }

                ThriftSResponse sresponse = null;
                try
                {
                    var xpool = ConnectionPoolManager.GetPool(this.Host, this.Port, this.Timeout);
                    ThriftSConnection xconnection     = null;
                    TimeSpan          connectTookTime = TimeSpan.MinValue;
                    try
                    {
                        DateTime beginConnectTime = DateTime.Now;
                        xconnection     = xpool.Borrow();
                        connectTookTime = beginConnectTime - DateTime.Now;

                        if (string.IsNullOrEmpty(this.ClientIP))
                        {
                            this.ClientIP = xconnection.LocalAddress.ToString();
                        }

                        srequest.ClientIP = this.ClientIP;
                        sresponse         = xconnection.Client.Process(srequest);
                    }
                    catch (SocketException exception)
                    {
                        xpool.ReportError(xconnection, exception);
                        this.HandleException("SocketException", invokeDesc, srequest, exception);
                    }
                    catch (IOException exception)
                    {
                        xpool.ReportError(xconnection, exception);
                        var socketException = exception.InnerException as SocketException;
                        if (socketException != null)
                        {
                            this.HandleException("SocketException", invokeDesc, srequest, socketException);
                        }

                        this.HandleException("IOException", invokeDesc, srequest, exception);
                    }
                    catch (TTransportException exception)
                    {
                        xpool.ReportError(xconnection, exception);

                        // 5秒以内的timeout认为是服务器积极拒绝.
                        if (exception.Message.StartsWith("Connect timed out") &&
                            connectTookTime.TotalSeconds < 5)
                        {
                            // 处理异常
                            this.HandleException(
                                "TTransportException",
                                invokeDesc,
                                srequest,
                                new TTransportException(exception.Type, "Service unavailable."));
                        }
                        else
                        {
                            this.HandleException("TTransportException", invokeDesc, srequest, exception);
                        }
                    }
                    catch (TProtocolException exception)
                    {
                        xpool.ReportError(xconnection, exception);
                        this.HandleException("TProtocolException", invokeDesc, srequest, exception);
                    }
                    finally
                    {
                        // 内部Try可以更快的释放连接。
                        xpool.Release(xconnection);
                    }

                    // 非void且result非空
                    if (sresponse != null && sresponse.Result != null)
                    {
                        // 解压
                        if (sresponse.Result.Compression == ThriftSCompression.Gzip)
                        {
                            sresponse.Result.Data = Utils.GzipUnCompress(sresponse.Result.Data);
                        }

                        if (sresponse.Result.ContentType == ContentTypes.Thrift)
                        {
                            returnValue = ThriftSerializer.Deserialize(
                                ((MethodInfo)mcm.MethodBase).ReturnType,
                                sresponse.Result.Data);
                        }
                        else
                        {
                            throw new NotSupportedException(string.Format("Not supported content type: {0}", sresponse.Result.ContentType));
                        }
                    }

                    returnMessage = new ReturnMessage(returnValue, null, 0, mcm.LogicalCallContext, mcm);
                }
                catch (TApplicationException tapplicationException)
                {
                    var info      = string.Format("tapplication exception on calling {0}. ", srequest.Uri);
                    var exception = new ThriftSException(info + tapplicationException.Message, tapplicationException);

                    returnMessage = new ReturnMessage(exception, mcm);
                }
                catch (BadRequestException badRequestException)
                {
                    var info      = string.Format("Bad request exception on calling {0}. ", srequest.Uri);
                    var exception = new ThriftSException(
                        info + badRequestException.ErrorMessage,
                        info + Environment.NewLine + badRequestException.ErrorMessage);

                    // 远端异常使用ReturnMessage包装
                    returnMessage = new ReturnMessage(exception, mcm);
                }
                catch (InternalServerException internalServerException)
                {
                    var info      = string.Format("Server internal exception on calling {0}. ", srequest.Uri);
                    var exception = new ThriftSException(
                        info + internalServerException.ErrorMessage,
                        info + Environment.NewLine + internalServerException.ErrorDescription);

                    returnMessage = new ReturnMessage(exception, mcm);
                }
                catch (InvocationException invocationException)
                {
                    var info      = string.Format("Server invocation exception on calling {0}. ", srequest.Uri);
                    var exception = new ThriftSException(
                        info + invocationException.ErrorMessage,
                        info + Environment.NewLine + invocationException.ErrorDescription);

                    returnMessage = new ReturnMessage(exception, mcm);
                }
                catch (Exception exception)
                {
                    this.HandleException("Exception", invokeDesc, srequest, exception);
                }
            }
            finally
            {
                stopwatch.Stop();
            }

            return(returnMessage);
        }
Пример #6
0
        /// <summary>
        /// 请求处理
        /// </summary>
        /// <param name="request">request</param>
        /// <returns>response</returns>
        public ThriftSResponse Process(ThriftSRequest request)
        {
            if (request == null ||
                string.IsNullOrWhiteSpace(request.ServiceName) ||
                string.IsNullOrWhiteSpace(request.MethodName))
            {
                throw new BadRequestException(request, "The ServiceName or MethodName must be not null.");
            }

            if (LocalCache.ServiceDictionary.ContainsKey(request.ServiceName) == false)
            {
                throw new BadRequestException(request, "Service not found.");
            }

            if (LocalCache.ServiceDictionary[request.ServiceName].ContainsKey(request.MethodName) == false)
            {
                throw new BadRequestException(request, "Method not found.");
            }

            ThriftSEnvirnment.Logger.Debug("Accept request: {0}", request.Uri);

            var serviceMetadata = LocalCache.ServiceDictionary[request.ServiceName][request.MethodName];

            // 创建服务实例
            var service = Activator.CreateInstance(serviceMetadata.ServiceHandlerType);

            // 参数赋值
            var methodParameters = serviceMetadata.Method.GetParameters();
            var invokeParameters = new Dictionary <string, object>();

            for (var i = 0; i < methodParameters.Length; i++)
            {
                var parameter = methodParameters[i];

                // 在跨平台的时候服务端和客户端的参数名可能完全不一样,因此唯一依据是参数顺序,请求上下文的参数名以服务端为基准。
                request.Parameters[i].Name = parameter.Name;
                try
                {
                    ThriftSEnvirnment.Logger.Debug(string.Format(
                                                       new FileSizeFormatProvider(),
                                                       "Request parameter:{0}, ContentType:{1}, Compress:{2}, Length:{3:fs}",
                                                       parameter.Name,
                                                       request.Parameters[i].ContentType,
                                                       request.Parameters[i].Compression,
                                                       request.Parameters[i].HasValue ? request.Parameters[i].Value.Length : 0));

                    // 解压
                    if (request.Parameters[i].Compression == ThriftSCompression.Gzip)
                    {
                        request.Parameters[i].Value = Utils.GzipUnCompress(request.Parameters[i].Value);
                    }

                    if (request.Parameters[i].HasValue == false)
                    {
                        invokeParameters.Add(parameter.Name, null);
                    }
                    else
                    {
                        //if (request.Parameters[i].ContentType == ContentTypes.Protobuf)
                        //{
                        //    invokeParameters.Add(
                        //        parameter.Name,
                        //        Utils.DeserializeFromBytes(parameter.ParameterType, request.Parameters[i].Value));
                        //}
                        //else if (request.Parameters[i].ContentType == ContentTypes.Json)
                        //{
                        //    invokeParameters.Add(
                        //        parameter.Name,
                        //        Utils.DeserializeFromJson(parameter.ParameterType, request.Parameters[i].Value));
                        //}else
                        if (request.Parameters[i].ContentType == ContentTypes.Thrift)
                        {
                            invokeParameters.Add(
                                parameter.Name,
                                ThriftSerializer.Deserialize(parameter.ParameterType, request.Parameters[i].Value));
                        }
                        else
                        {
                            throw new NotSupportedException(string.Format("Not supported content type: {0}", request.Parameters[i].ContentType));
                        }
                    }
                }
                catch (Exception ex)
                {
                    throw new BadRequestException(
                              request,
                              string.Format("Parsing error on parameter '{0}'. {1}", parameter.Name, ex.Message));
                }
            }

            var    stopwatch = new Stopwatch();
            object result    = null;
            var    xresponse = new ThriftSResponse()
            {
                Headers = new Dictionary <string, string>()
            };

            xresponse.Version = Utils.Version;

            try
            {
                stopwatch.Start();

                try
                {
                    // 关联调用上下文
                    ThriftSContext.Current = new ThriftSContext()
                    {
                        Request = request
                    };

                    Func <object> action = () => serviceMetadata.Handle(service, invokeParameters.Values.ToArray());

                    if (serviceMetadata.Attribute.IsOneWay)
                    {
                        action.BeginInvoke(null, null);
                    }
                    else
                    {
                        result = action();
                    }

                    /*
                     * //异步调用,可以做oneway和timeout
                     * //Func<object> action = () =>
                     * //{
                     * //    return serviceMetadata.Handle(service, invokeParameters.Values.ToArray());
                     * //};
                     *
                     * //IAsyncResult asyncResult = action.BeginInvoke(null, null);
                     * //var isGetSignal = asyncResult.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(60));
                     * //if (isGetSignal == false)
                     * //{
                     * //    throw new TimeoutException("Execution timeout.");
                     * //}
                     * //result = action.EndInvoke(asyncResult);
                     */
                }
                catch (Exception ex)
                {
                    throw new InvocationException()
                          {
                              Request          = request,
                              ErrorMessage     = ex.Message,
                              ErrorDescription = ex.ToString()
                          };
                }

                // 检查返回值
                if (serviceMetadata.Method.ReturnType != typeof(void))
                {
                    if (result != null)
                    {
                        //if (Utils.GetSerializerMode(result.GetType()) == SerializerMode.ProtoBuf)
                        //{
                        //    xresponse.Result = new ThriftSResult()
                        //    {
                        //        ContentType = ContentTypes.Protobuf,
                        //        Compression = ThriftSCompression.None,
                        //        Data = Utils.SerializeToBytes(result)
                        //    };
                        //}
                        //else if (Utils.GetSerializerMode(result.GetType()) == SerializerMode.Json)
                        //{
                        //    xresponse.Result = new ThriftSResult()
                        //    {
                        //        ContentType = ContentTypes.Json,
                        //        Compression = ThriftSCompression.None,
                        //        Data = Utils.SerializeToJson(result)
                        //    };
                        //}
                        //else
                        {
                            xresponse.Result = new ThriftSResult()
                            {
                                ContentType = ContentTypes.Thrift,
                                Compression = ThriftSCompression.None,
                                Data        = ThriftSerializer.Serialize(result)
                            };
                        }

                        // 大于10K开启压缩
                        if (xresponse.Result.Data.Length > 10 * 1024)
                        {
                            xresponse.Result.Data        = Utils.GzipCompress(xresponse.Result.Data);
                            xresponse.Result.Compression = ThriftSCompression.Gzip;
                        }

                        ThriftSEnvirnment.Logger.Debug(string.Format(
                                                           new FileSizeFormatProvider(),
                                                           "Render response. ContentType:{0}, Compress:{1}, Length:{2:fs}",
                                                           xresponse.Result.ContentType,
                                                           xresponse.Result.Compression,
                                                           xresponse.Result.Data.Length));
                    }
                }
            }
            catch (Exception ex)
            {
                if (ex is InvocationException)
                {
                    throw;
                }

                throw new InternalServerException()
                      {
                          Request          = request,
                          ErrorMessage     = ex.Message,
                          ErrorDescription = ex.ToString()
                      };
            }
            finally
            {
                stopwatch.Stop();

                ThriftSEnvirnment.Logger.Debug("Request end. Took: {0}ms", stopwatch.Elapsed.TotalMilliseconds);
            }

            return(xresponse);
        }