Beispiel #1
0
        private void HandleMessage(GcMessage message)
        {
            MessageHandler handler;

            _messageHandlers.TryGetValue(message.OpCode, out handler);

            if (handler == null && message.RequiresResponse)
            {
                // No handler, but message requires a response
                message.Respond(ResponseStatus.NotHandled, "Not handled");
                return;
            }

            // No handler, but don't need to respond
            if (handler == null)
            {
                return;
            }

            Task.Run(async() =>
            {
                try
                {
                    await handler.Invoke(message);
                }
                catch (Exception e)
                {
                    _logger.LogError("Exception while handling a request", e);

                    try
                    {
                        if (message.RequiresResponse)
                        {
                            message.Respond(ResponseStatus.Error, "Internal error");
                        }
                    }
                    catch (Exception responseException)
                    {
                        _logger.LogError("Exception while trying to respond after " +
                                         "catching an exception", responseException);
                    }
                }
            });
        }
        public GcConnection(IConnectionImplementation implementation)
        {
            // Generate instance id for better hashing
            _instanceId = Interlocked.Increment(ref _instanceIdGenerator);

            _relayedPeers      = new ConcurrentDictionary <int, GcPeer>();
            _responseCallbacks = new ConcurrentDictionary <int, TaskCompletionSource <GcMessage> >();
            _timeoutMessage    = new GcMessage(null, 0)
            {
                Status = ResponseStatus.Timeout
            };

            Implementation = implementation;

            implementation.DataReceived += OnDataReceived;
            implementation.Disconnected += OnDisconnected;

            _writer = new NetWriter();
        }
Beispiel #3
0
        public static GcMessage ParseMessage(GcPeer peer, byte[] data)
        {
            var reader = new NetReader(data);

            var flags  = reader.ReadByte();
            var opCode = reader.ReadInt16();

            // Read peer id if it's provided
            if ((flags & MessageFlags.PaddedPeerId) > 0)
            {
                // Read padded peer id
                reader.ReadInt32();
            }

            var msg = new GcMessage(peer, flags)
            {
                OpCode = opCode,
                Reader = reader
            };

            if ((flags & MessageFlags.Request) > 0)
            {
                var requestId = reader.ReadInt32();
                msg.RequestId = requestId;
            }

            if ((flags & MessageFlags.Response) > 0)
            {
                var responseId     = reader.ReadInt32();
                var responseStatus = (ResponseStatus)reader.ReadByte();
                msg.ResponseId = responseId;
                msg.Status     = responseStatus;
            }

            return(msg);
        }
Beispiel #4
0
        private async Task HandleEstablishPeer(GcMessage message)
        {
            var    peerId          = message.Reader.ReadInt32();
            var    isDirectMessage = peerId < 0;
            GcPeer peer            = null;

            if (isDirectMessage)
            {
                // This is a direct message from client
                // who can't know his peer id
                peerId = message.Peer.PeerId;
                peer   = message.Peer;
            }
            else
            {
                // This is a message that was already relayed at least once
                // We need to create a virtual peer which will be used in this server
                var vPeer = new GcPeer(Interlocked.Increment(ref _peerIdGenerator), message.Peer);

                _peers.TryAdd(vPeer.PeerId, vPeer);
                PeerJoined?.Invoke(vPeer);

                // Add the newly created peer id
                peerId = vPeer.PeerId;
                peer   = vPeer;
            }

            // Send messages to all of the relayed servers to establish a peer in them
            var connections = _relayConnections.Values.Distinct().Where(c => c.IsConnected);

            var allSuccessful = true;

            // Do it "linearly" (one by one) because it's a lot easier to handle
            foreach (var connection in connections)
            {
                var response =
                    await connection.SendRequest((short)InternalOpCodes.EstablishPeer, w => w.Write(peerId));

                if (response.Status != ResponseStatus.Success)
                {
                    _logger.LogWarning("Failed to establish a peer in connection: " + connection);
                    allSuccessful = false;
                    continue;
                }

                var assignedPeerId = response.Reader.ReadInt32();

                // For forwarding messages
                peer.SetPeerIdInRelayedServer(assignedPeerId, connection);

                // For "backwarding" messages
                connection.SaveRelayedPeer(assignedPeerId, peer);
            }

            if (isDirectMessage)
            {
                message.Respond(allSuccessful ? ResponseStatus.Success : ResponseStatus.Failed);
            }
            else
            {
                message.Respond(ResponseStatus.Success, w => w.Write(peerId));
            }
        }