/// <summary> /// Handles the event for a new server joining the cluster. /// </summary> /// <param name="id">The id of the server joining.</param> /// <param name="remoteServer">The server joining.</param> protected void HandleServerJoinEvent(ushort id, IRemoteServer remoteServer) { EventHandler <ServerJoinedEventArgs> handler = ServerJoined; if (handler != null) { void DoServerJoinEvent() { long startTimestamp = Stopwatch.GetTimestamp(); try { handler?.Invoke(this, new ServerJoinedEventArgs(remoteServer, id, this)); } catch (Exception e) { serverJoinedEventFailuresCounter.Increment(); // TODO this seems bad, shoudln't we disconnect them? logger.Error("A plugin encountered an error whilst handling the ServerJoined event. The server will still be connected. (See logs for exception)", e); } double time = (double)(Stopwatch.GetTimestamp() - startTimestamp) / Stopwatch.Frequency; serverJoinedEventTimeHistogram.Report(time); } threadHelper.DispatchIfNeeded(DoServerJoinEvent); } }
internal void Connect() { IEnumerable <IPAddress> addresses = Dns.GetHostEntry(Host).AddressList; // Try to connect to an IP address // TODO this might not reconnect to the same IP, break out option to prioritised last connected to. // TODO this will always try the same IP address, break out round robin option for load balancing this.connection = GetResultOfFirstSuccessfulInvocationOf(addresses, (address) => { NetworkClientConnection c = serverGroup.GetConnection(address, Port); c.MessageReceived += MessageReceivedHandler; c.Disconnected += DisconnectedHandler; c.Connect(); return(c); }); using (DarkRiftWriter writer = DarkRiftWriter.Create()) { writer.Write(remoteServerManager.ServerID); using (Message message = Message.Create((ushort)CommandCode.Identify, writer)) { message.IsCommandMessage = true; SendMessage(message, SendMode.Reliable); } } EventHandler <ServerConnectedEventArgs> handler = ServerConnected; if (handler != null) { void DoServerConnectedEvent() { long startTimestamp = Stopwatch.GetTimestamp(); try { handler?.Invoke(this, new ServerConnectedEventArgs(this)); } catch (Exception e) { serverConnectedEventFailuresCounter.Increment(); // TODO this seems bad, shouldn't we disconenct them? logger.Error("A plugin encountered an error whilst handling the ServerConnected event. The server will still be connected. (See logs for exception)", e); } double time = (double)(Stopwatch.GetTimestamp() - startTimestamp) / Stopwatch.Frequency; serverConnectedEventTimeHistogram.Report(time); } threadHelper.DispatchIfNeeded(DoServerConnectedEvent); } }
/// <summary> /// Sets the connection being used by this remote server. /// </summary> /// <param name="pendingServer">The connection to switch to.</param> internal void SetConnection(PendingDownstreamRemoteServer pendingServer) { if (connection != null) { connection.MessageReceived -= MessageReceivedHandler; connection.Disconnected -= DisconnectedHandler; } connection = pendingServer.Connection; // Switch out message received handler from the pending server connection.MessageReceived = MessageReceivedHandler; connection.Disconnected = DisconnectedHandler; EventHandler <ServerConnectedEventArgs> handler = ServerConnected; if (handler != null) { void DoServerConnectedEvent() { long startTimestamp = Stopwatch.GetTimestamp(); try { handler?.Invoke(this, new ServerConnectedEventArgs(this)); } catch (Exception e) { serverConnectedEventFailuresCounter.Increment(); logger.Error("A plugin encountered an error whilst handling the ServerConnected event. The server will still be connected. (See logs for exception)", e); } double time = (double)(Stopwatch.GetTimestamp() - startTimestamp) / Stopwatch.Frequency; serverConnectedEventTimeHistogram.Report(time); } threadHelper.DispatchIfNeeded(DoServerConnectedEvent); } // Handle all messages that had queued foreach (PendingDownstreamRemoteServer.QueuedMessage queuedMessage in pendingServer.GetQueuedMessages()) { HandleMessage(queuedMessage.Message, queuedMessage.SendMode); queuedMessage.Message.Dispose(); } }
/// <summary> /// Invokes the callback. /// </summary> /// <param name="_">Unused.</param> private void InvokeCallback(object _) { void DoInvoke() { Callback.Invoke(this); } threadHelper.DispatchIfNeeded(DoInvoke); }
/// <summary> /// Invokes the given command. /// </summary> /// <param name="rawCommand">The command as entered into the console.</param> /// <param name="command">The command to run.</param> private void InvokeCommand(string rawCommand, Command command) { CommandEventArgs args = BuildCommandEventArgs(rawCommand, command); threadHelper.DispatchIfNeeded(() => { try { command.Handler.Invoke(this, args); } catch (CommandSyntaxException e) { logger.Error($"Syntax Error: {e.Message}\nUsage: {command.Usage}"); } catch (Exception e) { logger.Error($"A plugin encountered an error whilst handling the command '{rawCommand}'. (See logs for exception)", e); } }); }
/// <summary> /// Called when a new client connects. /// </summary> /// <param name="connection">The new client.</param> internal void HandleNewConnection(NetworkServerConnection connection) { //Allocate ID and add to list ushort id; try { id = ReserveID(); } catch (InvalidOperationException) { logger.Info($"New client could not be connected as there were no IDs available to allocate to them [{connection.RemoteEndPoints.Format()}]."); connection.Disconnect(); return; } Client client; try { client = Client.Create( connection, id, this, threadHelper, clientLogger #if PRO , clientMetricsCollector #endif ); } catch (Exception e) { logger.Error("An exception ocurred while connecting a client. The client has been dropped.", e); connection.Disconnect(); DeallocateID(id, out int _); return; } AllocateIDToClient(id, client, out int noClients); // TODO if a client sends immediately after connecting then the message will be missed as the Connected event has not yet fired connection.Client = client; logger.Info($"New client [{client.ID}] connected [{client.RemoteEndPoints.Format()}]."); #if PRO clientsConnectedGauge.Report(noClients); #endif //Inform plugins of the new connection EventHandler <ClientConnectedEventArgs> handler = ClientConnected; if (handler != null) { threadHelper.DispatchIfNeeded( delegate() { #if PRO long startTimestamp = Stopwatch.GetTimestamp(); #endif try { handler.Invoke(this, new ClientConnectedEventArgs(client)); } catch (Exception e) { logger.Error("A plugin encountered an error whilst handling the ClientConnected event. The client will be disconnected. (See logs for exception)", e); client.DropConnection(); #if PRO clientConnectedEventFailuresCounter.Increment(); #endif return; } #if PRO double time = (double)(Stopwatch.GetTimestamp() - startTimestamp) / Stopwatch.Frequency; clientConnectedEventTimeHistogram.Report(time); #endif }, (_) => client.StartListening() ); } }