//\r
using System;\r
using System.Collections.Generic;\r
+using System.Threading;\r
using OpenMetaverse;\r
\r
namespace Radegast.Commands\r
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
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
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
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
InterpretersLoaded.Clear();\r
}\r
CommandsByName.Clear();\r
+ _commandWorker.Abort();\r
+ _commandWorker = null;\r
+ CommandQueued = null;\r
}\r
\r
public void StartInterpreter(RadegastInstance inst)\r
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
{\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
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
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