Example #1
0
        private async Task InvokeThread(object state)
        {
            IWsDataSerializer serializer;

            if (!this.factory.iocContainer.TryResolve(out serializer))
            {
                serializer = this.factory.iocContainer.Resolve <IWsDataSerializer>("default");
            }
            var data = state as byte[];

            using (var inputms = new MemoryStream(data))
            {
                //response = eventKey + arguments
                var keyBytes = new byte[4];
                inputms.Read(keyBytes, 0, keyBytes.Length);
                var eventKey = BitConverter.ToInt32(keyBytes, 0);
                var key      = this.subscriptions.Keys.FirstOrDefault(x => x == eventKey);
                var d        = this.subscriptions[key];
                //the server will change a object sender to a string when process a eventhandler call. the string value is "<service-instance>"
                //we should fix
                var argTypes  = d.Method.GetParameters().Select(x => x.ParameterType).ToArray();
                var argNames  = d.Method.GetParameters().Select(x => x.Name).ToArray();
                var fixup     = this.FixupRemoteEventHandlerSenderType(argTypes);
                var arguments = serializer.Deserialize(inputms, argTypes, argNames);

                IRpcEventHandleResult result =
                    d.Method.ReturnType == typeof(void) ?
                    new RpcEventHandleResultVoid() :
                    Activator.CreateInstance(typeof(RpcEventHandleResultGeneral <>).MakeGenericType(d.Method.ReturnType)) as IRpcEventHandleResult;
                object retVal = null;
                try
                {
                    if (fixup)
                    {
                        this.FixupRemoteEventHandlerSenderValue(arguments);
                    }
                    Debugger.Break();
                    retVal       = d.Method.Invoke(d.Target, arguments);
                    result.Value = retVal;
                }
                catch (Exception ex)
                {
                    result.Error = RpcError.FromException(ex);
                }
                using (var outputms = new MemoryStream())
                {
                    serializer.Serialize(outputms, new Type[] { result.GetType() }, new object[] { result }, new string[] { "p0" });
                    await clientWebSocket.SendAsync(new ArraySegment <byte>(outputms.ToArray()), WebSocketMessageType.Binary, true, CancellationToken.None);
                }
            }
        }
Example #2
0
        public RpcError HandleException(RpcHead head, Exception ex)
        {
            var ae = ex as AggregateException;

            if (ae != null)
            {
                return(RpcError.FromException(ex.InnerException));
            }
            var tie = ex as TargetInvocationException;

            if (tie != null)
            {
                return(RpcError.FromException(ex.InnerException));
            }
            return(RpcError.FromException(ex));
        }
Example #3
0
 public RpcException(string mesage, RpcError detail, RpcErrorLocation location) : base(mesage)
 {
     this.Detail   = detail;
     this.Location = location;
 }
Example #4
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);
        }