From f2cbc48a9e704da8e86ed659437c1e338e212c50 Mon Sep 17 00:00:00 2001 From: Tedd Hansen Date: Sat, 6 Dec 2008 03:28:34 +0000 Subject: [PATCH] GUI for launching grids. Early version, but should work fine. Will execute all OpenSim services redirect their input/output/errors to the selected "GUI module". This version has following "GUI modules": * Windows Forms * Windows Service (doesn't work yet) * Console * TCP daemon This means that OpenSim can now run in a single console for those who want that. Console functionallity is not too rich yet, but code/framework is there... more to come. :) --- OpenSim/Tools/OpenSim.GridLaunch/App.config | 40 + .../Tools/OpenSim.GridLaunch/AppExecutor.cs | 247 +++++ .../OpenSim.GridLaunch/AppExecutor_AsyncIO.cs | 85 ++ .../OpenSim.GridLaunch/AppExecutor_Thread.cs | 187 ++++ .../OpenSim.GridLaunch/CommandProcessor.cs | 76 ++ .../OpenSim.GridLaunch/GUI/Console/Console.cs | 122 +++ OpenSim/Tools/OpenSim.GridLaunch/GUI/IGUI.cs | 12 + .../OpenSim.GridLaunch/GUI/Network/Client.cs | 113 +++ .../OpenSim.GridLaunch/GUI/Network/TCPD.cs | 231 +++++ .../OpenSim.GridLaunch/GUI/Service/Service.cs | 65 ++ .../GUI/WinForm/OpenSim Bottom Border.png | Bin 0 -> 163 bytes .../GUI/WinForm/OpenSim Right Border.png | Bin 0 -> 545 bytes .../GUI/WinForm/OpenSim.png | Bin 0 -> 44571 bytes .../GUI/WinForm/ProcessPanel.Designer.cs | 224 +++++ .../GUI/WinForm/ProcessPanel.cs | 288 ++++++ .../GUI/WinForm/ProcessPanel.resx | 882 ++++++++++++++++++ .../GUI/WinForm/ucAppWindow.Designer.cs | 72 ++ .../GUI/WinForm/ucAppWindow.cs | 63 ++ .../GUI/WinForm/ucAppWindow.resx | 120 +++ .../GUI/WinForm/ucInputField.Designer.cs | 77 ++ .../GUI/WinForm/ucInputField.cs | 97 ++ .../GUI/WinForm/ucInputField.resx | 120 +++ .../GUI/WinForm/ucLogWindow.Designer.cs | 62 ++ .../GUI/WinForm/ucLogWindow.cs | 54 ++ .../GUI/WinForm/ucLogWindow.resx | 120 +++ .../OpenSim.GridLaunch.csproj | 126 +++ .../OpenSim.GridLaunch/OpenSim.GridLaunch.ini | 3 + .../OpenSim.GridLaunch/OpenSim.GridLaunch.sln | 20 + OpenSim/Tools/OpenSim.GridLaunch/Program.cs | 245 +++++ .../Properties/AssemblyInfo.cs | 63 ++ .../Properties/Resources.Designer.cs | 84 ++ .../Properties/Resources.resx | 130 +++ OpenSim/Tools/OpenSim.GridLaunch/Settings.cs | 181 ++++ .../OpenSim.GridLaunch/log4netAppender.cs | 65 ++ 34 files changed, 4274 insertions(+) create mode 100644 OpenSim/Tools/OpenSim.GridLaunch/App.config create mode 100644 OpenSim/Tools/OpenSim.GridLaunch/AppExecutor.cs create mode 100644 OpenSim/Tools/OpenSim.GridLaunch/AppExecutor_AsyncIO.cs create mode 100644 OpenSim/Tools/OpenSim.GridLaunch/AppExecutor_Thread.cs create mode 100644 OpenSim/Tools/OpenSim.GridLaunch/CommandProcessor.cs create mode 100644 OpenSim/Tools/OpenSim.GridLaunch/GUI/Console/Console.cs create mode 100644 OpenSim/Tools/OpenSim.GridLaunch/GUI/IGUI.cs create mode 100644 OpenSim/Tools/OpenSim.GridLaunch/GUI/Network/Client.cs create mode 100644 OpenSim/Tools/OpenSim.GridLaunch/GUI/Network/TCPD.cs create mode 100644 OpenSim/Tools/OpenSim.GridLaunch/GUI/Service/Service.cs create mode 100644 OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/OpenSim Bottom Border.png create mode 100644 OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/OpenSim Right Border.png create mode 100644 OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/OpenSim.png create mode 100644 OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ProcessPanel.Designer.cs create mode 100644 OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ProcessPanel.cs create mode 100644 OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ProcessPanel.resx create mode 100644 OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ucAppWindow.Designer.cs create mode 100644 OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ucAppWindow.cs create mode 100644 OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ucAppWindow.resx create mode 100644 OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ucInputField.Designer.cs create mode 100644 OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ucInputField.cs create mode 100644 OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ucInputField.resx create mode 100644 OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ucLogWindow.Designer.cs create mode 100644 OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ucLogWindow.cs create mode 100644 OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ucLogWindow.resx create mode 100644 OpenSim/Tools/OpenSim.GridLaunch/OpenSim.GridLaunch.csproj create mode 100644 OpenSim/Tools/OpenSim.GridLaunch/OpenSim.GridLaunch.ini create mode 100644 OpenSim/Tools/OpenSim.GridLaunch/OpenSim.GridLaunch.sln create mode 100644 OpenSim/Tools/OpenSim.GridLaunch/Program.cs create mode 100644 OpenSim/Tools/OpenSim.GridLaunch/Properties/AssemblyInfo.cs create mode 100644 OpenSim/Tools/OpenSim.GridLaunch/Properties/Resources.Designer.cs create mode 100644 OpenSim/Tools/OpenSim.GridLaunch/Properties/Resources.resx create mode 100644 OpenSim/Tools/OpenSim.GridLaunch/Settings.cs create mode 100644 OpenSim/Tools/OpenSim.GridLaunch/log4netAppender.cs diff --git a/OpenSim/Tools/OpenSim.GridLaunch/App.config b/OpenSim/Tools/OpenSim.GridLaunch/App.config new file mode 100644 index 0000000000..1e53319b3b --- /dev/null +++ b/OpenSim/Tools/OpenSim.GridLaunch/App.config @@ -0,0 +1,40 @@ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OpenSim/Tools/OpenSim.GridLaunch/AppExecutor.cs b/OpenSim/Tools/OpenSim.GridLaunch/AppExecutor.cs new file mode 100644 index 0000000000..2c6ac31ac8 --- /dev/null +++ b/OpenSim/Tools/OpenSim.GridLaunch/AppExecutor.cs @@ -0,0 +1,247 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections; +using System.Diagnostics; +using System.IO; +using System.Reflection; +using System.Text; +using System.Threading; +using log4net; + +namespace OpenSim.GridLaunch +{ + internal partial class AppExecutor : IDisposable + { + // How long to wait for process to shut down by itself + private static readonly int shutdownWaitSeconds = 10; + + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + //private StreamWriter Input { get { return process.StandardInput; } } + //private StreamReader Output { get { return process.StandardOutput; } } + //private StreamReader Error { get { return process.StandardError; } } + + private StreamWriter Input { get; set; } + private StreamReader Output { get; set; } + private StreamReader Error { get; set; } + + private object processLock = new object(); + + private bool isRunning = false; + public bool IsRunning { get { return isRunning; } } + + private string file; + public string File { get { return file; } } + + Process process; + + public AppExecutor(string File) + { + file = File; + } + + #region Dispose of unmanaged resources + ~AppExecutor() + { + Dispose(); + } + private bool isDisposed = false; + public void Dispose() + { + if (!isDisposed) + { + isDisposed = true; + Stop(); + } + } + #endregion + + #region Start / Stop process + public void Start() + { + if (isDisposed) + throw new ApplicationException("Attempt to start process in Disposed instance of AppExecutor."); + // Stop before starting + Stop(); + + lock (processLock) + { + isRunning = true; + + m_log.InfoFormat("Starting \"{0}\".", file); + + // Start the process + process = new Process(); + process.StartInfo.FileName = file; + process.StartInfo.Arguments = ""; + process.StartInfo.CreateNoWindow = true; + process.StartInfo.UseShellExecute = false; + process.StartInfo.ErrorDialog = false; + process.EnableRaisingEvents = true; + + + // Redirect all standard input/output/errors + process.StartInfo.RedirectStandardInput = true; + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.RedirectStandardError = true; + + // Start process + process.Start(); + + Input = process.StandardInput; + Output = process.StandardOutput; + Error = process.StandardError; + + // Start data copying + timer_Start(); + + // We will flush manually + //Input.AutoFlush = false; + + } + } + + public void Stop() + { + // Shut down process + // We will ignore some exceptions here, against good programming practice... :) + + lock (processLock) + { + // Running? + if (!isRunning) + return; + isRunning = false; + + timer_Stop(); + + m_log.InfoFormat("Stopping \"{0}\".", file); + + // Send exit command to console + try + { + if (Input != null) + { + _writeLine(""); + _writeLine("exit"); + _writeLine("quit"); + // Wait for process to exit + process.WaitForExit(1000 * shutdownWaitSeconds); + } + } + catch (Exception ex) + { + m_log.ErrorFormat("Exeption asking \"{0}\" to shut down: {1}", file, ex.ToString()); + } + + try + { + // Forcefully kill it + if (process.HasExited != true) + process.Kill(); + } + catch (Exception ex) + { + m_log.ErrorFormat("Exeption killing \"{0}\": {1}", file, ex.ToString()); + } + + try + { + // Free resources + process.Close(); + } + catch (Exception ex) + { + m_log.ErrorFormat("Exeption freeing resources for \"{0}\": {1}", file, ex.ToString()); + } + + // Dispose of stream and process object + //SafeDisposeOf(Input); + //SafeDisposeOf(Output); + //SafeDisposeOf(Error); + Program.SafeDisposeOf(process); + } + + // Done stopping process + } + + #endregion + + #region Write to stdInput + public void Write(string Text) + { + // Lock so process won't shut down while we write, and that we won't write while proc is shutting down + lock (processLock) + { + _write(Text); + } + } + public void _write(string Text) + { + if (Input != null) + { + try + { + Input.Write(Text); + Input.Flush(); + } + catch (Exception ex) + { + m_log.ErrorFormat("Exeption sending text \"{0}\" to \"{1}\": {2}", file, Text, ex.ToString()); + } + + } + } + public void WriteLine(string Text) + { + // Lock so process won't shut down while we write, and that we won't write while proc is shutting down + lock (processLock) + { + _writeLine(Text); + } + } + public void _writeLine(string Text) + { + if (Input != null) + { + try + { + m_log.DebugFormat("\"{0}\": Sending: \"{1}\"", file, Text); + Input.WriteLine(Text); + Input.Flush(); + } + catch (Exception ex) + { + m_log.ErrorFormat("Exeption sending text \"{0}\" to \"{1}\": {2}", file, Text, ex.ToString()); + } + } + } + #endregion + + } +} diff --git a/OpenSim/Tools/OpenSim.GridLaunch/AppExecutor_AsyncIO.cs b/OpenSim/Tools/OpenSim.GridLaunch/AppExecutor_AsyncIO.cs new file mode 100644 index 0000000000..0d07226847 --- /dev/null +++ b/OpenSim/Tools/OpenSim.GridLaunch/AppExecutor_AsyncIO.cs @@ -0,0 +1,85 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace OpenSim.GridLaunch +{ + internal partial class AppExecutor + { + + + #region Start / Stop timer thread + private void timer_Start() + { + asyncReadOutput(); + asyncReadError(); + } + + private bool running = true; + private void timer_Stop() + { + running = false; + } + #endregion + + private byte[] readBufferOutput = new byte[4096]; + private byte[] readBufferError = new byte[4096]; + + private void asyncReadOutput() + { + if (running) + Output.BaseStream.BeginRead(readBufferOutput, 0, readBufferOutput.Length, asyncReadCallBackOutput, null); + } + private void asyncReadError() + { + if (running) + Error.BaseStream.BeginRead(readBufferError, 0, readBufferError.Length, asyncReadCallBackError, null); + } + + private void asyncReadCallBackOutput(IAsyncResult ar) + { + int len = Output.BaseStream.EndRead(ar); + Program.FireAppConsoleOutput(file, + System.Text.Encoding.ASCII.GetString(readBufferOutput, 0, len) + ); + + asyncReadOutput(); + } + private void asyncReadCallBackError(IAsyncResult ar) + { + int len = Error.BaseStream.EndRead(ar); + Program.FireAppConsoleError(file, + System.Text.Encoding.ASCII.GetString(readBufferError, 0, len) + ); + + asyncReadError(); + } + } +} diff --git a/OpenSim/Tools/OpenSim.GridLaunch/AppExecutor_Thread.cs b/OpenSim/Tools/OpenSim.GridLaunch/AppExecutor_Thread.cs new file mode 100644 index 0000000000..cd160f8c91 --- /dev/null +++ b/OpenSim/Tools/OpenSim.GridLaunch/AppExecutor_Thread.cs @@ -0,0 +1,187 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +//using System; +//using System.Collections; +//using System.Collections.Generic; +//using System.Reflection; +//using System.Text; +//using System.Threading; +//using log4net; + +//namespace OpenSim.GridLaunch +//{ +// internal class AppExecutor2 +// { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); +// private static readonly int consoleReadIntervalMilliseconds = 50; +// //private static readonly Timer readTimer = new Timer(readConsole, null, Timeout.Infinite, Timeout.Infinite); +// private static Thread timerThread; +// private static object timerThreadLock = new object(); + +// #region Start / Stop timer thread +// private static void timer_Start() +// { +// //readTimer.Change(0, consoleReadIntervalMilliseconds); +// lock (timerThreadLock) +// { +// if (timerThread == null) +// { +// m_log.Debug("Starting timer thread."); +// timerThread = new Thread(timerThreadLoop); +// timerThread.Name = "StdOutputStdErrorReadThread"; +// timerThread.IsBackground = true; +// timerThread.Start(); +// } +// } +// } +// private static void timer_Stop() +// { +// //readTimer.Change(Timeout.Infinite, Timeout.Infinite); +// lock (timerThreadLock) +// { +// if (timerThread != null) +// { +// m_log.Debug("Stopping timer thread."); +// try +// { +// if (timerThread.IsAlive) +// timerThread.Abort(); +// timerThread.Join(2000); +// timerThread = null; +// } +// catch (Exception ex) +// { +// m_log.Error("Exception stopping timer thread: " + ex.ToString()); +// } +// } +// } +// } +// #endregion + +// #region Timer read from consoles and fire event + +// private static void timerThreadLoop() +// { +// try +// { +// while (true) +// { +// readConsole(); +// Thread.Sleep(consoleReadIntervalMilliseconds); +// } +// } +// catch (ThreadAbortException) { } // Expected on thread shutdown +// } + +// private static void readConsole() +// { +// try +// { + +// // Lock so we don't collide with any startup or shutdown +// lock (Program.AppList) +// { +// foreach (AppExecutor app in new ArrayList(Program.AppList.Values)) +// { +// try +// { +// string txt = app.GetStdOutput(); +// // Fire event with received text +// if (!string.IsNullOrEmpty(txt)) +// Program.FireAppConsoleOutput(app.File, txt); +// } +// catch (Exception ex) +// { +// m_log.ErrorFormat("Exception reading standard output from \"{0}\": {1}", app.File, ex.ToString()); +// } +// try +// { +// string txt = app.GetStdError(); +// // Fire event with received text +// if (!string.IsNullOrEmpty(txt)) +// Program.FireAppConsoleOutput(app.File, txt); +// } +// catch (Exception ex) +// { +// m_log.ErrorFormat("Exception reading standard error from \"{0}\": {1}", app.File, ex.ToString()); +// } +// } +// } +// } +// finally +// { +// } +// } +// #endregion + + +// #region Read stdOutput and stdError +// public string GetStdOutput() +// { +// return GetStreamData(Output); +// } +// public string GetStdError() +// { +// return GetStreamData(Error); +// } + +// private static int num = 0; +// // Gets any data from StreamReader object, non-blocking +// private static string GetStreamData(StreamReader sr) +// { +// // Can't read? +// if (!sr.BaseStream.CanRead) +// return ""; + +// // Read a chunk +// //sr.BaseStream.ReadTimeout = 100; +// byte[] buffer = new byte[4096]; +// num++; +// Trace.WriteLine("Start read " + num); +// int len = sr.BaseStream.Read(buffer, 0, buffer.Length); +// Trace.WriteLine("End read " + num + ": " + len); + +// // Nothing? +// if (len <= 0) +// return ""; + +// // Return data +// StringBuilder sb = new StringBuilder(); +// sb.Append(System.Text.Encoding.ASCII.GetString(buffer, 0, len)); + +// //while (sr.Peek() >= 0) +// //{ +// // sb.Append(Convert.ToChar(sr.Read())); +// //} + +// return sb.ToString(); +// } +// #endregion + + +// } +//} diff --git a/OpenSim/Tools/OpenSim.GridLaunch/CommandProcessor.cs b/OpenSim/Tools/OpenSim.GridLaunch/CommandProcessor.cs new file mode 100644 index 0000000000..aca36e9abc --- /dev/null +++ b/OpenSim/Tools/OpenSim.GridLaunch/CommandProcessor.cs @@ -0,0 +1,76 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenSim.GridLaunch +{ + internal class CommandProcessor + { + public delegate void CommandLineDelegate(string application, string command, string arguments); + public event CommandLineDelegate CommandLine; + + public bool IsCommand(string cmd) + { + if (cmd.Trim().StartsWith("/")) + return true; + return false; + } + + public static readonly char[] cmdSplit = new char[] { ' ' }; + public bool Process(string app, string command) + { + // Only process commands + if (!IsCommand(command)) + return false; + + // Remove first / + command = command.Trim().Remove(0, 1); + + // Split cmd and args + string[] carg = command.Split(cmdSplit, 2); + if (carg.Length == 0) + return true; + + string cmd = carg[0]; // Command + string arg = ""; + if (carg.Length > 1) + arg = carg[1]; // Arguments + + // Do we have a command? + if (string.IsNullOrEmpty(cmd)) + return true; + + // All is fine + if (CommandLine != null) + CommandLine(app, cmd, arg); + return true; + } + + } +} diff --git a/OpenSim/Tools/OpenSim.GridLaunch/GUI/Console/Console.cs b/OpenSim/Tools/OpenSim.GridLaunch/GUI/Console/Console.cs new file mode 100644 index 0000000000..a04c9cfd60 --- /dev/null +++ b/OpenSim/Tools/OpenSim.GridLaunch/GUI/Console/Console.cs @@ -0,0 +1,122 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenSim.GridLaunch.GUI.Console +{ + internal class Console: IGUI + { + private List Apps = new List(); + public Console () + { + Program.AppCreated += Program_AppCreated; + Program.AppRemoved += Program_AppRemoved; + Program.AppConsoleOutput += Program_AppConsoleOutput; + Program.Command.CommandLine += Command_CommandLine; + } + + private string currentApp = ""; + private bool quitTyped = false; + void Command_CommandLine(string application, string command, string arguments) + { + + // If command is a number then someone might be trying to change console: /1, /2, etc. + int currentAppNum = 0; + if (int.TryParse(command, out currentAppNum)) + if (currentAppNum <= Apps.Count) + { + currentApp = Apps[currentAppNum - 1]; + System.Console.WriteLine("Changed console to app: " + currentApp); + } else + System.Console.WriteLine("Unable to change to app number: " + currentAppNum); + + // Has user typed quit? + if (command.ToLower() == "quit") + quitTyped = true; + + // Has user typed /list? + if (command.ToLower() == "list") + { + System.Console.WriteLine("/0 Log console"); + for (int i = 1; i <= Apps.Count; i++) + { + System.Console.WriteLine(string.Format("/{0} {1}", i, Apps[i - 1])); + } + } + } + #region Module Start / Stop + public void StartGUI() + { + // Console start + System.Console.WriteLine("Console GUI"); + System.Console.WriteLine("Use commands /0, /1, /2, etc to switch between applications."); + System.Console.WriteLine("Type /list for list of applications."); + System.Console.WriteLine("Anything that doesn't start with a / will be sent to selected application"); + System.Console.WriteLine("type /quit to exit"); + + + while (quitTyped == false) + { + string line = System.Console.ReadLine().TrimEnd("\r\n".ToCharArray()); + Program.Write(currentApp, line); + } + // We are done + System.Console.WriteLine("Console exit."); + } + + public void StopGUI() + { + // Console stop + } + #endregion + + #region GridLaunch Events + void Program_AppCreated(string App) + { + System.Console.WriteLine("Started: " + App); + if (!Apps.Contains(App)) + Apps.Add(App); + } + + void Program_AppRemoved(string App) + { + System.Console.WriteLine("Stopped: " + App); + if (Apps.Contains(App)) + Apps.Remove(App); + } + + void Program_AppConsoleOutput(string App, string Text) + { + System.Console.Write(App + ": " + Text); + } + #endregion + + + } +} diff --git a/OpenSim/Tools/OpenSim.GridLaunch/GUI/IGUI.cs b/OpenSim/Tools/OpenSim.GridLaunch/GUI/IGUI.cs new file mode 100644 index 0000000000..45d8af76aa --- /dev/null +++ b/OpenSim/Tools/OpenSim.GridLaunch/GUI/IGUI.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenSim.GridLaunch.GUI +{ + public interface IGUI + { + void StartGUI(); + void StopGUI(); + } +} diff --git a/OpenSim/Tools/OpenSim.GridLaunch/GUI/Network/Client.cs b/OpenSim/Tools/OpenSim.GridLaunch/GUI/Network/Client.cs new file mode 100644 index 0000000000..19b27e48f8 --- /dev/null +++ b/OpenSim/Tools/OpenSim.GridLaunch/GUI/Network/Client.cs @@ -0,0 +1,113 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.Net.Sockets; +using System.Text; +using System.Text.RegularExpressions; + +namespace OpenSim.GridLaunch.GUI.Network +{ + internal class Client + { + public TcpClient tcpClient; + private byte[] readBuffer = new byte[4096]; + private byte[] writeBuffer; + private TCPD tcp; + private string inputData = ""; + private object inputDataLock = new object(); + public Client(TCPD _tcp, TcpClient Client) + { + tcp = _tcp; + tcpClient = Client; + asyncReadStart(); + Write("OpenSim TCP Console GUI"); + Write("Use commands /0, /1, /2, etc to switch between applications."); + Write("Type /list for list of applications."); + Write("Anything that doesn't start with a / will be sent to selected application"); + Write("type /quit to exit"); + + } + + private void asyncReadStart() + { + tcpClient.GetStream().BeginRead(readBuffer, 0, readBuffer.Length, asyncReadCallBack, null); + } + + //private Regex LineExtractor = new Regex("^(.*)$") + private void asyncReadCallBack(IAsyncResult ar) + { + try + { + // Read data + int len = tcpClient.GetStream().EndRead(ar); + + // Send it to app + string newData = System.Text.Encoding.ASCII.GetString(readBuffer, 0, len); + //lock (inputDataLock) + //{ + inputData += newData; + if (newData.Contains("\n")) + SendInputLines(); + //} + + // Start it again + asyncReadStart(); + } + catch + { + // TODO: Remove client when we get exception + // Temp patch: if exception we don't call asyncReadStart() + } + } + + private void SendInputLines() + { + StringBuilder line = new StringBuilder(); + foreach (char c in inputData) + { + if (c == 13) + continue; + if (c == 10) + { + Program.WriteLine(tcp.currentApp, line.ToString()); + line = new StringBuilder(); + continue; + } + line.Append(c); + } + // We'll keep whatever is left over + inputData = line.ToString(); + } + + public void Write(string Text) + { + writeBuffer = Encoding.ASCII.GetBytes(Text); + tcpClient.GetStream().Write(writeBuffer, 0, writeBuffer.Length); + } + } +} diff --git a/OpenSim/Tools/OpenSim.GridLaunch/GUI/Network/TCPD.cs b/OpenSim/Tools/OpenSim.GridLaunch/GUI/Network/TCPD.cs new file mode 100644 index 0000000000..5524e2168a --- /dev/null +++ b/OpenSim/Tools/OpenSim.GridLaunch/GUI/Network/TCPD.cs @@ -0,0 +1,231 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Net; +using System.Net.Sockets; +using System.Reflection; +using System.Text; +using System.Threading; +using log4net; + +namespace OpenSim.GridLaunch.GUI.Network +{ + public class TCPD : IGUI, IDisposable + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private List Clients = new List(); + + private readonly int defaultPort = 7998; + private TcpListener tcpListener; + private Thread listenThread; + private Thread clientThread; + + + private List Apps = new List(); + internal string currentApp = ""; + private bool quitTyped = false; + + public TCPD() + { + Program.AppCreated += Program_AppCreated; + Program.AppRemoved += Program_AppRemoved; + Program.AppConsoleOutput += Program_AppConsoleOutput; + Program.Command.CommandLine += Command_CommandLine; + + } + + ~TCPD() + { + Dispose(); + } + private bool isDisposed = false; + /// + ///Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + ///2 + public void Dispose() + { + if (isDisposed) + return; + isDisposed = true; + tcpd_Stop(); + } + + public void StartGUI() + { + // We are starting + tcpd_Start(); + } + + public void StopGUI() + { + // We are stopping + tcpd_Stop(); + } + + + #region GridLaunch Events + private void Command_CommandLine(string application, string command, string arguments) + { + // If command is a number then someone might be trying to change console: /1, /2, etc. + int currentAppNum = 0; + if (int.TryParse(command, out currentAppNum)) + if (currentAppNum <= Apps.Count) + { + currentApp = Apps[currentAppNum - 1]; + TCPWriteToAll("Changed console to app: " + currentApp + Environment.NewLine); + } + else + TCPWriteToAll("Unable to change to app number: " + currentAppNum + Environment.NewLine); + + // Has user typed quit? + if (command.ToLower() == "quit") + quitTyped = true; + + // Has user typed /list? + if (command.ToLower() == "list") + { + TCPWriteToAll("/0 Log console"); + for (int i = 1; i <= Apps.Count; i++) + { + TCPWriteToAll(string.Format("/{0} {1}", i, Apps[i - 1])); + } + } + + } + + void Program_AppCreated(string App) + { + TCPWriteToAll("Started: " + App); + if (!Apps.Contains(App)) + Apps.Add(App); + } + + void Program_AppRemoved(string App) + { + TCPWriteToAll("Stopped: " + App); + if (Apps.Contains(App)) + Apps.Remove(App); + } + + private void Program_AppConsoleOutput(string App, string Text) + { + TCPWriteToAll(App, Text); + } + + #endregion + + private void tcpd_Start() + { + listenThread = new Thread(new ThreadStart(ListenForClients)); + listenThread.Name = "TCPDThread"; + listenThread.IsBackground = true; + listenThread.Start(); + + while (!quitTyped) + { + Thread.Sleep(500); + } + + //clientThread = new Thread(new ThreadStart(ProcessClients)); + //clientThread.Name = "TCPClientThread"; + //clientThread.IsBackground = true; + ////clientThread.Start(); + + } + private void tcpd_Stop() + { + StopThread(listenThread); + StopThread(clientThread); + } + private void ListenForClients() + { + int Port = 0; + int.TryParse(Program.Settings["TCPPort"], out Port); + if (Port < 1) + Port = defaultPort; + + m_log.Info("Starting TCP Server on port " + Port); + this.tcpListener = new TcpListener(IPAddress.Any, Port); + + this.tcpListener.Start(); + + while (true) + { + // Blocks until a client has connected to the server + TcpClient tcpClient = this.tcpListener.AcceptTcpClient(); + Client client = new Client(this, tcpClient); + + lock (Clients) + { + Clients.Add(client); + } + System.Threading.Thread.Sleep(500); + } + } + + private static void StopThread(Thread t) + { + if (t != null) + { + m_log.Debug("Stopping thread " + t.Name); + try + { + if (t.IsAlive) + t.Abort(); + t.Join(2000); + t = null; + } + catch (Exception ex) + { + m_log.Error("Exception stopping thread: " + ex.ToString()); + } + } + } + + private void TCPWriteToAll(string app, string text) + { + TCPWriteToAll(text); + } + private void TCPWriteToAll(string text) + { + foreach (Client c in new ArrayList(Clients)) + { + try + { + c.Write(text); + } catch (Exception ex) + { + m_log.Error("Exception writing to TCP: " + ex.ToString()); + } + } + } + + } +} diff --git a/OpenSim/Tools/OpenSim.GridLaunch/GUI/Service/Service.cs b/OpenSim/Tools/OpenSim.GridLaunch/GUI/Service/Service.cs new file mode 100644 index 0000000000..c6fd501a0c --- /dev/null +++ b/OpenSim/Tools/OpenSim.GridLaunch/GUI/Service/Service.cs @@ -0,0 +1,65 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.ServiceProcess; +using System.Text; +using OpenSim.GridLaunch.GUI; + +namespace OpenSim.GridLaunch +{ + internal class Service: ServiceBase, IGUI + { + private ServiceBase[] ServicesToRun; + public Service() + { + ServicesToRun = new ServiceBase[] {this}; + } + + public void StartGUI() + { + ServiceBase.Run(ServicesToRun); + } + + public void StopGUI() + { + // Nothing + } + + protected override void OnStart(string[] args) + { + // Command line arguments override settings + Program.Settings.ParseCommandArguments(args); + } + + protected override void OnStop() + { + Program.Shutdown(); + } + + } +} \ No newline at end of file diff --git a/OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/OpenSim Bottom Border.png b/OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/OpenSim Bottom Border.png new file mode 100644 index 0000000000000000000000000000000000000000..b3594b68007837ee38e4897e260909f2d022d629 GIT binary patch literal 163 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx1SBVv2j2ryoCO|{#S9F5he4R}c>anMkc#3U zcPEB*=VV?2IV|apzK#qG8~eHcB(ehe3dtTpz6=aiY77hwEes65fIEak75uV&(eSm?1X&$4zcC6%Upg4o4tDnm{r-UW|5$YwU literal 0 HcmV?d00001 diff --git a/OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/OpenSim Right Border.png b/OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/OpenSim Right Border.png new file mode 100644 index 0000000000000000000000000000000000000000..8b03281febce2628e0bda720b2554df2589d1eb9 GIT binary patch literal 545 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 IsXO5Q4 + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ProcessPanel)); + this.tabControl1 = new System.Windows.Forms.TabControl(); + this.tabLogs = new System.Windows.Forms.TabPage(); + this.btnShutdown = new System.Windows.Forms.Button(); + this.pictureBox2 = new System.Windows.Forms.PictureBox(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.pictureBox3 = new System.Windows.Forms.PictureBox(); + this.tabSettings = new System.Windows.Forms.TabPage(); + this.cblStartupComponents = new System.Windows.Forms.CheckedListBox(); + this.gbStartupComponents = new System.Windows.Forms.GroupBox(); + this.btnSave = new System.Windows.Forms.Button(); + this.ucLogWindow1 = new OpenSim.GridLaunch.GUI.WinForm.ucLogWindow(); + this.label1 = new System.Windows.Forms.Label(); + this.tabControl1.SuspendLayout(); + this.tabLogs.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox2)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox3)).BeginInit(); + this.tabSettings.SuspendLayout(); + this.gbStartupComponents.SuspendLayout(); + this.SuspendLayout(); + // + // tabControl1 + // + this.tabControl1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.tabControl1.Controls.Add(this.tabSettings); + this.tabControl1.Controls.Add(this.tabLogs); + this.tabControl1.Location = new System.Drawing.Point(-1, 123); + this.tabControl1.Name = "tabControl1"; + this.tabControl1.SelectedIndex = 0; + this.tabControl1.Size = new System.Drawing.Size(632, 275); + this.tabControl1.TabIndex = 0; + // + // tabLogs + // + this.tabLogs.Controls.Add(this.ucLogWindow1); + this.tabLogs.Location = new System.Drawing.Point(4, 22); + this.tabLogs.Name = "tabLogs"; + this.tabLogs.Padding = new System.Windows.Forms.Padding(3); + this.tabLogs.Size = new System.Drawing.Size(624, 249); + this.tabLogs.TabIndex = 0; + this.tabLogs.Text = "Logs"; + this.tabLogs.UseVisualStyleBackColor = true; + // + // btnShutdown + // + this.btnShutdown.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.btnShutdown.Location = new System.Drawing.Point(542, 400); + this.btnShutdown.Name = "btnShutdown"; + this.btnShutdown.Size = new System.Drawing.Size(75, 23); + this.btnShutdown.TabIndex = 1; + this.btnShutdown.Text = "Shutdown"; + this.btnShutdown.UseVisualStyleBackColor = true; + this.btnShutdown.Click += new System.EventHandler(this.btnShutdown_Click); + // + // pictureBox2 + // + this.pictureBox2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.pictureBox2.Image = ((System.Drawing.Image)(resources.GetObject("pictureBox2.Image"))); + this.pictureBox2.Location = new System.Drawing.Point(585, -1); + this.pictureBox2.Name = "pictureBox2"; + this.pictureBox2.Size = new System.Drawing.Size(46, 124); + this.pictureBox2.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage; + this.pictureBox2.TabIndex = 3; + this.pictureBox2.TabStop = false; + // + // pictureBox1 + // + this.pictureBox1.Image = ((System.Drawing.Image)(resources.GetObject("pictureBox1.Image"))); + this.pictureBox1.Location = new System.Drawing.Point(-1, -1); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(586, 124); + this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize; + this.pictureBox1.TabIndex = 2; + this.pictureBox1.TabStop = false; + // + // pictureBox3 + // + this.pictureBox3.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.pictureBox3.Image = global::OpenSim.GridLaunch.Properties.Resources.OpenSim_Bottom_Border; + this.pictureBox3.Location = new System.Drawing.Point(-1, 120); + this.pictureBox3.Name = "pictureBox3"; + this.pictureBox3.Size = new System.Drawing.Size(632, 310); + this.pictureBox3.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage; + this.pictureBox3.TabIndex = 4; + this.pictureBox3.TabStop = false; + // + // tabSettings + // + this.tabSettings.Controls.Add(this.label1); + this.tabSettings.Controls.Add(this.btnSave); + this.tabSettings.Controls.Add(this.gbStartupComponents); + this.tabSettings.Location = new System.Drawing.Point(4, 22); + this.tabSettings.Name = "tabSettings"; + this.tabSettings.Padding = new System.Windows.Forms.Padding(3); + this.tabSettings.Size = new System.Drawing.Size(624, 249); + this.tabSettings.TabIndex = 1; + this.tabSettings.Text = "Settings"; + this.tabSettings.UseVisualStyleBackColor = true; + // + // cblStartupComponents + // + this.cblStartupComponents.CheckOnClick = true; + this.cblStartupComponents.FormattingEnabled = true; + this.cblStartupComponents.Location = new System.Drawing.Point(6, 19); + this.cblStartupComponents.Name = "cblStartupComponents"; + this.cblStartupComponents.Size = new System.Drawing.Size(202, 109); + this.cblStartupComponents.TabIndex = 0; + // + // gbStartupComponents + // + this.gbStartupComponents.Controls.Add(this.cblStartupComponents); + this.gbStartupComponents.Location = new System.Drawing.Point(9, 6); + this.gbStartupComponents.Name = "gbStartupComponents"; + this.gbStartupComponents.Size = new System.Drawing.Size(214, 136); + this.gbStartupComponents.TabIndex = 1; + this.gbStartupComponents.TabStop = false; + this.gbStartupComponents.Text = "Startup components"; + // + // btnSave + // + this.btnSave.Location = new System.Drawing.Point(9, 148); + this.btnSave.Name = "btnSave"; + this.btnSave.Size = new System.Drawing.Size(92, 23); + this.btnSave.TabIndex = 2; + this.btnSave.Text = "Save settings"; + this.btnSave.UseVisualStyleBackColor = true; + this.btnSave.Click += new System.EventHandler(this.btnSave_Click); + // + // ucLogWindow1 + // + this.ucLogWindow1.Dock = System.Windows.Forms.DockStyle.Fill; + this.ucLogWindow1.Location = new System.Drawing.Point(3, 3); + this.ucLogWindow1.Name = "ucLogWindow1"; + this.ucLogWindow1.Size = new System.Drawing.Size(618, 243); + this.ucLogWindow1.TabIndex = 0; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(108, 149); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(259, 13); + this.label1.TabIndex = 3; + this.label1.Text = "* You have to restart app before changes take effect."; + // + // ProcessPanel + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(629, 428); + this.Controls.Add(this.pictureBox2); + this.Controls.Add(this.pictureBox1); + this.Controls.Add(this.btnShutdown); + this.Controls.Add(this.tabControl1); + this.Controls.Add(this.pictureBox3); + this.Name = "ProcessPanel"; + this.Text = "OpenSim GUI alpha"; + this.Load += new System.EventHandler(this.ProcessPanel_Load); + this.tabControl1.ResumeLayout(false); + this.tabLogs.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox2)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox3)).EndInit(); + this.tabSettings.ResumeLayout(false); + this.tabSettings.PerformLayout(); + this.gbStartupComponents.ResumeLayout(false); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TabControl tabControl1; + private System.Windows.Forms.TabPage tabLogs; + private System.Windows.Forms.Button btnShutdown; + private ucLogWindow ucLogWindow1; + private System.Windows.Forms.PictureBox pictureBox1; + private System.Windows.Forms.PictureBox pictureBox2; + private System.Windows.Forms.PictureBox pictureBox3; + private System.Windows.Forms.TabPage tabSettings; + private System.Windows.Forms.GroupBox gbStartupComponents; + private System.Windows.Forms.CheckedListBox cblStartupComponents; + private System.Windows.Forms.Button btnSave; + private System.Windows.Forms.Label label1; + + } +} \ No newline at end of file diff --git a/OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ProcessPanel.cs b/OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ProcessPanel.cs new file mode 100644 index 0000000000..dbf97d6910 --- /dev/null +++ b/OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ProcessPanel.cs @@ -0,0 +1,288 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Diagnostics; +using System.Drawing; +using System.Text; +using System.Windows.Forms; + +namespace OpenSim.GridLaunch.GUI.WinForm +{ + public partial class ProcessPanel : Form, IGUI + { + public ProcessPanel() + { + Application.EnableVisualStyles(); + //Application.SetCompatibleTextRenderingDefault(false); + + InitializeComponent(); + Program.AppCreated += Program_AppCreated; + Program.AppRemoved += Program_AppRemoved; + Program.AppConsoleOutput += Program_AppConsoleOutput; + Program.AppConsoleError += Program_AppConsoleError; + log4netAppender.LogLine += log4netAppender_LogLine; + } + + #region Module Start / Stop + public void StartGUI() + { + Application.Run(this); + } + + public void StopGUI() + { + this.Close(); + } + #endregion + + #region Main log tab + void log4netAppender_LogLine(Color color, string LogText) + { + ucLogWindow1.Write(color, LogText); + } + #endregion + + #region Form events + private void btnShutdown_Click(object sender, EventArgs e) + { + Program.Shutdown(); + } + #endregion + + #region GridLaunch Events + public delegate void Program_AppCreatedDelegate(string App); + public void Program_AppCreated(string App) + { + if (this.InvokeRequired) { + this.Invoke(new Program_AppCreatedDelegate(Program_AppCreated), App); + return; + } + + Trace.WriteLine("Start: " + App); + + // Do we already have app window for that app? + if (AppWindow_Get(App) != null) + return; + + // New log window + ucAppWindow aw = new ucAppWindow(); + // New tab page + TabPage tp = new TabPage(App); + // Add log window into tab page + tp.Controls.Add(aw); + // Add tab page into tab control + tabControl1.TabPages.Add(tp); + // Add it all to our internal list + AppWindow_Add(App, aw); + // Hook up events + aw.LineEntered += AppWindow_LineEntered; + + // Fill log window fully inside tab page + aw.Dock = DockStyle.Fill; + } + + + public delegate void Program_AppRemovedDelegate(string App); + public void Program_AppRemoved(string App) + { + if (this.InvokeRequired) { + this.Invoke(new Program_AppRemovedDelegate(Program_AppRemoved), App); + return; + } + + Trace.WriteLine("Stop: " + App); + + // Get app window + ucAppWindow aw = AppWindow_Get(App); + if (aw == null) + return; + + // Get its tab page + TabPage tp = aw.Parent as TabPage; + + if (tp != null) + { + // Remove tab page from tab control + tabControl1.TabPages.Remove(tp); + // Remove app window from tab + tp.Controls.Remove(aw); + } + + // Dispose of app window + aw.Dispose(); + + // Dispose of tab page + if (tp != null) + tp.Dispose(); + + // Remove from our internal list + AppWindow_Remove(App); + } + + + public delegate void Program_AppConsoleOutputDelegate(string App, string LogText); + void Program_AppConsoleOutput(string App, string LogText) + { + if (this.InvokeRequired) + { + this.Invoke(new Program_AppConsoleOutputDelegate(Program_AppConsoleOutput), App, LogText); + return; + } + + // Get app window + ucAppWindow aw = AppWindow_Get(App); + // Write text to it + if (aw != null) + aw.Write(System.Drawing.Color.Black, LogText); + } + + public delegate void Program_AppConsoleErrorDelegate(string App, string LogText); + void Program_AppConsoleError(string App, string LogText) + { + if (this.InvokeRequired) { + this.Invoke(new Program_AppConsoleErrorDelegate(Program_AppConsoleError), App, LogText); + return; + } + + // Get app window + ucAppWindow aw = AppWindow_Get(App); + // Write text to it + if (aw != null) + aw.Write(System.Drawing.Color.Red, LogText); + + } + #endregion + + #region App Window events + private void AppWindow_LineEntered(ucAppWindow AppWindow, string LogText) + { + Program.WriteLine(AppWindow_Get(AppWindow), LogText); + } + #endregion + + private void ProcessPanel_Load(object sender, EventArgs e) + { + string[] arr = new string[Program.Settings.Components.Keys.Count]; + Program.Settings.Components.Keys.CopyTo(arr, 0); + cblStartupComponents.Items.AddRange(arr); + + // Now correct all check states + for (int i = 0; i < cblStartupComponents.Items.Count; i++ ) + { + string _name = cblStartupComponents.Items[i] as string; + bool _checked = Program.Settings.Components[_name]; + + cblStartupComponents.SetItemChecked(i, _checked); + } + + + } + + + + + #region Internal App Window list and functions + private Dictionary _appWindows = new Dictionary(); + private Dictionary _appWindows_rev = new Dictionary(); + private void AppWindow_Add(string AppWindowName, ucAppWindow AppWindow) + { + lock (_appWindows) + { + _appWindows.Add(AppWindowName, AppWindow); + _appWindows_rev.Add(AppWindow, AppWindowName); + // Hook events + AppWindow.LineEntered += AppWindow_LineEntered; + } + } + private void AppWindow_Remove(ucAppWindow AppWindow) + { + lock (_appWindows) + { + if (_appWindows_rev.ContainsKey(AppWindow)) + { + // Unhook events + AppWindow.LineEntered -= AppWindow_LineEntered; + // Delete from list + string name = _appWindows_rev[AppWindow]; + _appWindows.Remove(name); + _appWindows_rev.Remove(AppWindow); + } + } + } + private void AppWindow_Remove(string AppWindowName) + { + lock (_appWindows) + { + if (_appWindows.ContainsKey(AppWindowName)) + { + ucAppWindow AppWindow = _appWindows[AppWindowName]; + // Unhook events + AppWindow.LineEntered -= AppWindow_LineEntered; + // Delete from list + _appWindows.Remove(AppWindowName); + _appWindows_rev.Remove(AppWindow); + } + } + } + private string AppWindow_Get(ucAppWindow AppWindow) + { + lock (_appWindows) + { + if (_appWindows_rev.ContainsKey(AppWindow)) + return _appWindows_rev[AppWindow]; + } + return null; + } + private ucAppWindow AppWindow_Get(string AppWindowName) + { + lock (_appWindows) + { + if (_appWindows.ContainsKey(AppWindowName)) + return _appWindows[AppWindowName]; + } + return null; + } + #endregion + + private void btnSave_Click(object sender, EventArgs e) + { + Program.Settings.Components.Clear(); + for (int i = 0; i < cblStartupComponents.Items.Count; i++) + { + string _name = cblStartupComponents.Items[i] as string; + bool _checked = cblStartupComponents.GetItemChecked(i); + + Program.Settings.Components.Add(_name, _checked); + Program.Settings.SaveConfig(); + } + } + + } +} diff --git a/OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ProcessPanel.resx b/OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ProcessPanel.resx new file mode 100644 index 0000000000..361d658d48 --- /dev/null +++ b/OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ProcessPanel.resx @@ -0,0 +1,882 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + iVBORw0KGgoAAAANSUhEUgAAAAEAAAB8CAIAAAAny03BAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAlwSFlzAAAOpgAA + DqYBh9ypbwAAAYpJREFUKFOV0fkrH3AYwPG3Y84NW2xzj76btomJHE20NUcpi9DKUlt+0i6EjbnmiOWY + ZTKSo69YtolNRHOEYWsIK8sksiZZU5Ompo8n379gP7x63s/z+fEDdz7w3+4Oondv6JD+/WH0H4xgkDx6 + yDBlDMPUcY6kfcQofQKjjEmMH05h8ugTppmfMc36gtnjacyzZziaM8uxvDks8uexfLKAVcFXjhctcqL4 + G9YlS9iUfufk02VOla9wumIV28o17KvWcXj+A8fqnzi92MC5ZhOX2i1cX/5CU/8bTcM25xr/4Na0w/mW + XS5q/+LeuodH2z882ve51KHweq3wfqvw6VT4din83ykC3isu9yoC+xRB/Qq7bHDIBfs8sJPpWABOxXIr + lFsRuJaJCtA8gzPibDVcqAE34VknXStv0n7N0rJ7N0m3QIAWrrZBYCtcewVXRLAIeQMRnXKTGdmtE9YF + 0T0QLh0lM6YProu4fgjthRsDcFO+79YQJIhY6fhBSByB26M6SeM6idIJwxwAjlSW4/2by3sAAAAASUVO + RK5CYII= + + + + + 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 + OxA5OCbeDtx9K3DPLXK640Zg0m2SxhFsyEF63x2SBmfMDVIQl9RsuASBrCx4dt0MSL4dkHgrYNdNUvWO + m/6xN/ygz64bvjtv+MTf9Iq76Rl/02PnDbfNV12h/7orTpuuOq5ttlt/2WZlk/W6ZstVTebRTcoVjWZR + jfLIepNFdUaL66QLayXL6g1mVIvn1ujPrhYtqhVNuSicfUk48YLOrIuC6RcF484LJp7nj0WIRkELIAeE + mH2JNwYB03nejIskjfwhQBp6aTgFnvHnyKXJNAFO8IymObiE04kI+3BHjeYgDTkzL6lEAR0hB/lgQ3Gk + cUQaVSCBq+ojCk6hmUwZJFgaRQi40iMYUAvTQa0Ypz9nfwwVbvxw8/df6n9482qAbcLZNboTLogmXxLN + rtZfWi+edslgYZ1kUZ00ssF4Wo0JQC6q0XRFo2J1szK62WLLVQpyV222XrXbcMVh61XHbdec1lx22XXD + Jfa6647rbvE33Xfc8Nh23XPnTc/Y616brgFRvHfd9N59E+jik3jbZ8cNH6S3XScUd9Nn1w2fPTd9Ym+Q + NEVHkgaBB8e9t0gOOHfd9Nl+nZxGX1FdAlyxq6At1wgPchJueW+5huq8dt7wggJrrwJ0AWbu26+7xV53 + 236d6em8/Zrj9msO6y/bbbpiu/GKTWSj1eYrlmuaCbCtazZb0QhQl6H5C2ql06oNF9dJFtSJ59WKF9Tq + LakjSwEYbfx54bjzOjMuCaZcEMy8JJhwgT/1IsGVaQAebDCep6hDAQn5I8/yJlEIwWk/7EDSSwyuplwk + NBx3wiiezakmzMgBD44RuE+GSAvxH6I3ygkGAnKXyBH8uARCceQjAQWQABvk44iyuIR8Vgu7ikykUQur + CEIIWNJMcKIWKM/pz9mfGz/c/P1X+x/e/DodeOq5NcL5tboL60RL6vUW1ukvqhMvbTCYVC1ZUi9d3mC0 + pM5kaYNsSb18Xj0CGsXGK8o1zRZrL1tGN1mtabbZeNVm4xWAhN3mq/ZAuw1XHLdfd9py1WkHQRGXXTdd + tl1z2XnDJeY6AT+EehuvusbddN12jdDWa67br7nuvEmOSG++5hpzzXXXTYSDrltoGoRM5IAZxVEWzLgK + fpazm57uuOG6E3STnMai3hukxlVXSNUx1503XyH6rL/iGHXZYdMV+5jrdhuv2G64YgPl0YR1pCHmQO6o + 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 + + + \ No newline at end of file diff --git a/OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ucAppWindow.Designer.cs b/OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ucAppWindow.Designer.cs new file mode 100644 index 0000000000..1ff7d434bd --- /dev/null +++ b/OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ucAppWindow.Designer.cs @@ -0,0 +1,72 @@ +namespace OpenSim.GridLaunch.GUI.WinForm +{ + partial class ucAppWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.ucLogWindow1 = new OpenSim.GridLaunch.GUI.WinForm.ucLogWindow(); + this.ucInputField1 = new OpenSim.GridLaunch.GUI.WinForm.ucInputField(); + this.SuspendLayout(); + // + // ucLogWindow1 + // + this.ucLogWindow1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.ucLogWindow1.Location = new System.Drawing.Point(3, 3); + this.ucLogWindow1.Name = "ucLogWindow1"; + this.ucLogWindow1.Size = new System.Drawing.Size(232, 132); + this.ucLogWindow1.TabIndex = 0; + // + // ucInputField1 + // + this.ucInputField1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.ucInputField1.Location = new System.Drawing.Point(0, 141); + this.ucInputField1.Name = "ucInputField1"; + this.ucInputField1.Size = new System.Drawing.Size(234, 30); + this.ucInputField1.TabIndex = 1; + // + // ucAppWindow + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.ucInputField1); + this.Controls.Add(this.ucLogWindow1); + this.DoubleBuffered = true; + this.Name = "ucAppWindow"; + this.Size = new System.Drawing.Size(235, 166); + this.ResumeLayout(false); + + } + + #endregion + + private ucLogWindow ucLogWindow1; + private ucInputField ucInputField1; + } +} diff --git a/OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ucAppWindow.cs b/OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ucAppWindow.cs new file mode 100644 index 0000000000..66072dc9e6 --- /dev/null +++ b/OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ucAppWindow.cs @@ -0,0 +1,63 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Data; +using System.Text; +using System.Windows.Forms; + +namespace OpenSim.GridLaunch.GUI.WinForm +{ + public partial class ucAppWindow : UserControl + { + // Just forwarding from ucInputField1 + public delegate void LineEnteredDelegate(ucAppWindow AppWindow, string Text); + public event LineEnteredDelegate LineEntered; + + public ucAppWindow() + { + InitializeComponent(); + ucInputField1.LineEntered += ucInputField1_LineEntered; + } + + #region Forward Text Input Event and Log Write Function + void ucInputField1_LineEntered(string Text) + { + if (LineEntered != null) + LineEntered(this, Text); + } + + public void Write(Color color, string LogText) + { + ucLogWindow1.Write(color, LogText); + } + #endregion + + } +} diff --git a/OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ucAppWindow.resx b/OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ucAppWindow.resx new file mode 100644 index 0000000000..19dc0dd8b3 --- /dev/null +++ b/OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ucAppWindow.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ucInputField.Designer.cs b/OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ucInputField.Designer.cs new file mode 100644 index 0000000000..1eaec69429 --- /dev/null +++ b/OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ucInputField.Designer.cs @@ -0,0 +1,77 @@ +namespace OpenSim.GridLaunch.GUI.WinForm +{ + partial class ucInputField + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.txtInput = new System.Windows.Forms.TextBox(); + this.btnSend = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // txtInput + // + this.txtInput.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.txtInput.Location = new System.Drawing.Point(3, 2); + this.txtInput.Name = "txtInput"; + this.txtInput.Size = new System.Drawing.Size(289, 20); + this.txtInput.TabIndex = 0; + this.txtInput.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.txtInput_KeyPress); + // + // btnSend + // + this.btnSend.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnSend.Location = new System.Drawing.Point(295, 0); + this.btnSend.Name = "btnSend"; + this.btnSend.Size = new System.Drawing.Size(75, 23); + this.btnSend.TabIndex = 3; + this.btnSend.Text = "&Send"; + this.btnSend.UseVisualStyleBackColor = true; + this.btnSend.Click += new System.EventHandler(this.btnSend_Click); + // + // ucInputField + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.btnSend); + this.Controls.Add(this.txtInput); + this.Name = "ucInputField"; + this.Size = new System.Drawing.Size(373, 25); + this.Load += new System.EventHandler(this.ucInputField_Load); + this.Resize += new System.EventHandler(this.ucInputField_Resize); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TextBox txtInput; + private System.Windows.Forms.Button btnSend; + } +} diff --git a/OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ucInputField.cs b/OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ucInputField.cs new file mode 100644 index 0000000000..5ffa27550b --- /dev/null +++ b/OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ucInputField.cs @@ -0,0 +1,97 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Drawing; +using System.Data; +using System.Text; +using System.Windows.Forms; + +namespace OpenSim.GridLaunch.GUI.WinForm +{ + public partial class ucInputField : UserControl + { + public delegate void LineEnteredDelegate(string Text); + public event LineEnteredDelegate LineEntered; + + public List History = new List(); + + public ucInputField() + { + InitializeComponent(); + } + + private void ucInputField_Load(object sender, EventArgs e) + { + _resize(); + } + + private void ucInputField_Resize(object sender, EventArgs e) + { + _resize(); + } + + private void _resize() + { + Height = txtInput.Height + 10; + } + + private void btnSend_Click(object sender, EventArgs e) + { + Send(); + } + + private void txtInput_KeyPress(object sender, KeyPressEventArgs e) + { + //Trace.WriteLine("KeyChar: " + ((int)e.KeyChar).ToString()); + if (e.KeyChar == 13) + { + e.Handled = true; + Send(); + } + + // TODO: Add arrow up/down history functions + } + + private void Send() + { + // Remove \r\n at end + string txt = txtInput.Text.TrimEnd("\r\n".ToCharArray()); + + // Fire event + if (LineEntered != null) + LineEntered(txt); + + // Add to history + History.Add(txtInput.Text); + + txtInput.Text = ""; + } + } +} diff --git a/OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ucInputField.resx b/OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ucInputField.resx new file mode 100644 index 0000000000..19dc0dd8b3 --- /dev/null +++ b/OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ucInputField.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ucLogWindow.Designer.cs b/OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ucLogWindow.Designer.cs new file mode 100644 index 0000000000..839fe9905f --- /dev/null +++ b/OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ucLogWindow.Designer.cs @@ -0,0 +1,62 @@ +namespace OpenSim.GridLaunch.GUI.WinForm +{ + partial class ucLogWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.txtLog = new System.Windows.Forms.TextBox(); + this.SuspendLayout(); + // + // txtLog + // + this.txtLog.BackColor = System.Drawing.SystemColors.Window; + this.txtLog.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtLog.Location = new System.Drawing.Point(0, 0); + this.txtLog.Multiline = true; + this.txtLog.Name = "txtLog"; + this.txtLog.ReadOnly = true; + this.txtLog.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + this.txtLog.Size = new System.Drawing.Size(150, 150); + this.txtLog.TabIndex = 0; + this.txtLog.TextChanged += new System.EventHandler(this.txtLog_TextChanged); + // + // ucLogWindow + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.txtLog); + this.Name = "ucLogWindow"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TextBox txtLog; + } +} diff --git a/OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ucLogWindow.cs b/OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ucLogWindow.cs new file mode 100644 index 0000000000..7b35c151db --- /dev/null +++ b/OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ucLogWindow.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Data; +using System.Text; +using System.Windows.Forms; + +namespace OpenSim.GridLaunch.GUI.WinForm +{ + public partial class ucLogWindow : UserControl + { + // If text in window is more than this + private static readonly int logWindowMaxTextLength = 20000; + // Remove this much from start of it + private static int logWindowTrunlTextLength = 10000; + + public ucLogWindow() + { + if (logWindowMaxTextLength < logWindowTrunlTextLength) + logWindowTrunlTextLength = logWindowMaxTextLength / 2; + + InitializeComponent(); + } + + public delegate void textWriteDelegate(Color color, string LogText); + public void Write(Color color, string LogText) + { + // Check if we to pass task on to GUI thread + if (this.InvokeRequired) + { + this.Invoke(new textWriteDelegate(Write), color, LogText); + return; + } + // Append to window + try + { + if (!txtLog.IsDisposed) + txtLog.AppendText(LogText); + } catch { } + } + + private void txtLog_TextChanged(object sender, EventArgs e) + { + // Go to bottom of window + txtLog.ScrollToCaret(); + + // Make sure amount of text in window doesn't grow too big + if (txtLog.Text.Length > logWindowMaxTextLength) + txtLog.Text = txtLog.Text.Remove(0, logWindowTrunlTextLength); + } + + } +} diff --git a/OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ucLogWindow.resx b/OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ucLogWindow.resx new file mode 100644 index 0000000000..19dc0dd8b3 --- /dev/null +++ b/OpenSim/Tools/OpenSim.GridLaunch/GUI/WinForm/ucLogWindow.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/OpenSim/Tools/OpenSim.GridLaunch/OpenSim.GridLaunch.csproj b/OpenSim/Tools/OpenSim.GridLaunch/OpenSim.GridLaunch.csproj new file mode 100644 index 0000000000..b262dd152c --- /dev/null +++ b/OpenSim/Tools/OpenSim.GridLaunch/OpenSim.GridLaunch.csproj @@ -0,0 +1,126 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {595D67F3-B413-4A43-8568-5B5930E3B31D} + Exe + Properties + OpenSim.GridLaunch + OpenSim.GridLaunch + v2.0 + 512 + + + true + full + false + ..\..\..\bin\ + DEBUG;TRACE + prompt + 4 + x86 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + Component + + + Form + + + ProcessPanel.cs + + + UserControl + + + ucAppWindow.cs + + + UserControl + + + ucInputField.cs + + + UserControl + + + ucLogWindow.cs + + + + + + True + True + Resources.resx + + + + + + ProcessPanel.cs + + + ucAppWindow.cs + + + ucInputField.cs + + + ucLogWindow.cs + + + + + + + + + + + PreserveNewest + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + \ No newline at end of file diff --git a/OpenSim/Tools/OpenSim.GridLaunch/OpenSim.GridLaunch.ini b/OpenSim/Tools/OpenSim.GridLaunch/OpenSim.GridLaunch.ini new file mode 100644 index 0000000000..c065898b1d --- /dev/null +++ b/OpenSim/Tools/OpenSim.GridLaunch/OpenSim.GridLaunch.ini @@ -0,0 +1,3 @@ +GUI=WinForm +;GUI=TCPD +;Components=c:\temp\test.bat;true \ No newline at end of file diff --git a/OpenSim/Tools/OpenSim.GridLaunch/OpenSim.GridLaunch.sln b/OpenSim/Tools/OpenSim.GridLaunch/OpenSim.GridLaunch.sln new file mode 100644 index 0000000000..8f745e11ba --- /dev/null +++ b/OpenSim/Tools/OpenSim.GridLaunch/OpenSim.GridLaunch.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenSim.GridLaunch", "OpenSim.GridLaunch.csproj", "{595D67F3-B413-4A43-8568-5B5930E3B31D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {595D67F3-B413-4A43-8568-5B5930E3B31D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {595D67F3-B413-4A43-8568-5B5930E3B31D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {595D67F3-B413-4A43-8568-5B5930E3B31D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {595D67F3-B413-4A43-8568-5B5930E3B31D}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/OpenSim/Tools/OpenSim.GridLaunch/Program.cs b/OpenSim/Tools/OpenSim.GridLaunch/Program.cs new file mode 100644 index 0000000000..5a0bb0cdda --- /dev/null +++ b/OpenSim/Tools/OpenSim.GridLaunch/Program.cs @@ -0,0 +1,245 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using System.Threading; +using log4net; +using log4net.Appender; +using log4net.Repository.Hierarchy; +using OpenSim.GridLaunch.GUI; +using OpenSim.GridLaunch.GUI.Network; + +namespace OpenSim.GridLaunch +{ + class Program + { + public static readonly string ConfigFile = "OpenSim.GridLaunch.ini"; + internal static Dictionary AppList = new Dictionary(); + private static readonly int delayBetweenExecuteSeconds = 10; + //private static readonly int consoleReadIntervalMilliseconds = 50; + ////private static readonly Timer readTimer = new Timer(readConsole, null, Timeout.Infinite, Timeout.Infinite); + //private static Thread timerThread; + //private static object timerThreadLock = new object(); + private static IGUI GUIModule; + private static string GUIModuleName = ""; + public static readonly CommandProcessor Command = new CommandProcessor(); + public static readonly Settings Settings = new Settings(); + + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + public delegate void AppConsoleOutputDelegate(string App, string Text); + public static event AppConsoleOutputDelegate AppConsoleOutput; + public delegate void AppConsoleErrorDelegate(string App, string Text); + public static event AppConsoleErrorDelegate AppConsoleError; + public delegate void AppCreatedDelegate(string App); + public static event AppCreatedDelegate AppCreated; + public delegate void AppRemovedDelegate(string App); + public static event AppRemovedDelegate AppRemoved; + + internal static void FireAppConsoleOutput(string App, string Text) + { + if (AppConsoleOutput != null) + AppConsoleOutput(App, Text); + } + internal static void FireAppConsoleError(string App, string Text) + { + if (AppConsoleError != null) + AppConsoleError(App, Text); + } + + + private static readonly object startStopLock = new object(); + + public static string Name { get { return "OpenSim Grid executor"; } } + + #region Start/Shutdown + static void Main(string[] args) + { + log4net.Config.XmlConfigurator.Configure(); + + // Startup + m_log.Info(Name); + m_log.Info(new string('-', Name.Length)); + + // Read settings + Settings.LoadConfig(ConfigFile); + // Command line arguments override settings + Settings.ParseCommandArguments(args); + + // Start GUI module + StartGUIModule(); + + // Start the processes + ThreadPool.QueueUserWorkItem(startProcesses); + + // Hand over thread control to whatever GUI module + GUIModule.StartGUI(); + + // GUI module returned, we are done + Shutdown(); + + } + + private static void StartGUIModule() + { + // Create GUI module + GUIModuleName = Settings["GUI"]; + + switch (GUIModuleName.ToLower()) + { + case "winform": + GUIModuleName = "WinForm"; + GUIModule = new GUI.WinForm.ProcessPanel(); + break; + case "service": + GUIModuleName = "Service"; + GUIModule = new Service(); + break; + case "tcpd": + GUIModuleName = "TCPD"; + GUIModule = new TCPD(); + break; + case "console": + default: + GUIModuleName = "Console"; + GUIModule = new GUI.Console.Console(); + break; + } + m_log.Info("GUI type: " + GUIModuleName); + + } + + internal static void Shutdown() + { + // Stop the processes + stopProcesses(); + + lock (startStopLock) + { + // Stop GUI module + if (GUIModule != null) + { + GUIModule.StopGUI(); + GUIModule = null; + } + } + } + + internal static void SafeDisposeOf(object obj) + { + IDisposable o = obj as IDisposable; + try + { + if (o != null) + o.Dispose(); + } + catch { } + } + #endregion + + #region Start / Stop applications + private static void startProcesses(Object stateInfo) + { + // Stop before starting + stopProcesses(); + + // Start console read timer + //timer_Start(); + + // Start the applications + foreach (string file in new ArrayList(Settings.Components.Keys)) + { + // Is this file marked for startup? + if (Settings.Components[file]) + { + AppExecutor app = new AppExecutor(file); + app.Start(); + AppList.Add(file, app); + if (AppCreated != null) + AppCreated(app.File); + System.Threading.Thread.Sleep(1000*delayBetweenExecuteSeconds); + } + } + } + + private static void stopProcesses() + { + // Stop timer + //timer_Stop(); + + // Lock so we don't collide with any timer still executing on AppList + lock (AppList) + { + // Start the applications + foreach (AppExecutor app in AppList.Values) + { + try + { + m_log.Info("Stopping: " + app.File); + app.Stop(); + } + catch (Exception ex) + { + m_log.ErrorFormat("Exception while stopping \"{0}\": {1}", app.File, ex.ToString()); + } + finally + { + if (AppRemoved != null) + AppRemoved(app.File); + app.Dispose(); + } + + } + AppList.Clear(); + } + } + #endregion + + public static void Write(string App, string Text) + { + // Check if it is a commands + bool isCommand = Command.Process(App, Text); + + // Write to stdInput of app + if (!isCommand && AppList.ContainsKey(App)) + AppList[App].Write(Text); + } + + public static void WriteLine(string App, string Text) + { + // Check if it is a commands + bool isCommand = Command.Process(App, Text); + + // Write to stdInput of app + if (!isCommand && AppList.ContainsKey(App)) + AppList[App].WriteLine(Text); + } + } +} diff --git a/OpenSim/Tools/OpenSim.GridLaunch/Properties/AssemblyInfo.cs b/OpenSim/Tools/OpenSim.GridLaunch/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..4c300d0078 --- /dev/null +++ b/OpenSim/Tools/OpenSim.GridLaunch/Properties/AssemblyInfo.cs @@ -0,0 +1,63 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OpenSim.GridLaunch")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("OpenSim.GridLaunch")] +[assembly: AssemblyCopyright("Copyright (c) 2008")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("5072e919-46ab-47e6-8a63-08108324ccdf")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/OpenSim/Tools/OpenSim.GridLaunch/Properties/Resources.Designer.cs b/OpenSim/Tools/OpenSim.GridLaunch/Properties/Resources.Designer.cs new file mode 100644 index 0000000000..88b0cebdd9 --- /dev/null +++ b/OpenSim/Tools/OpenSim.GridLaunch/Properties/Resources.Designer.cs @@ -0,0 +1,84 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:2.0.50727.3053 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace OpenSim.GridLaunch.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("OpenSim.GridLaunch.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + internal static System.Drawing.Bitmap OpenSim { + get { + object obj = ResourceManager.GetObject("OpenSim", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap OpenSim_Bottom_Border { + get { + object obj = ResourceManager.GetObject("OpenSim_Bottom_Border", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap OpenSim_Right_Border { + get { + object obj = ResourceManager.GetObject("OpenSim_Right_Border", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/OpenSim/Tools/OpenSim.GridLaunch/Properties/Resources.resx b/OpenSim/Tools/OpenSim.GridLaunch/Properties/Resources.resx new file mode 100644 index 0000000000..b82a1fced2 --- /dev/null +++ b/OpenSim/Tools/OpenSim.GridLaunch/Properties/Resources.resx @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\gui\winform\opensim.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\gui\winform\opensim bottom border.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\gui\winform\opensim right border.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/OpenSim/Tools/OpenSim.GridLaunch/Settings.cs b/OpenSim/Tools/OpenSim.GridLaunch/Settings.cs new file mode 100644 index 0000000000..91353d8daf --- /dev/null +++ b/OpenSim/Tools/OpenSim.GridLaunch/Settings.cs @@ -0,0 +1,181 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Text; +using log4net; + +namespace OpenSim.GridLaunch +{ + internal class Settings + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private Dictionary Config = new Dictionary(); + public Dictionary Components = new Dictionary(); + + public static string[] defaultComponents = new string[] + { + "OpenSim.Grid.UserServer.exe", + "OpenSim.Grid.GridServer.exe", + "OpenSim.Grid.AssetServer.exe", + "OpenSim.Grid.InventoryServer.exe", + "OpenSim.Grid.MessagingServer.exe", + "OpenSim.32BitLaunch.exe" + }; + + + private static readonly char[] confSplit = new char[] { '=' }; + private static readonly char[] comaSplit = new char[] { ',' }; + private static readonly char[] colonSplit = new char[] { ';' }; + + private string configFile = ""; + + public Settings() + { + } + public Settings(string ConfigFile) + { + LoadConfig(ConfigFile); + } + + + public void LoadConfig(string ConfigFile) + { + configFile = ConfigFile; + m_log.Info("Reading config file: " + ConfigFile); + try + { + // Read config file + foreach (string line in System.IO.File.ReadAllLines(ConfigFile)) + { + string[] s = line.Split(confSplit, 2); + if (s.Length >= 2) + Config.Add(s[0], s[1]); + } + + // Process Components section + string cmp = Config["Components"]; + Config.Remove("Components"); + foreach (string c in cmp.Split(comaSplit)) + { + string[] cs = c.Split(colonSplit); + if (cs.Length >= 2) + { + bool status = false; + bool.TryParse(cs[1], out status); + Components.Add(cs[0], status); + } + } + } + catch (Exception ex) + { + m_log.Error("Exception reading config file: " + ex.ToString()); + } + // No components? Add default components + if (Components.Count == 0) + foreach (string c in defaultComponents) + { + Components.Add(c, true); + } + } + + public void SaveConfig(string ConfigFile) + { + configFile = ConfigFile; + SaveConfig(); + } + + public void SaveConfig() + { + m_log.Info("Writing config file: " + configFile); + try + { + System.IO.File.WriteAllText(configFile, ToString()); + } + catch (Exception ex) + { + m_log.Error("Exception writing config file: " + ex.ToString()); + } + + } + + public new string ToString() + { + StringBuilder ret = new StringBuilder(); + + Dictionary config = new Dictionary(Config); + + // Add Components key + StringBuilder _Components = new StringBuilder(); + foreach (string c in Components.Keys) + { + if (_Components.Length > 0) + _Components.Append(","); + _Components.Append(c + ";" + Components[c].ToString()); + } + config["Components"] = _Components.ToString(); + + // Make return string + foreach (string key in config.Keys) + { + ret.AppendLine(key + "=" + config[key]); + } + + // Return it + return ret.ToString(); + } + + public string this[string Key] + { + get + { + if (Config.ContainsKey(Key)) + return Config[Key]; + return ""; + } + set { Config[Key] = value; } + } + + public void ParseCommandArguments(string[] args) + { + string key = null; + foreach (string a in args) + { + if (a.StartsWith("--")) + key = a.Remove(0, 2); + else + { + if (key != null) + Config[key] = a; + key = null; + } + } + + } + } +} diff --git a/OpenSim/Tools/OpenSim.GridLaunch/log4netAppender.cs b/OpenSim/Tools/OpenSim.GridLaunch/log4netAppender.cs new file mode 100644 index 0000000000..d9bea1aaf8 --- /dev/null +++ b/OpenSim/Tools/OpenSim.GridLaunch/log4netAppender.cs @@ -0,0 +1,65 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Text; +using System.Windows.Forms; +using log4net.Appender; +using log4net.Core; + +namespace OpenSim.GridLaunch +{ + internal class log4netAppender : log4net.Appender.AppenderSkeleton + { + public delegate void LogLineDelegate(Color color, string Text); + public static event LogLineDelegate LogLine; + public static readonly Dictionary Level2Color = new Dictionary(); + + static log4netAppender() + { + Level2Color.Add("INFO", Color.Black); + Level2Color.Add("DEBUG", Color.Gray); + Level2Color.Add("WARN", Color.OrangeRed); + Level2Color.Add("ERROR", Color.Red); + } + + + protected override void Append(LoggingEvent loggingEvent) + { + // Find appropriate color + Color color = Color.Black; + if (Level2Color.ContainsKey(loggingEvent.Level.Name)) + color = Level2Color[loggingEvent.Level.Name]; + + // Fire event with new log message + if (LogLine != null) + LogLine(color, loggingEvent.RenderedMessage + System.Environment.NewLine); + } + + } +}