Example #1
0
        private void ProcessNormalRequest(IRpcHttpContext ctx, Stream outputStream)
        {
            RpcError error = new RpcError("rpc server error.", null);

            if (ctx.Request.ContentLength64 > ByteSize.FromMbs(10).TotalBytes)
            {
                error.Message = "request data is limited in 10Mb";
            }
            else
            {
                var requestMeta = ctx.Request.Headers["meta"];
                if (requestMeta != null)
                {
                    //get request metadata
                    IRpcHeadSerializer headSerializer;
                    if (!iocContainer.TryResolve(out headSerializer))
                    {
                        headSerializer = iocContainer.Resolve <IRpcHeadSerializer>("default");
                    }
                    RpcHead head = null;
                    bool    deserialize_head_error_obtained = false;
                    bool    deserialize_body_error_obtained = false;
                    try
                    {
                        head = headSerializer.Deserialize(requestMeta);
                    }
                    catch (Exception ex)
                    {
                        deserialize_head_error_obtained = true;
                        error.Message    = "error on deserialize rpc head metadata. " + ex.Message;
                        error.StackTrace = ex.StackTrace;
                    }
                    if (head != null)
                    {
                        RpcHead.SetCurrent(head);
                        Type itfType = itfTypes.FirstOrDefault(x => x.Namespace == head.Namespace && x.Name == head.TypeName);
                        if (itfType != null)
                        {
                            var itfMethod = (MethodInfo)ReflectionHelper.ResolveMethod(itfType, head.MethodMDToken);
                            if (itfMethod != null)
                            {
                                var         parmTypes       = itfMethod.GetParameters().Select(x => x.ParameterType).ToArray();
                                var         pramNames       = itfMethod.GetParameters().Select(x => x.Name).ToArray();
                                bool        error_generated = false;
                                IRpcService rpcService      = null;

                                //deserialize arguments
                                IRpcDataSerializer serializer;
                                if (!iocContainer.TryResolve(out serializer))
                                {
                                    serializer = iocContainer.Resolve <IRpcDataSerializer>("default");
                                }
                                object[] args = null;
                                if (head.EventOp)
                                {
                                    FixupEventHandlerType(parmTypes);
                                }
                                try
                                {
                                    args = serializer.Deserialize(ctx.Request.InputStream, parmTypes, pramNames);
                                }
                                catch (Exception ex)
                                {
                                    deserialize_body_error_obtained = true;
                                    error.Message    = "error on deserialize rpc request data. " + ex.Message;
                                    error.StackTrace = ex.StackTrace;
                                }
                                if (!deserialize_body_error_obtained)
                                {
                                    object impl      = null;
                                    object returnVal = null;

                                    //find a instance
                                    if (!this.instances.TryGetValue(head.InstanceId, out impl))
                                    {
                                        //resolve the implimentation of the interface
                                        impl = iocContainer.Resolve(itfType);
                                    }
                                    var implInternal = impl;
                                    if (impl != null && !typeof(ThunkImplementation).IsAssignableFrom(impl.GetType()))
                                    {
                                        //thunk impl is for event remote handle, if no this thunk, server can not known which client handler will call
                                        impl = this.instances[head.InstanceId] = thunkImplFactory.GetProxy(itfType, impl, head.InstanceId, this);
                                    }

                                    //process a call for getting user infomation if user code support authroize
                                    rpcService = impl as IRpcService;
                                    var abstractRpcService = implInternal as RpcService;
                                    if (abstractRpcService != null)
                                    {
                                        abstractRpcService.exceptionHandler = this.ExceptionHandler;
                                        abstractRpcService.authorizeHandler = this.AuthroizeHandler;
                                    }
                                    RpcIdentity identity = rpcService != null?rpcService.Authroize(head.Token) : AuthroizeHandler.Authroize(head.Token);

                                    var principal = new RpcPrincipal(identity);
                                    Thread.CurrentPrincipal = principal;
                                    if (abstractRpcService != null)
                                    {
                                        abstractRpcService.User = principal;
                                    }
                                    var rpcAdministration = implInternal as RpcServiceAdministration;
                                    if (rpcAdministration != null)
                                    {
                                        rpcAdministration.Server = this;
                                    }

                                    Type instanceType = impl.GetType();

                                    try
                                    {
                                        Console.WriteLine("[rpc call] {0}.{1}.{2}", head.Namespace, head.TypeName, head.MethodName);
                                        if (!RpcMethodHelper.IsAuthoirzied(itfType, itfMethod, instanceType))
                                        {
                                            error_generated         = true;
                                            error                   = new RpcError("access denied.", null);
                                            ctx.Response.StatusCode = 401;
                                        }
                                        else
                                        {
                                            //execute the call
                                            if (head.EventOp)
                                            {
                                                //Debugger.Break();
                                                var op = head.GetEventOp();
                                                //create a method as the event proxy

                                                EventInfo e           = TypeHelper.GetEventInfo(itfType, op.EventName);
                                                var       hanlderName = itfType.Name + "_" + op.EventName;

                                                //thunkHandler is a proxy method will call DelegateHelper.
                                                var thunkHandler = instanceType.GetMethod(hanlderName);

                                                var clientHandlerId = (int)args[0]; /*event callback id of client*/

                                                //event register/unregister
                                                if (op.EventKind == RpcEventKind.Add)
                                                {
                                                    EventHub.AddEventHandler(e, impl, head.InstanceId, thunkHandler, clientHandlerId);
                                                }
                                                else
                                                {
                                                    EventHub.RemoveEventHandler(e, impl, head.InstanceId, thunkHandler, clientHandlerId);
                                                    BlockingQueue <RpcEvent> messages;
                                                    if (this.eventMessages.TryGetValue(head.InstanceId, out messages))
                                                    {
                                                        //null for close the ws connection
                                                        //Console.WriteLine("send null RpcEvent for close the ws connection on instance " + head.InstanceId);
                                                        messages.Enqueue(null);
                                                    }
                                                }
                                            }
                                            else
                                            {
                                                MethodInfo implMethod = RpcMethodHelper.FindImplMethod(itfType, itfMethod, instanceType);
                                                returnVal = RpcMethodHelper.Invoke(itfType, itfMethod, impl, implMethod, head.EventOp, head.Timeout, head.Token, args);
                                            }
                                            //dispose resouces like stream
                                            foreach (IDisposable item in args.OfType <IDisposable>())
                                            {
                                                try
                                                {
                                                    item.Dispose();
                                                }
                                                catch { }
                                            }
                                        }
                                    }
                                    catch (TargetInvocationException ex)
                                    {
                                        error_generated = true;
                                        if (rpcService != null)
                                        {
                                            try
                                            {
                                                error = rpcService.HandleException(head, ex.InnerException);
                                            }
                                            catch (Exception ex2)
                                            {
                                                //do not use exceptionHandler here, it may cause a deal loop
                                                //because the rpcService backend ex handler is exceptionHandler by default
                                                error = RpcError.FromException(ex2);
                                            }
                                        }
                                        else
                                        {
                                            error = this.ExceptionHandler.HandleException(head, ex.InnerException);
                                        }
                                    }
                                    catch (Exception ex)
                                    {
                                        error_generated = true;
                                        if (rpcService != null)
                                        {
                                            try
                                            {
                                                error = rpcService.HandleException(head, ex);
                                            }
                                            catch (Exception ex2)
                                            {
                                                //do not use exceptionHandler here, it may cause a deal loop
                                                //because the rpcService backend ex handler is exceptionHandler by default
                                                error = RpcError.FromException(ex2);
                                            }
                                        }
                                        else
                                        {
                                            error = this.ExceptionHandler.HandleException(head, ex);
                                        }
                                    }
                                    if (!error_generated)
                                    {
                                        try
                                        {
                                            if (itfMethod.ReturnType != typeof(void))
                                            {
                                                if (typeof(Task).IsAssignableFrom(itfMethod.ReturnType))
                                                {
                                                    if (itfMethod.ReturnType.IsGenericType)
                                                    {
                                                        serializer.Serialize(outputStream, new Type[] { itfMethod.ReturnType.GenericTypeArguments[0] }, new object[] { returnVal }, new string[] { "p0" });
                                                    }
                                                    else
                                                    {
                                                        //no need handle task without a result.
                                                    }
                                                }
                                                else
                                                {
                                                    serializer.Serialize(outputStream, new Type[] { itfMethod.ReturnType }, new object[] { returnVal }, new string[] { "p0" });
                                                }
                                                IDisposable value = returnVal as IDisposable;
                                                if (value != null)
                                                {
                                                    try { value.Dispose(); } catch { }
                                                }
                                                IDisposable inst = impl as IDisposable;
                                                if (inst != null)
                                                {
                                                    try { inst.Dispose(); } catch { }
                                                }
                                            }
                                            return;
                                        }
                                        catch (Exception ex)
                                        {
                                            Console.WriteLine("error on writting response, " + ex.Message);
                                            return; // connection is broken. nothing to do.
                                        }
                                    }
                                }
                            }
                            else
                            {
                                error.Message = "invalid rpc request metadata, unknown method under the interface.";
                            }
                        }
                        else
                        {
                            error.Message = "invalid rpc request metadata, unknown interface.";
                        }
                    }
                    else if (!deserialize_head_error_obtained)
                    {
                        error.Message = "invalid rpc request metadata, deserialize failed.";
                    }
                }
                else
                {
                    error.Message = "invalid rpc request metadata";
                }
            }
            Console.WriteLine(error.Message);
            Console.WriteLine(error.StackTrace);
            if (ctx.Response.StatusCode == 200)
            {
                ctx.Response.StatusCode        = 500;
                ctx.Response.StatusDescription = "Internal Server Error";
            }
            ctx.WriteOutput(outputStream, error);
        }