Exemplo n.º 1
0
        public override void Read(ChannelHandlerContext ctx, object msg)
        {
            // client-side:
            // Here, the result for the awaitable task can be set.
            // If it is not a fire-and-forget message, the "result" of the TCS
            // must be set here. (If FF, then it is set in Sender.)

            // Java uses a SimpleChannelInboundHandler that only expects Message objects
            var responseMessage = msg as Message.Message;

            if (responseMessage == null)
            {
                return;
            }

            var recvMessageId = new MessageId(responseMessage);

            // error handling
            if (responseMessage.Type == Message.Message.MessageType.UnknownId)
            {
                string msg2 =
                    "Message was not delivered successfully. Unknown ID (peer may be offline or unknown RPC handler): " +
                    _message;
                ExceptionCaught(ctx, new PeerException(PeerException.AbortCauseEnum.PeerAbort, msg2));
                return;
            }
            if (responseMessage.Type == Message.Message.MessageType.Exception)
            {
                string msg2 = "Message caused an exception on the other side. Handle as PeerAbort: " + _message;
                ExceptionCaught(ctx, new PeerException(PeerException.AbortCauseEnum.PeerAbort, msg2));
                return;
            }
            if (responseMessage.IsRequest())
            {
                ctx.FireRead(responseMessage);
                return;
            }
            if (!_sendMessageId.Equals(recvMessageId))
            {
                string msg2 =
                    String.Format(
                        "Response message [{0}] sent to the node is not the same as we expect. We sent request message [{1}].",
                        responseMessage, _message);
                ExceptionCaught(ctx, new PeerException(PeerException.AbortCauseEnum.PeerAbort, msg2));
                return;
            }
            // We need to exclude RCON messages from the sanity check because we
            // use this RequestHandler for sending a Type.REQUEST_1,
            // RPC.Commands.RCON message on top of it. Therefore the response
            // type will never be the same Type as the one the user initially
            // used (e.g. DIRECT_DATA).
            if (responseMessage.Command != Rpc.Rpc.Commands.Rcon.GetNr() &&
                _message.Recipient.IsRelayed != responseMessage.Sender.IsRelayed)
            {
                string msg2 =
                    String.Format(
                        "Response message [{0}] sent has a different relay flag than we sent with request message [{1}]. Recipient ({2}) / Sender ({3}).",
                        responseMessage, _message, _message.Recipient.IsRelayed, responseMessage.Sender.IsRelayed);
                ExceptionCaught(ctx, new PeerException(PeerException.AbortCauseEnum.PeerAbort, msg2));
                return;
            }

            // we got a good answer, let's mark the sender as alive
            if (responseMessage.IsOk() || responseMessage.IsNotOk())
            {
                lock (PeerBean.PeerStatusListeners)
                {
                    if (responseMessage.Sender.IsRelayed && responseMessage.PeerSocketAddresses.Count != 0)
                    {
                        // use the response message as we have up-to-date content for the relays
                        PeerAddress remotePeer =
                            responseMessage.Sender.ChangePeerSocketAddresses(responseMessage.PeerSocketAddresses);
                        responseMessage.SetSender(remotePeer);
                    }
                    foreach (IPeerStatusListener listener in PeerBean.PeerStatusListeners)
                    {
                        listener.PeerFound(responseMessage.Sender, null, null);
                    }
                }
            }

            // call this for streaming support
            if (!responseMessage.IsDone)
            {
                Logger.Debug("Good message is streaming. {0}", responseMessage);
                return;
            }

            if (!_message.IsKeepAlive())
            {
                Logger.Debug("Good message {0}. Close channel {1}.", responseMessage, ctx.Channel);

                // .NET-specific:
                // set the result now, but trigger the notify when the channel is closed
                _tcsResponse.ResponseLater(responseMessage, ctx);

                // in Java, the channel creator adds a listener that sets the
                // future response result when the channel is closed
                ctx.Close(); // TODO needed?
            }
            else
            {
                Logger.Debug("Good message {0}. Leave channel {1} open.", responseMessage, ctx.Channel);
                _tcsResponse.SetResult(responseMessage);
            }
        }