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(); }
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); }
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)); } }