OSDN Git Service

CommandsManager now runs commands in a TaskQueue from chat
authorDouglas R. Miles <logicmoo@gmail.com>
Sat, 12 Sep 2009 23:34:51 +0000 (23:34 +0000)
committerDouglas R. Miles <logicmoo@gmail.com>
Sat, 12 Sep 2009 23:34:51 +0000 (23:34 +0000)
ThreadCommand used to manage the tasks

git-svn-id: https://radegast.googlecode.com/svn/trunk@229 f7a694da-4d33-11de-9ad6-1127a62b9fcd

Radegast/Core/Commands/CommandsManager.cs
Radegast/Core/Commands/ThreadCommand.cs

index a8bc903..b833219 100644 (file)
@@ -30,6 +30,7 @@
 //\r
 using System;\r
 using System.Collections.Generic;\r
+using System.Threading;\r
 using OpenMetaverse;\r
 \r
 namespace Radegast.Commands\r
@@ -41,6 +42,11 @@ namespace Radegast.Commands
         public readonly Dictionary<string, IRadegastCommand> CommandsByName = new Dictionary<string, IRadegastCommand>();\r
         public readonly List<ICommandInterpreter> InterpretersLoaded = new List<ICommandInterpreter>();\r
         RadegastInstance instance;\r
+        public Queue<KeyValuePair<string, ThreadStart>> CommandQueue = new Queue<KeyValuePair<string, ThreadStart>>();\r
+        public AutoResetEvent CommandQueued = new AutoResetEvent(false);\r
+\r
+        private Thread _commandWorker;\r
+\r
         public CommandsManager(RadegastInstance inst)\r
         {\r
             instance = inst;\r
@@ -54,6 +60,64 @@ namespace Radegast.Commands
                                manager.Help(args, writeline);\r
                            }\r
                    });\r
+            _commandWorker = new Thread(CommandsManager_CommandWorker)\r
+                                {\r
+                                    Name = "CommandsManager Worker"\r
+                                };\r
+            _commandWorker.Start();\r
+        }\r
+\r
+        void CommandsManager_CommandWorker()\r
+        {\r
+            try\r
+            {\r
+                while (true)\r
+                {\r
+                    if (CommandQueue.Count == 0)\r
+                        CommandQueued.WaitOne();\r
+                    KeyValuePair<string, ThreadStart> todo;\r
+                    lock (CommandQueue)\r
+                    {\r
+                        if (CommandQueue.Count == 0)\r
+                        {\r
+                            continue;\r
+                        }\r
+                        todo = CommandQueue.Dequeue();\r
+                    }\r
+                    try\r
+                    {\r
+\r
+                        todo.Value();\r
+                    }\r
+                    catch (ThreadAbortException ex)\r
+                    {\r
+                        break;\r
+                    }\r
+                    catch (Exception ex)\r
+                    {\r
+                        instance.TabConsole.DisplayNotificationInChat(\r
+                            string.Format("Command error: {0} \n{1} {2} ", todo.Key, ex.Message, ex.StackTrace));\r
+                    }\r
+                }\r
+            }\r
+            finally\r
+            {\r
+                CommandQueue.Clear();\r
+                try\r
+                {\r
+                    CommandQueued.Close();\r
+                }\r
+                catch (Exception)\r
+                {\r
+                }\r
+            }\r
+        }\r
+\r
+        public void EnqueueCommand(string name, ThreadStart ts)\r
+        {\r
+            lock (CommandQueue)\r
+                CommandQueue.Enqueue(new KeyValuePair<string, ThreadStart>(name, ts));\r
+            CommandQueued.Set();\r
         }\r
 \r
         public IRadegastCommand AddCmd(string name, string desc, string usage, CommandExecuteDelegate executeDelegate)\r
@@ -158,27 +222,39 @@ namespace Radegast.Commands
             instance.TabConsole.DisplayNotificationInChat(str);\r
         }\r
 \r
-        public void ExecuteCommand(string cmd)\r
+        /// <summary>\r
+        /// Queues command for execution\r
+        /// </summary>\r
+        /// <param name="cmdline"></param>\r
+        public void ExecuteCommand(string cmdline)\r
         {\r
-            ExecuteCommand(WriteLine, cmd);\r
+            ExecuteCommand(this.WriteLine, cmdline);\r
         }\r
 \r
+        /// <summary>\r
+        /// Queues command for execution\r
+        /// </summary>\r
+        /// <param name="WriteLine"></param>\r
+        /// <param name="cmdline"></param>\r
         public void ExecuteCommand(ConsoleWriteLine WriteLine, string cmdline)\r
         {\r
+            EnqueueCommand(cmdline, () => ExecuteCommandForeground(WriteLine, cmdline));\r
+        }\r
+\r
+        public void ExecuteCommandForeground(ConsoleWriteLine WriteLine, string cmdline)\r
+        {\r
             if (cmdline == null) return;\r
             cmdline = cmdline.Trim();\r
+            List<ICommandInterpreter> interpretersLoadedLocal = new List<ICommandInterpreter>();\r
             lock (InterpretersLoaded)\r
-                foreach (ICommandInterpreter manager in InterpretersLoaded)\r
-                {\r
-                    if (manager.IsValidCommand(cmdline))\r
-                    {\r
-                        System.Threading.ThreadPool.QueueUserWorkItem((object state) =>\r
-                            {\r
-                                manager.ExecuteCommand(WriteLine, cmdline);\r
-                            });\r
-                        return;\r
-                    }\r
-                }\r
+                interpretersLoadedLocal.AddRange(InterpretersLoaded);\r
+            foreach (ICommandInterpreter manager in interpretersLoadedLocal)\r
+            {\r
+                if (!manager.IsValidCommand(cmdline)) continue;\r
+                // the command is queued from outside\r
+                manager.ExecuteCommand(WriteLine, cmdline);\r
+                return;\r
+            }\r
 \r
             // our local impl\r
             while (cmdline.StartsWith(CmdPrefix))\r
@@ -189,29 +265,20 @@ namespace Radegast.Commands
             if (cmdline == "") return;\r
             string[] parsd = ParseArguments(cmdline);\r
             string cmd = parsd[0];\r
-            ExecuteCommand(WriteLine, cmd, SplitOff(parsd, 1));\r
-        }\r
-\r
-        private void ExecuteCommand(ConsoleWriteLine WriteLine, string cmd, string[] parms)\r
-        {\r
             IRadegastCommand cmdimpl;\r
             if (CommandsByName.TryGetValue(cmd.ToLower(), out cmdimpl))\r
             {\r
                 try\r
                 {\r
-                    System.Threading.ThreadPool.QueueUserWorkItem((object state) =>\r
-                        {\r
-                            cmdimpl.Execute(cmd, parms, WriteLine);\r
-                        });\r
+                    cmdimpl.Execute(cmd, SplitOff(parsd, 1), WriteLine);\r
                 }\r
                 catch (Exception ex)\r
                 {\r
-                    WriteLine("Execute command error: {0} {1}\n{2} {3}",\r
-                        cmd, string.Join(" ", parms), ex.Message, ex.StackTrace);\r
-                }\r
+                    WriteLine("Command error: {0} \n{1} {2} ", cmdline, ex.Message, ex.StackTrace);\r
+                } \r
                 return;\r
             }\r
-            WriteLine("Command no found {0}", cmd);\r
+            WriteLine("Command not found {0}", cmd);\r
         }\r
 \r
         public void Dispose()\r
@@ -241,6 +308,9 @@ namespace Radegast.Commands
                 InterpretersLoaded.Clear();\r
             }\r
             CommandsByName.Clear();\r
+            _commandWorker.Abort();\r
+            _commandWorker = null;\r
+            CommandQueued = null;\r
         }\r
 \r
         public void StartInterpreter(RadegastInstance inst)\r
@@ -353,7 +423,7 @@ namespace Radegast.Commands
                     if (manager.IsValidCommand(msg)) return true;\r
             msg = msg.Trim();\r
             if (!msg.StartsWith(CmdPrefix)) return false;\r
-            msg = msg.Substring(2);\r
+            msg = msg.Substring(CmdPrefix.Length);\r
             return CommandExists(ParseArguments(msg)[0]);\r
         }\r
 \r
index 65aaccd..0842a67 100644 (file)
@@ -36,7 +36,9 @@ namespace Radegast.Commands
 {\r
     public class ThreadCommand : IRadegastCommand\r
     {\r
-        readonly List<Thread> _commandThreads = new List<Thread>();\r
+        private List<Thread> _listed = null;\r
+        List<Thread> _commandThreads = new List<Thread>();\r
+        Queue<KeyValuePair<string, ThreadStart>> _commandQueue { get { return instance.CommandsManager.CommandQueue; } }\r
         private RadegastInstance instance;\r
         public string Name\r
         {\r
@@ -56,6 +58,8 @@ namespace Radegast.Commands
         public void StartCommand(RadegastInstance inst)\r
         {\r
             instance = inst;\r
+            instance.CommandsManager.CommandsByName.Add("kill", this);\r
+            instance.CommandsManager.CommandsByName.Add("threads", this);\r
         }\r
 \r
         public void Dispose()\r
@@ -76,42 +80,136 @@ namespace Radegast.Commands
         public void Execute(string threadCmd, string[] cmdArgs, ConsoleWriteLine WriteLine)\r
         {\r
             string args = String.Join(" ", cmdArgs);\r
+            if (threadCmd == "kill")\r
+            {\r
+                if (_listed == null)\r
+                {\r
+                    WriteLine("Must load the threadlist Using: thread");\r
+                    return;\r
+                }\r
+                lock (_listed)\r
+                {\r
+                    if (_listed.Count == 0)\r
+                    {\r
+                        WriteLine("No threaded commands to kill.");\r
+                    }\r
+                    else\r
+                    {\r
+                        WriteLine("Killing all threaded commands");\r
+                        int found = 0;\r
+                        foreach (var cmd in _listed)\r
+                        {\r
+                            try\r
+                            {\r
+                                if (cmd.IsAlive)\r
+                                {\r
+                                    found++;\r
+                                    cmd.Abort();\r
+                                }\r
+                            }\r
+                            catch (Exception)\r
+                            {\r
+                            }\r
+                        }\r
+                        WriteLine("Killed {0} thread{1}.", found, found == 1 ? "" : "s");\r
+                        _listed = null;\r
+\r
+                    }\r
+                }\r
+                lock (_commandQueue)\r
+                {\r
+                    int commandQueueCount = _commandQueue.Count;\r
+                    if (commandQueueCount == 0)\r
+                    {\r
+                        WriteLine("No queued commands.");\r
+                    }\r
+                    else\r
+                    {\r
+                        _commandQueue.Clear();\r
+                        WriteLine("Clear queued commands: " + commandQueueCount);\r
+                    }\r
+                }\r
+                return;\r
+            }\r
+\r
+            //cleared each time becasue the list will change \r
+            _listed = null;\r
             if (args == string.Empty)\r
             {\r
-                lock (_commandThreads)\r
+                lock (_commandThreads) _listed = new List<Thread>(_commandThreads);\r
+                if (_listed.Count == 0)\r
+                {\r
+                    WriteLine("No threaded commands.");\r
+                }\r
+                else\r
                 {\r
-                    if (_commandThreads.Count == 0)\r
+                    int found = _listed.Count;\r
+                    WriteLine("Listing {0} thread{1}.", found, found == 1 ? "" : "s");\r
+                    for (int i = 0; i < _listed.Count; i++)\r
                     {\r
-                        WriteLine("No threaded commands.");\r
+                        WriteLine(" * {0}: {1}", i, _listed[i].Name);\r
+                    }\r
+                }\r
+                lock (_commandQueue)\r
+                {\r
+                    if (_commandQueue.Count == 0)\r
+                    {\r
+                        WriteLine("No queued commands.");\r
                     }\r
                     else\r
                     {\r
-                        WriteLine("Threaded command list");\r
-                        foreach (Thread thr in _commandThreads)\r
+                        WriteLine("Queued commands: {0}", _commandQueue.Count);\r
+                        foreach (var c in _commandQueue)\r
                         {\r
-                            WriteLine(" * {0}", thr.Name);\r
+                            WriteLine(" Q: {0}", c.Key);\r
                         }\r
-                        int found = _commandThreads.Count;\r
-                        WriteLine("Listed {0} threads{1}.", found, found == 1 ? "" : "s");\r
                     }\r
                 }\r
                 return;\r
             }\r
+            string name = string.Format("ThreadCommand {0}: {1}", DateTime.Now, args);\r
             Thread thread = new Thread(() =>\r
                                            {\r
                                                try\r
                                                {\r
                                                    WriteLine("Started command: {0}", args);\r
-                                                   instance.CommandsManager.ExecuteCommand(WriteLine, args);\r
+                                                   instance.CommandsManager.ExecuteCommandForeground(WriteLine, args);\r
+                                               }\r
+                                               catch (Exception e)\r
+                                               {\r
+                                                   WriteLine("Exception: " + name + "\n" + e);\r
                                                }\r
                                                finally\r
                                                {\r
                                                    WriteLine("Done with {0}", args);\r
                                                    _commandThreads.Remove(Thread.CurrentThread);\r
                                                }\r
-                                           }) { Name = "ThreadCommand for " + args };\r
+                                           }) {Name = name};\r
             lock (_commandThreads) _commandThreads.Add(thread);\r
             thread.Start();\r
         }\r
     }\r
+\r
+    public class PauseCommand : RadegastCommand\r
+    {\r
+        public PauseCommand(RadegastInstance inst)\r
+            : base(inst)\r
+        {\r
+            Name = "pause";\r
+            Description = "pauses command script execution";\r
+            Usage = "pause [seconds]";\r
+        }\r
+        public override void Execute(string name, string[] cmdArgs, ConsoleWriteLine WriteLine)\r
+        {\r
+            float time;\r
+            if (cmdArgs.Length == 0 || !float.TryParse(cmdArgs[0], out time))\r
+                WriteLine(Usage);\r
+            else\r
+            {\r
+                WriteLine("pausing for " + time);\r
+                Thread.Sleep((int)(time * 1000));\r
+                WriteLine("paused for " + time);\r
+            }\r
+        }\r
+    }\r
 }
\ No newline at end of file