From 8d1deb2ae478fae2536e1781b83140e5e96286b8 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Mon, 27 Dec 2010 08:51:48 -0800 Subject: [PATCH] Splitting a file into smaller chunks. --- Download.cs | 58 +++++++ Main.cs | 396 ------------------------------------------- ServiceDescriptor.cs | 371 ++++++++++++++++++++++++++++++++++++++++ winsw.csproj | 2 + 4 files changed, 431 insertions(+), 396 deletions(-) create mode 100755 Download.cs create mode 100755 ServiceDescriptor.cs diff --git a/Download.cs b/Download.cs new file mode 100755 index 0000000..55c59fd --- /dev/null +++ b/Download.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.ServiceProcess; +using System.Text; +using System.IO; +using System.Net; +using WMI; +using System.Xml; +using System.Threading; +using Microsoft.Win32; + +namespace winsw +{ + /// + /// Specify the download activities prior to the launch. + /// This enables self-updating services. + /// + public class Download + { + public readonly string From; + public readonly string To; + + internal Download(XmlNode n) + { + From = Environment.ExpandEnvironmentVariables(n.Attributes["from"].Value); + To = Environment.ExpandEnvironmentVariables(n.Attributes["to"].Value); + } + + public void Perform() + { + WebRequest req = WebRequest.Create(From); + WebResponse rsp = req.GetResponse(); + FileStream tmpstream = new FileStream(To + ".tmp", FileMode.Create); + CopyStream(rsp.GetResponseStream(), tmpstream); + // only after we successfully downloaded a file, overwrite the existing one + if (File.Exists(To)) + File.Delete(To); + File.Move(To + ".tmp", To); + } + + private static void CopyStream(Stream i, Stream o) + { + byte[] buf = new byte[8192]; + while (true) + { + int len = i.Read(buf, 0, buf.Length); + if (len <= 0) break; + o.Write(buf, 0, len); + } + i.Close(); + o.Close(); + } + } +} diff --git a/Main.cs b/Main.cs index 34d2a36..7dd3129 100644 --- a/Main.cs +++ b/Main.cs @@ -37,402 +37,6 @@ namespace winsw SERVICE_PAUSED = 0x00000007, } - /// - /// In-memory representation of the configuration file. - /// - public class ServiceDescriptor - { - private readonly XmlDocument dom = new XmlDocument(); - - /// - /// Where did we find the configuration file? - /// - /// This string is "c:\abc\def\ghi" when the configuration XML is "c:\abc\def\ghi.xml" - /// - public readonly string BasePath; - /// - /// The file name portion of the configuration file. - /// - /// In the above example, this would be "ghi". - /// - public readonly string BaseName; - - public static string ExecutablePath - { - get - { - // this returns the executable name as given by the calling process, so - // it needs to be absolutized. - string p = Environment.GetCommandLineArgs()[0]; - return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, p); - - } - } - - public ServiceDescriptor() - { - // find co-located configuration xml. We search up to the ancestor directories to simplify debugging, - // as well as trimming off ".vshost" suffix (which is used during debugging) - string p = ExecutablePath; - string baseName = Path.GetFileNameWithoutExtension(p); - if (baseName.EndsWith(".vshost")) baseName = baseName.Substring(0, baseName.Length - 7); - while (true) - { - p = Path.GetDirectoryName(p); - if (File.Exists(Path.Combine(p, baseName + ".xml"))) - break; - } - - // register the base directory as environment variable so that future expansions can refer to this. - Environment.SetEnvironmentVariable("BASE", p); - - BaseName = baseName; - BasePath = Path.Combine(p, BaseName); - - dom.Load(BasePath+".xml"); - } - - private string SingleElement(string tagName) - { - var n = dom.SelectSingleNode("//" + tagName); - if (n == null) throw new InvalidDataException("<" + tagName + "> is missing in configuration XML"); - return Environment.ExpandEnvironmentVariables(n.InnerText); - } - - /// - /// Path to the executable. - /// - public string Executable - { - get - { - return SingleElement("executable"); - } - } - - /// - /// Optionally specify a different Path to an executable to shutdown the service. - /// - public string StopExecutable - { - get - { - return AppendTags("stopexecutable"); - } - } - - /// - /// Arguments or multiple optional argument elements which overrule the arguments element. - /// - public string Arguments - { - get - { - string arguments = AppendTags("argument"); - - if (arguments == null) - { - var tagName = "arguments"; - var argumentsNode = dom.SelectSingleNode("//" + tagName); - - if (argumentsNode == null) - { - if (AppendTags("startargument") == null) - { - throw new InvalidDataException("<" + tagName + "> is missing in configuration XML"); - } - else - { - return ""; - } - } - - return Environment.ExpandEnvironmentVariables(argumentsNode.InnerText); - } - else - { - return arguments; - } - } - } - - /// - /// Multiple optional startargument elements. - /// - public string Startarguments - { - get - { - return AppendTags("startargument"); - } - } - - /// - /// Multiple optional stopargument elements. - /// - public string Stoparguments - { - get - { - return AppendTags("stopargument"); - } - } - - /// - /// Combines the contents of all the elements of the given name, - /// or return null if no element exists. - /// - private string AppendTags(string tagName) - { - XmlNode argumentNode = dom.SelectSingleNode("//" + tagName); - - if (argumentNode == null) - { - return null; - } - else - { - string arguments = ""; - - foreach (XmlNode argument in dom.SelectNodes("//" + tagName)) - { - arguments += " " + argument.InnerText; - } - - return Environment.ExpandEnvironmentVariables(arguments); - } - } - - /// - /// LogDirectory is the service wrapper executable directory or the optionally specified logpath element. - /// - public string LogDirectory - { - get - { - XmlNode loggingNode = dom.SelectSingleNode("//logpath"); - - if (loggingNode != null) - { - return loggingNode.InnerText; - } - else - { - return Path.GetDirectoryName(ExecutablePath); - } - } - } - - - /// - /// Logmode to 'reset', 'rotate' once or 'append' [default] the out.log and err.log files. - /// - public string Logmode - { - get - { - XmlNode logmodeNode = dom.SelectSingleNode("//logmode"); - - if (logmodeNode == null) - { - return "append"; - } - else - { - return logmodeNode.InnerText; - } - } - } - - /// - /// Optionally specified depend services that must start before this service starts. - /// - public string[] ServiceDependencies - { - get - { - System.Collections.ArrayList serviceDependencies = new System.Collections.ArrayList(); - - foreach (XmlNode depend in dom.SelectNodes("//depend")) - { - serviceDependencies.Add(depend.InnerText); - } - - return (string[])serviceDependencies.ToArray(typeof(string)); - } - } - - public string Id - { - get - { - return SingleElement("id"); - } - } - - public string Caption - { - get - { - return SingleElement("name"); - } - } - - public string Description - { - get - { - return SingleElement("description"); - } - } - - /// - /// True if the service should when finished on shutdown. - /// - public bool BeepOnShutdown - { - get - { - return dom.SelectSingleNode("//beeponshutdown") != null; - } - } - - - /// - /// The estimated time required for a pending stop operation, in milliseconds (default 15 secs). - /// Before the specified amount of time has elapsed, the service should make its next call to the SetServiceStatus function - /// with either an incremented checkPoint value or a change in currentState. (see http://msdn.microsoft.com/en-us/library/ms685996.aspx) - /// - public int WaitHint - { - get - { - XmlNode waithintNode = dom.SelectSingleNode("//waithint"); - - if (waithintNode == null) - { - return 15000; - } - else - { - return int.Parse(waithintNode.InnerText); - } - } - } - - - /// - /// The time, in milliseconds (default 1 sec), before the service should make its next call to the SetServiceStatus function - /// with an incremented checkPoint value. - /// Do not wait longer than the wait hint. A good interval is one-tenth of the wait hint but not less than 1 second and not more than 10 seconds. - /// - public int SleepTime - { - get - { - XmlNode sleeptimeNode = dom.SelectSingleNode("//sleeptime"); - - if (sleeptimeNode == null) - { - return 1000; - } - else - { - return int.Parse(sleeptimeNode.InnerText); - } - } - } - - /// - /// True if the service can interact with the desktop. - /// - public bool Interactive - { - get - { - return dom.SelectSingleNode("//interactive") != null; - } - } - - /// - /// Environment variable overrides - /// - public Dictionary EnvironmentVariables - { - get - { - Dictionary map = new Dictionary(); - foreach (XmlNode n in dom.SelectNodes("//env")) - { - string key = n.Attributes["name"].Value; - string value = Environment.ExpandEnvironmentVariables(n.Attributes["value"].Value); - map[key] = value; - - Environment.SetEnvironmentVariable(key, value); - } - return map; - } - } - - /// - /// List of downloads to be performed by the wrapper before starting - /// a service. - /// - public List Downloads - { - get - { - List r = new List(); - foreach (XmlNode n in dom.SelectNodes("//download")) - { - r.Add(new Download(n)); - } - return r; - } - } - } - - /// - /// Specify the download activities prior to the launch. - /// This enables self-updating services. - /// - public class Download - { - public readonly string From; - public readonly string To; - - internal Download(XmlNode n) - { - From = Environment.ExpandEnvironmentVariables(n.Attributes["from"].Value); - To = Environment.ExpandEnvironmentVariables(n.Attributes["to"].Value); - } - - public void Perform() - { - WebRequest req = WebRequest.Create(From); - WebResponse rsp = req.GetResponse(); - FileStream tmpstream = new FileStream(To+".tmp", FileMode.Create); - CopyStream(rsp.GetResponseStream(), tmpstream); - // only after we successfully downloaded a file, overwrite the existing one - if(File.Exists(To)) - File.Delete(To); - File.Move(To + ".tmp", To); - } - - private static void CopyStream(Stream i, Stream o) - { - byte[] buf = new byte[8192]; - while (true) - { - int len = i.Read(buf, 0, buf.Length); - if (len <= 0) break; - o.Write(buf, 0, len); - } - i.Close(); - o.Close(); - } - } - public class WrapperService : ServiceBase { [DllImport("ADVAPI32.DLL")] diff --git a/ServiceDescriptor.cs b/ServiceDescriptor.cs new file mode 100755 index 0000000..73050b2 --- /dev/null +++ b/ServiceDescriptor.cs @@ -0,0 +1,371 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.ServiceProcess; +using System.Text; +using System.IO; +using System.Net; +using WMI; +using System.Xml; +using System.Threading; +using Microsoft.Win32; +namespace winsw +{ + /// + /// In-memory representation of the configuration file. + /// + public class ServiceDescriptor + { + private readonly XmlDocument dom = new XmlDocument(); + + /// + /// Where did we find the configuration file? + /// + /// This string is "c:\abc\def\ghi" when the configuration XML is "c:\abc\def\ghi.xml" + /// + public readonly string BasePath; + /// + /// The file name portion of the configuration file. + /// + /// In the above example, this would be "ghi". + /// + public readonly string BaseName; + + public static string ExecutablePath + { + get + { + // this returns the executable name as given by the calling process, so + // it needs to be absolutized. + string p = Environment.GetCommandLineArgs()[0]; + return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, p); + + } + } + + public ServiceDescriptor() + { + // find co-located configuration xml. We search up to the ancestor directories to simplify debugging, + // as well as trimming off ".vshost" suffix (which is used during debugging) + string p = ExecutablePath; + string baseName = Path.GetFileNameWithoutExtension(p); + if (baseName.EndsWith(".vshost")) baseName = baseName.Substring(0, baseName.Length - 7); + while (true) + { + p = Path.GetDirectoryName(p); + if (File.Exists(Path.Combine(p, baseName + ".xml"))) + break; + } + + // register the base directory as environment variable so that future expansions can refer to this. + Environment.SetEnvironmentVariable("BASE", p); + + BaseName = baseName; + BasePath = Path.Combine(p, BaseName); + + dom.Load(BasePath + ".xml"); + } + + private string SingleElement(string tagName) + { + var n = dom.SelectSingleNode("//" + tagName); + if (n == null) throw new InvalidDataException("<" + tagName + "> is missing in configuration XML"); + return Environment.ExpandEnvironmentVariables(n.InnerText); + } + + /// + /// Path to the executable. + /// + public string Executable + { + get + { + return SingleElement("executable"); + } + } + + /// + /// Optionally specify a different Path to an executable to shutdown the service. + /// + public string StopExecutable + { + get + { + return AppendTags("stopexecutable"); + } + } + + /// + /// Arguments or multiple optional argument elements which overrule the arguments element. + /// + public string Arguments + { + get + { + string arguments = AppendTags("argument"); + + if (arguments == null) + { + var tagName = "arguments"; + var argumentsNode = dom.SelectSingleNode("//" + tagName); + + if (argumentsNode == null) + { + if (AppendTags("startargument") == null) + { + throw new InvalidDataException("<" + tagName + "> is missing in configuration XML"); + } + else + { + return ""; + } + } + + return Environment.ExpandEnvironmentVariables(argumentsNode.InnerText); + } + else + { + return arguments; + } + } + } + + /// + /// Multiple optional startargument elements. + /// + public string Startarguments + { + get + { + return AppendTags("startargument"); + } + } + + /// + /// Multiple optional stopargument elements. + /// + public string Stoparguments + { + get + { + return AppendTags("stopargument"); + } + } + + /// + /// Combines the contents of all the elements of the given name, + /// or return null if no element exists. + /// + private string AppendTags(string tagName) + { + XmlNode argumentNode = dom.SelectSingleNode("//" + tagName); + + if (argumentNode == null) + { + return null; + } + else + { + string arguments = ""; + + foreach (XmlNode argument in dom.SelectNodes("//" + tagName)) + { + arguments += " " + argument.InnerText; + } + + return Environment.ExpandEnvironmentVariables(arguments); + } + } + + /// + /// LogDirectory is the service wrapper executable directory or the optionally specified logpath element. + /// + public string LogDirectory + { + get + { + XmlNode loggingNode = dom.SelectSingleNode("//logpath"); + + if (loggingNode != null) + { + return loggingNode.InnerText; + } + else + { + return Path.GetDirectoryName(ExecutablePath); + } + } + } + + + /// + /// Logmode to 'reset', 'rotate' once or 'append' [default] the out.log and err.log files. + /// + public string Logmode + { + get + { + XmlNode logmodeNode = dom.SelectSingleNode("//logmode"); + + if (logmodeNode == null) + { + return "append"; + } + else + { + return logmodeNode.InnerText; + } + } + } + + /// + /// Optionally specified depend services that must start before this service starts. + /// + public string[] ServiceDependencies + { + get + { + System.Collections.ArrayList serviceDependencies = new System.Collections.ArrayList(); + + foreach (XmlNode depend in dom.SelectNodes("//depend")) + { + serviceDependencies.Add(depend.InnerText); + } + + return (string[])serviceDependencies.ToArray(typeof(string)); + } + } + + public string Id + { + get + { + return SingleElement("id"); + } + } + + public string Caption + { + get + { + return SingleElement("name"); + } + } + + public string Description + { + get + { + return SingleElement("description"); + } + } + + /// + /// True if the service should when finished on shutdown. + /// + public bool BeepOnShutdown + { + get + { + return dom.SelectSingleNode("//beeponshutdown") != null; + } + } + + + /// + /// The estimated time required for a pending stop operation, in milliseconds (default 15 secs). + /// Before the specified amount of time has elapsed, the service should make its next call to the SetServiceStatus function + /// with either an incremented checkPoint value or a change in currentState. (see http://msdn.microsoft.com/en-us/library/ms685996.aspx) + /// + public int WaitHint + { + get + { + XmlNode waithintNode = dom.SelectSingleNode("//waithint"); + + if (waithintNode == null) + { + return 15000; + } + else + { + return int.Parse(waithintNode.InnerText); + } + } + } + + + /// + /// The time, in milliseconds (default 1 sec), before the service should make its next call to the SetServiceStatus function + /// with an incremented checkPoint value. + /// Do not wait longer than the wait hint. A good interval is one-tenth of the wait hint but not less than 1 second and not more than 10 seconds. + /// + public int SleepTime + { + get + { + XmlNode sleeptimeNode = dom.SelectSingleNode("//sleeptime"); + + if (sleeptimeNode == null) + { + return 1000; + } + else + { + return int.Parse(sleeptimeNode.InnerText); + } + } + } + + /// + /// True if the service can interact with the desktop. + /// + public bool Interactive + { + get + { + return dom.SelectSingleNode("//interactive") != null; + } + } + + /// + /// Environment variable overrides + /// + public Dictionary EnvironmentVariables + { + get + { + Dictionary map = new Dictionary(); + foreach (XmlNode n in dom.SelectNodes("//env")) + { + string key = n.Attributes["name"].Value; + string value = Environment.ExpandEnvironmentVariables(n.Attributes["value"].Value); + map[key] = value; + + Environment.SetEnvironmentVariable(key, value); + } + return map; + } + } + + /// + /// List of downloads to be performed by the wrapper before starting + /// a service. + /// + public List Downloads + { + get + { + List r = new List(); + foreach (XmlNode n in dom.SelectNodes("//download")) + { + r.Add(new Download(n)); + } + return r; + } + } + } +} diff --git a/winsw.csproj b/winsw.csproj index 20a6424..ced05c1 100644 --- a/winsw.csproj +++ b/winsw.csproj @@ -46,11 +46,13 @@ + Component +