/// <summary>
            /// Adds a procedure that can be called by remote peer to the scene.
            /// </summary>
            /// <param name="route"></param>
            /// <param name="handler"></param>
            /// <param name="ordered">True if the message should be alwayse receive in order, false otherwise.</param>
            /// <remarks>
            /// The procedure is added to the scene to which this service is attached.
            /// </remarks>
            public void AddProcedure(string route, Func <RequestContext <IScenePeer>, Task> handler, bool ordered)
            {
                this._scene.AddRoute(route, p =>
                {
                    var buffer = new byte[2];
                    p.Stream.Read(buffer, 0, 2);
                    var id         = BitConverter.ToUInt16(buffer, 0);
                    var cts        = new CancellationTokenSource();
                    var ctx        = new RequestContext <IScenePeer>(p.Connection, _scene, id, ordered, new SubStream(p.Stream, false), cts.Token);
                    var identifier = System.Tuple.Create(p.Connection.Id, id);
                    if (_runningRequests.TryAdd(identifier, cts))
                    {
                        handler.InvokeWrapping(ctx).ContinueWith(t =>
                        {
                            _runningRequests.TryRemove(identifier, out cts);
                            if (t.Status == TaskStatus.RanToCompletion)
                            {
                                ctx.SendCompleted();
                            }
                            else if (t.Status == TaskStatus.Faulted)
                            {
                                var errorSent = false;

                                var ex = t.Exception.InnerExceptions.OfType <ClientException>();
                                if (ex.Any())
                                {
                                    ctx.SendError(string.Join("|", ex.Select(e => e.Message).ToArray()));
                                    errorSent = true;
                                }
                                if (t.Exception.InnerExceptions.Any(e => !(e is ClientException)))
                                {
                                    string errorMessage = string.Format("An error occured while executing procedure '{0}'.", route);
                                    if (!errorSent)
                                    {
                                        var errorId = Guid.NewGuid().ToString("N");
                                        ctx.SendError(string.Format("An exception occurred on the remote peer. Error {0}.", errorId));

                                        errorMessage = string.Format("Error {0}. ", errorId) + errorMessage;
                                    }

                                    _scene.DependencyResolver.Resolve <ILogger>().Log(LogLevel.Error, "rpc.server", errorMessage, t.Exception);
                                }
                            }
                        });
                    }
                }, new Dictionary <string, string> {
                    { RpcClientPlugin.PluginName, RpcClientPlugin.Version }
                });
            }
        /// <summary>
        /// Adds a procedure that can be called by remote peer to the scene.
        /// </summary>
        /// <param name="route"></param>
        /// <param name="handler"></param>
        /// <param name="ordered">True if the message should be alwayse receive in order, false otherwise.</param>
        /// <remarks>
        /// The procedure is added to the scene to which this service is attached.
        /// </remarks>
        public void AddProcedure(string route, Func <RequestContext <IScenePeerClient>, Task> handler, bool ordered)
        {
            this._scene.AddRoute(route, async p =>
            {
                var buffer = new byte[2];
                p.Stream.Read(buffer, 0, 2);
                var id = BitConverter.ToUInt16(buffer, 0);
                var peerCancellationToken = GetCancellationTokenForPeer(p.Connection);

                var cts = CancellationTokenSource.CreateLinkedTokenSource(peerCancellationToken);

                var ctx        = new RequestContext <IScenePeerClient>(p.Connection, _scene, id, ordered, new SubStream(p.Stream, false), cts);
                var identifier = Tuple.Create(p.Connection.Id, id);
                if (_runningRequests.TryAdd(identifier, cts))
                {
                    try
                    {
                        Exception e       = null;
                        bool errorOccured = false;
                        try
                        {
                            await handler.InvokeWrapping(ctx);
                        }
                        catch (Exception ex)
                        {
                            errorOccured = true;
                            e            = ex;
                        }


                        if (!errorOccured)
                        {
                            ctx.SendCompleted();
                        }
                        else
                        {
                            var errorSent = false;
                            var ex        = e as ClientException;
                            if (ex != null)
                            {
                                ctx.SendError(string.Join("|", ex.Message));
                                errorSent = true;
                            }
                            else
                            {
                                string errorMessage = string.Format("An error occured while executing procedure '{0}'.", route);
                                if (!errorSent)
                                {
                                    var errorId = Guid.NewGuid().ToString("N");
                                    ctx.SendError($"An exception occurred on the server. Error {errorId}.");

                                    errorMessage = $"Error {errorId}. " + errorMessage;
                                }

                                _scene.DependencyResolver.Resolve <ILogger>().Log(LogLevel.Error, "rpc.client.server", errorMessage, e);
                            }
                        }
                    }
                    finally
                    {
                        _runningRequests.TryRemove(identifier, out cts);
                        ctx.Dispose();
                    }
                }
                else
                {
                    ctx.Dispose();
                }
            }, o => o, new Dictionary <string, string> {
                { RpcHostPlugin.PluginName, RpcHostPlugin.Version }
            });
        }
Пример #3
0
            /// <summary>
            /// Adds a procedure that can be called by remote peer to the scene.
            /// </summary>
            /// <param name="route"></param>
            /// <param name="handler"></param>
            /// <param name="ordered">True if the message should be alwayse receive in order, false otherwise.</param>
            /// <remarks>
            /// The procedure is added to the scene to which this service is attached.
            /// </remarks>
            public void AddProcedure(string route, Func<RequestContext<IScenePeer>, Task> handler, bool ordered)
            {
                this._scene.AddRoute(route, p =>
                {
                    var buffer = new byte[2];
                    p.Stream.Read(buffer, 0, 2);
                    var id = BitConverter.ToUInt16(buffer, 0);
                    var cts = new CancellationTokenSource();
                    var ctx = new RequestContext<IScenePeer>(p.Connection, _scene, id, ordered, new SubStream(p.Stream, false), cts.Token);
                    var identifier = System.Tuple.Create(p.Connection.Id, id);
                    if (_runningRequests.TryAdd(identifier, cts))
                    {
                        handler.InvokeWrapping(ctx).ContinueWith(t =>
                        {
                            _runningRequests.TryRemove(identifier, out cts);
                            if (t.Status == TaskStatus.RanToCompletion)
                            {
                                ctx.SendCompleted();
                            }
                            else if (t.Status == TaskStatus.Faulted)
                            {
                                var errorSent = false;

                                var ex = t.Exception.InnerExceptions.OfType<ClientException>();
                                if (ex.Any())
                                {
                                    ctx.SendError(string.Join("|", ex.Select(e => e.Message).ToArray()));
                                    errorSent = true;
                                }
                                if (t.Exception.InnerExceptions.Any(e => !(e is ClientException)))
                                {
                                    string errorMessage = string.Format("An error occured while executing procedure '{0}'.", route);
                                    if (!errorSent)
                                    {
                                        var errorId = Guid.NewGuid().ToString("N");
                                        ctx.SendError(string.Format("An exception occurred on the remote peer. Error {0}.", errorId));

                                        errorMessage = string.Format("Error {0}. ", errorId) + errorMessage;
                                    }

                                    _scene.DependencyResolver.Resolve<ILogger>().Log(LogLevel.Error, "rpc.server", errorMessage, t.Exception);

                                }

                            }
                        });
                    }
                }, new Dictionary<string, string> { { RpcClientPlugin.PluginName, RpcClientPlugin.Version } });
            }