using System.ComponentModel; using System.ServiceModel; using System.ServiceProcess; using System.Configuration; using System.Configuration.Install;
using System.Reflection; using System.Xml.Linq; using System.Xml.XPath;
// [ServiceContract(Namespace = "http://QBuilder.AppLauncher")] public interface IAppLauncher { // [OperationContract] bool TestConnection(); }
public class AppLauncherService : IAppLauncher { public bool TestConnection() { return true; } }
public class AppLauncherWindowsService : ServiceBase { public ServiceHost serviceHost = null; public AppLauncherWindowsService() { // Name the Windows Service ServiceName = "QBuilder App Launcher"; } public static void Main() { ServiceBase.Run(new AppLauncherWindowsService()); }
protected override void OnStart(string[] args) { if (serviceHost != null) { serviceHost.Close(); } // Create a ServiceHost for the CalculatorService type and // provide the base address. serviceHost = new ServiceHost(typeof(AppLauncherService)); // Open the ServiceHostBase to create listeners and start // listening for messages. serviceHost.Open(); }
protected override void OnStop() { if (serviceHost != null) { serviceHost.Close(); serviceHost = null; } } }
[RunInstaller(true)] public class ProjectInstaller : Installer { private ServiceProcessInstaller process; private ServiceInstaller service; public ProjectInstaller() { process = new ServiceProcessInstaller(); process.Account = ServiceAccount.LocalSystem; service = new ServiceInstaller(); service.ServiceName = "QBuilder App Launcher"; Installers.Add(process); Installers.Add(service); } }
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.serviceModel> <services> <service name="QBuilder.AppLauncher.AppLauncherService" behaviorConfiguration="AppLauncherServiceBehavior"> <host> <baseAddresses> <add baseAddress="http://localhost:8000/QBuilderAppLauncher/service"/> </baseAddresses> </host> <endpoint address="" binding="wsHttpBinding" contract="QBuilder.AppLauncher.IAppLauncher" /> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /> </service> </services> <behaviors> <serviceBehaviors> <behavior name="AppLauncherServiceBehavior"> <serviceMetadata httpGetEnabled="true"/> <serviceDebug includeExceptionDetailInFaults="False"/> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> </configuration>
static void RunInteractive(ServiceBase[] services) { Console.WriteLine("Service is running in interactive mode."); Console.WriteLine(); var start = typeof(ServiceBase).GetMethod("OnStart", BindingFlags.Instance | BindingFlags.NonPublic); foreach (var service in services) { Console.Write("Starting {0}...", service.ServiceName); start.Invoke(service, new object[] { new string[] { } }); Console.Write("Started {0}", service.ServiceName); } Console.WriteLine(); Console.WriteLine("Press any key to stop the services and end the process..."); Console.ReadKey(); Console.WriteLine(); var stop = typeof(ServiceBase).GetMethod("OnStop", BindingFlags.Instance | BindingFlags.NonPublic); foreach (var service in services) { Console.Write("Stopping {0}...", service.ServiceName); stop.Invoke(service, null); Console.WriteLine("Stopped {0}", service.ServiceName); } Console.WriteLine("All services stopped."); }
public static void Main(string[] args) { var services = new ServiceBase[] { new AppLauncherWindowsService() }; // , /console if (args.Length == 1 && args[0] == "/console" && Environment.UserInteractive) { // RunInteractive(services); } else { // ServiceBase.Run(services); } }
public class AppLauncherService : IAppLauncher
:
public class AppLauncherService : IAppLauncher { Process appProcess;
public bool IsStarted() { if (appProcess!=null) { if (appProcess.HasExited) { return false; } else { return true; } } else { return false; } }
public bool Start(string fileName, string arguments, string workingDirectory, string domain, string userName, int timeoutInMinutes) { ProcessStartInfo processStartInfo = new ProcessStartInfo(); processStartInfo.FileName = fileName; processStartInfo.Arguments = arguments; processStartInfo.Domain = domain; processStartInfo.UserName = userName; processStartInfo.CreateNoWindow = false; processStartInfo.UseShellExecute = false; try { if (appProcess!=null) { if (!appProcess.HasExited) { Console.WriteLine("Process is still running. Waiting..."); return false; } } } catch (Exception ex) { Console.WriteLine("Error while checking process: {0}", ex); } try { appProcess = new Process(); appProcess.StartInfo = processStartInfo; appProcess.Start(); } catch (Exception ex) { Console.WriteLine("Error while starting process: {0}",ex); } return true; }
// , public class QBuildRecord { // ID public string BuildId { get; set; } // ID public string IssueId { get; set; } // public string IssueName { get; set; } // public DateTime StartDate { get; set; } // public DateTime FinishDate { get; set; } // C# public bool Build_CSharp { get; set; } // C++ public bool Build_Cpp { get; set; } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Xml.Linq; using System.Xml.XPath; using System.IO; namespace QBuilder.AppQueue { . . . }
// XML public class CXmlQueue { // , string xmlBuildQueueFile; public CXmlQueue(string _xmlQueueFile) { xmlBuildQueueFile = _xmlQueueFile; } public string GetQueueFileName() { return xmlBuildQueueFile; } // , xml ( xml) public QBuildRecord GetCurrentBuild() { QBuildRecord qBr; XElement xRoot = OpenXmlQueue(); XElement xCurrentBuild = xRoot.XPathSelectElement("currentbuild"); if (xCurrentBuild != null) { qBr = new QBuildRecord(); qBr.BuildId = xCurrentBuild.Attribute("BuildId").Value; qBr.IssueId = xCurrentBuild.Attribute("IssueId").Value; qBr.StartDate = Convert.ToDateTime(xCurrentBuild.Attribute("StartDate").Value); return qBr; } return null; } // , xml ( xml) public void SetCurrentBuild(QBuildRecord qbr) { XElement xRoot = OpenXmlQueue(); XElement newXe = (new XElement( "currentbuild", new XAttribute("BuildId", qbr.BuildId), new XAttribute("IssueId", qbr.IssueId), new XAttribute("StartDate", DateTime.Now.ToString()) )); XElement xCurrentBuild = xRoot.XPathSelectElement("currentbuild"); if (xCurrentBuild != null) { xCurrentBuild.Remove(); // remove old value } xRoot.Add(newXe); xRoot.Save(xmlBuildQueueFile); } // , xml, , public void ClearCurrentBuild() { XElement xRoot = OpenXmlQueue(); try { XElement xCurrentBuild = xRoot.XPathSelectElement("currentbuild"); if (xCurrentBuild != null) { Console.WriteLine("Clearing current build information."); xCurrentBuild.Remove(); } } catch (Exception ex) { Console.WriteLine("XML queue doesn't have running build yet. Nothing to clear!"); } xRoot.Save(xmlBuildQueueFile); } // XML public XElement OpenXmlQueue() { XElement xRoot; if (File.Exists(xmlBuildQueueFile)) { xRoot = XElement.Load(xmlBuildQueueFile, LoadOptions.None); } else { Console.WriteLine("Queue file {0} not found. Creating...", xmlBuildQueueFile); XElement xE = new XElement("BuildsQueue", new XAttribute("BuildNumber", 0)); xE.Save(xmlBuildQueueFile); xRoot = XElement.Load(xmlBuildQueueFile, LoadOptions.None); } return xRoot; } // public int GetLastQueueBuildNumber() { XElement xRoot = OpenXmlQueue(); if (xRoot.HasAttributes) return int.Parse(xRoot.Attribute("BuildNumber").Value); return 0; } // public int IncrementLastQueueBuildNumber() { int buildIndex = GetLastQueueBuildNumber(); buildIndex++; XElement xRoot = OpenXmlQueue(); xRoot.Attribute("BuildNumber").Value = buildIndex.ToString(); xRoot.Save(xmlBuildQueueFile); return buildIndex; } // xml QBuildRecord public List<QBuildRecord> GetCurrentQueue() { List<QBuildRecord> qList = new List<QBuildRecord>(); XElement xRoot = OpenXmlQueue(); if (xRoot.XPathSelectElements("build").Any()) { List<XElement> xBuilds = xRoot.XPathSelectElements("build").ToList(); foreach (XElement xe in xBuilds) { qList.Add(new QBuildRecord { BuildId = xe.Attribute("BuildId").Value, IssueId = xe.Attribute("IssueId").Value, IssueName = xe.Attribute("IssueName").Value, StartDate = Convert.ToDateTime(xe.Attribute("StartDate").Value), Build_CSharp = bool.Parse(xe.Attribute("Build_CSharp").Value), Build_Cpp = bool.Parse(xe.Attribute("Build_Cpp").Value) }); } } return qList; } }
<?xml version="1.0" encoding="utf-8"?> <BuildsQueue BuildNumber="23"> <build BuildId="14" IssueId="26086" IssueName="TestIssueName" StartDate="2018-06-13T16:49:50.515238+02:00" Build_CSharp="true" Build_Cpp="true" /> <build BuildId="15" IssueId="59559" IssueName="TestIssueName" StartDate="2018-06-13T16:49:50.6880927+02:00" Build_CSharp="true" Build_Cpp="true" /> <build BuildId="16" IssueId="45275" IssueName="TestIssueName" StartDate="2018-06-13T16:49:50.859937+02:00" Build_CSharp="true" Build_Cpp="true" /> <build BuildId="17" IssueId="30990" IssueName="TestIssueName" StartDate="2018-06-13T16:49:51.0321322+02:00" Build_CSharp="true" Build_Cpp="true" /> <build BuildId="18" IssueId="16706" IssueName="TestIssueName" StartDate="2018-06-13T16:49:51.2009904+02:00" Build_CSharp="true" Build_Cpp="true" /> <build BuildId="19" IssueId="66540" IssueName="TestIssueName" StartDate="2018-06-13T16:49:51.3581274+02:00" Build_CSharp="true" Build_Cpp="true" /> <build BuildId="20" IssueId="68618" IssueName="TestIssueName" StartDate="2018-06-13T16:49:51.5087854+02:00" Build_CSharp="true" Build_Cpp="true" /> <build BuildId="21" IssueId="18453" IssueName="TestIssueName" StartDate="2018-06-13T16:49:51.6713477+02:00" Build_CSharp="true" Build_Cpp="true" /> <build BuildId="22" IssueId="68288" IssueName="TestIssueName" StartDate="2018-06-13T16:49:51.8277942+02:00" Build_CSharp="true" Build_Cpp="true" /> <build BuildId="23" IssueId="89884" IssueName="TestIssueName" StartDate="2018-06-13T16:49:52.0151294+02:00" Build_CSharp="true" Build_Cpp="true" /> <currentbuild BuildId="13" IssueId="4491" StartDate="13.06.2018 16:53:16" /> </BuildsQueue>
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace QBuilder.AppQueue { class AuxFunctions { // public static string FormatParameters(string fileName, IDictionary<string, string> parameters) { if (String.IsNullOrWhiteSpace(fileName)) { throw new ArgumentNullException("fileName"); } if (parameters == null) { throw new ArgumentNullException("parameters"); } var macros = String.Join(" ", parameters.Select(parameter => String.Format("\"{0}={1}\"", parameter.Key, parameter.Value.Replace(@"""", @"\""")))); return String.Format("{0} /b \"{1}\"", macros, fileName); } } }
public interface IAppQueue { // [OperationContract] void PushBuild(QBuildRecord qBRecord); // [OperationContract] void TestPushBuild(); // [OperationContract] QBuildRecord PullBuild(); }
public class AppQueueService : IAppQueue { // , public AppLauncherClient buildAgent; // , private string _xmlQueueFile; public AppQueueService() { // . , . _xmlQueueFile = ConfigurationManager.AppSettings["QueueFileName"]; } public QBuildRecord PullBuild() { QBuildRecord qBr; CXmlQueue xmlQueue = new CXmlQueue(_xmlQueueFile); XElement xRoot = xmlQueue.OpenXmlQueue(); if (xRoot.XPathSelectElements("build").Any()) { qBr = new QBuildRecord(); XElement xe = xRoot.XPathSelectElements("build").FirstOrDefault(); qBr.BuildId = xe.Attribute("BuildId").Value; qBr.IssueId = xe.Attribute("IssueId").Value; qBr.IssueName = xe.Attribute("IssueName").Value; qBr.StartDate = Convert.ToDateTime(xe.Attribute("StartDate").Value); qBr.Build_CSharp = bool.Parse(xe.Attribute("Build_CSharp").Value); qBr.Build_Cpp = bool.Parse(xe.Attribute("Build_Cpp").Value); xe.Remove(); // Remove first element xRoot.Save(xmlQueue.GetQueueFileName()); return qBr; } return null; } public void PushBuild(QBuildRecord qBRecord) { CXmlQueue xmlQueue = new CXmlQueue(_xmlQueueFile); XElement xRoot = xmlQueue.OpenXmlQueue(); xRoot.Add(new XElement( "build", new XAttribute("BuildId", qBRecord.BuildId), new XAttribute("IssueId", qBRecord.IssueId), new XAttribute("IssueName", qBRecord.IssueName), new XAttribute("StartDate", qBRecord.StartDate), new XAttribute("Build_CSharp", qBRecord.Build_CSharp), new XAttribute("Build_Cpp", qBRecord.Build_Cpp) )); xRoot.Save(xmlQueue.GetQueueFileName()); } public void TestPushBuild() { CXmlQueue xmlQueue = new CXmlQueue(_xmlQueueFile); Console.WriteLine("Using queue file: {0}",xmlQueue.GetQueueFileName()); int buildIndex = xmlQueue.IncrementLastQueueBuildNumber(); Random rnd = new Random(); PushBuild (new QBuildRecord { Build_CSharp = true, Build_Cpp = true, BuildId = buildIndex.ToString(), StartDate = DateTime.Now, IssueId = rnd.Next(100000).ToString(), IssueName = "TestIssueName" } ); } }
// , private System.Timers.Timer timer; // , public QBuildRecord currentBuild; //public QBuildRecord processingBuild; // , public bool clientStarted; // public string xmlBuildQueueFileName; // public CXmlQueue xmlQueue; // public string btWorkingDir; public string btLocalDomain; public string btUserName; public string buildToolPath; public string btScriptPath; public int agentTimeoutInMinutes; // public AppQueueService buildQueueService;
// try { xmlBuildQueueFileName = ConfigurationManager.AppSettings["QueueFileName"]; buildToolPath = ConfigurationManager.AppSettings["BuildToolPath"]; btWorkingDir = ConfigurationManager.AppSettings["BuildToolWorkDir"]; btLocalDomain = ConfigurationManager.AppSettings["LocalDomain"]; btUserName = ConfigurationManager.AppSettings["UserName"]; btScriptPath = ConfigurationManager.AppSettings["ScriptPath"]; agentTimeout= 30000; // buildQueueService = new AppQueueService(); // xmlQueue = new CXmlQueue(xmlBuildQueueFileName); } catch (Exception ex) { Console.WriteLine("Error while loading configuration: {0}", ex); }
// public bool BuildIsStarted() { IAppLauncher builderAgent; try { builderAgent = new AppLauncherClient(); return builderAgent.IsStarted(); } catch (Exception ex) { return false; } }
private void TimerTick(object sender, System.Timers.ElapsedEventArgs e) { try { // if (!BuildIsStarted()) { // clientStarted, if (clientStarted) { // , clientStarted false currentBuild.FinishDate = DateTime.Now; clientStarted = false; } else { // clientStarted=false ( ) - xmlQueue.ClearCurrentBuild(); } // currentBuild = buildQueueService.PullBuild(); // , if (currentBuild != null) { // true - clientStarted = true; // currentbuild - xml xmlQueue.SetCurrentBuild(currentBuild); // var parameters = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) { {"BUILD_ID", currentBuild.BuildId}, {"ISSUE_ID", currentBuild.IssueId}, {"ISSUE_NAME", currentBuild.IssueName}, {"BUILD_CSHARP", currentBuild.Build_CSharp ? "1" : "0"}, {"BUILD_CPP", currentBuild.Build_Cpp ? "1" : "0"} }; // var arguments = AuxFunctions.FormatParameters(btScriptPath, parameters); try { // AppLauncher IAppLauncher builderAgent = new AppLauncherClient(); builderAgent.Start(buildToolPath, arguments, btWorkingDir, btLocalDomain, btUserName, agentTimeout); } catch (Exception ex) { Console.WriteLine(ex); } } } } catch (Exception ex) { Console.WriteLine(ex); } }
// OnStart protected override void OnStart(string[] args) { if (serviceHost != null) { serviceHost.Close(); } // this.timer = new System.Timers.Timer(agentTimeout); // this.timer.AutoReset = true; this.timer.Elapsed += new System.Timers.ElapsedEventHandler(this.TimerTick); this.timer.Start(); // ServiceHost AppQueueService serviceHost = new ServiceHost(typeof(AppQueueService)); // ServiceHostBase serviceHost.Open(); }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ComponentModel; using System.ServiceModel; using System.ServiceProcess; using System.Configuration; using System.Configuration.Install; using System.Reflection; using System.Xml.Linq; using System.Xml.XPath; using QBuilder.AppQueue.AppLauncherService;
<appSettings> <add key="QueueFileName" value="BuildQueue.xml"/> <add key="BuildToolPath" value="c:\temp\dummybuild.exe"/> <add key="BuildToolWorkDir" value="c:\temp\"/> <add key="LocalDomain" value="."/> <add key="UserName" value="username"/> <add key="ScriptPath" value="C:\Temp\BuildSample.bld"/> </appSettings>
<?xml version="1.0" encoding="utf-8"?> <BuildsQueue BuildNumber="23"> <build BuildId="19" IssueId="66540" IssueName="TestIssueName" StartDate="2018-06-13T16:49:51.3581274+02:00" Build_CSharp="true" Build_Cpp="true" /> <build BuildId="20" IssueId="68618" IssueName="TestIssueName" StartDate="2018-06-13T16:49:51.5087854+02:00" Build_CSharp="true" Build_Cpp="true" /> <build BuildId="21" IssueId="18453" IssueName="TestIssueName" StartDate="2018-06-13T16:49:51.6713477+02:00" Build_CSharp="true" Build_Cpp="true" /> <build BuildId="22" IssueId="68288" IssueName="TestIssueName" StartDate="2018-06-13T16:49:51.8277942+02:00" Build_CSharp="true" Build_Cpp="true" /> <build BuildId="23" IssueId="89884" IssueName="TestIssueName" StartDate="2018-06-13T16:49:52.0151294+02:00" Build_CSharp="true" Build_Cpp="true" /> <currentbuild BuildId="18" IssueId="16706" StartDate="13.06.2018 23:20:06" /> </BuildsQueue>
<?xml version="1.0" encoding="utf-8"?> <BuildsQueue BuildNumber="23"> <build BuildId="21" IssueId="18453" IssueName="TestIssueName" StartDate="2018-06-13T16:49:51.6713477+02:00" Build_CSharp="true" Build_Cpp="true" /> <build BuildId="22" IssueId="68288" IssueName="TestIssueName" StartDate="2018-06-13T16:49:51.8277942+02:00" Build_CSharp="true" Build_Cpp="true" /> <build BuildId="23" IssueId="89884" IssueName="TestIssueName" StartDate="2018-06-13T16:49:52.0151294+02:00" Build_CSharp="true" Build_Cpp="true" /> <currentbuild BuildId="20" IssueId="68618" StartDate="13.06.2018 23:24:25" /> </BuildsQueue>
Source: https://habr.com/ru/post/417701/