/// <summary> /// Process commands in a single thread, until there are no more queued commands. /// Heartbeat is called between every command. /// </summary> public static void ProcessCommands() { if ((Core.Flags & StartupFlags.SingleThreaded) != StartupFlags.SingleThreaded) { throw new InvalidOperationException("ProcessCommands should only be called in single threaded mode."); } while (PendingCommands.Count > 0 && !ShuttingDown) { GlobalRules.ConsiderPerformRule("heartbeat"); Core.SendPendingMessages(); PendingCommand PendingCommand = null; try { PendingCommand = PendingCommands.FirstOrDefault(); if (PendingCommand != null) { PendingCommands.Remove(PendingCommand); } } catch (Exception e) { LogCommandError(e); PendingCommand = null; } if (PendingCommand != null) { NextCommand = PendingCommand; //Reset flags that the last command may have changed CommandTimeoutEnabled = true; SilentFlag = false; GlobalRules.LogRules(null); try { var handler = NextCommand.Actor.GetProperty <ClientCommandHandler>("command handler"); if (handler != null) { handler.HandleCommand(NextCommand); } } catch (Exception e) { LogCommandError(e); Core.DiscardPendingMessages(); } if (PendingCommand.ProcessingCompleteCallback != null) { PendingCommand.ProcessingCompleteCallback(); } } } }
private static void ProcessThreadedCommands() { if ((Core.Flags & StartupFlags.SingleThreaded) == StartupFlags.SingleThreaded) { throw new InvalidOperationException("ProcessThreadedCommands should never be called in single threaded mode."); } IndividualCommandThread = new Thread(ProcessCommandsWorkerThread); IndividualCommandThread.Start(); while (!ShuttingDown) { System.Threading.Thread.Sleep(10); DatabaseLock.WaitOne(); Heartbeat(); DatabaseLock.ReleaseMutex(); while (PendingCommands.Count > 0 && !ShuttingDown) { PendingCommand PendingCommand = null; PendingCommandLock.WaitOne(); try { PendingCommand = PendingCommands.FirstOrDefault(pc => { return(true); //if (pc.Actor.ConnectedClient == null) return true; //else return (DateTime.Now - pc.Actor.ConnectedClient.TimeOfLastCommand).TotalMilliseconds > SettingsObject.AllowedCommandRate; }); if (PendingCommand != null) { PendingCommands.Remove(PendingCommand); } } catch (Exception e) { LogCommandError(e); PendingCommand = null; } PendingCommandLock.ReleaseMutex(); if (PendingCommand != null) { DatabaseLock.WaitOne(); NextCommand = PendingCommand; //Reset flags that the last command may have changed CommandTimeoutEnabled = true; SilentFlag = false; GlobalRules.LogRules(null); CommandReadyHandle.Set(); //Signal worker thread to proceed. if (!CommandFinishedHandle.WaitOne(SettingsObject.CommandTimeOut)) { if (!CommandTimeoutEnabled) //Timeout is disabled, go ahead and wait for infinity. { CommandFinishedHandle.WaitOne(); } else { //Kill the command processor thread. IndividualCommandThread.Abort(); ClearPendingMessages(); if (PendingCommand.Actor.ConnectedClient != null) { PendingCommand.Actor.ConnectedClient.Send("Command timeout.\r\n"); LogError(String.Format("Command timeout. {0} - {1}", PendingCommand.Actor.ConnectedClient.ConnectionDescription, PendingCommand.RawCommand)); } else { LogError(String.Format("Command timeout [No client] - {1}", PendingCommand.RawCommand)); } IndividualCommandThread = new Thread(ProcessCommandsWorkerThread); IndividualCommandThread.Start(); } } if (PendingCommand.ProcessingCompleteCallback != null) { PendingCommand.ProcessingCompleteCallback(); } DatabaseLock.ReleaseMutex(); } } } IndividualCommandThread.Abort(); if (Core.OnShutDown != null) { Core.OnShutDown(); } }