From 3d6264095ee1298b63c40f7c193ba6ff4021053a Mon Sep 17 00:00:00 2001 From: tidusjar Date: Fri, 24 Feb 2017 21:43:36 +0000 Subject: [PATCH] Bunch of updater files --- Ombi.Common/EnvironmentInfo/OsInfo.cs | 54 +++ Ombi.Common/EnvironmentInfo/PlatformInfo.cs | 42 +++ Ombi.Common/Ombi.Common.csproj | 61 ++++ Ombi.Common/Processes/ProcessInfo.cs | 20 ++ Ombi.Common/Processes/ProcessOutput.cs | 59 ++++ Ombi.Common/Processes/ProcessProvider.cs | 343 ++++++++++++++++++++ Ombi.Common/Properties/AssemblyInfo.cs | 36 ++ Ombi.Common/ServiceProvider.cs | 203 ++++++++++++ Ombi.Common/packages.config | 4 + Ombi.Updater/AppType.cs | 35 ++ Ombi.Updater/DetectApplicationType.cs | 39 +++ Ombi.Updater/InstallService.cs | 57 ++++ Ombi.Updater/Ombi.Updater.csproj | 15 +- Ombi.Updater/TerminateOmbi.cs | 88 +++++ Ombi.Updater/packages.config | 1 + Ombi.sln | 10 +- 16 files changed, 1063 insertions(+), 4 deletions(-) create mode 100644 Ombi.Common/EnvironmentInfo/OsInfo.cs create mode 100644 Ombi.Common/EnvironmentInfo/PlatformInfo.cs create mode 100644 Ombi.Common/Ombi.Common.csproj create mode 100644 Ombi.Common/Processes/ProcessInfo.cs create mode 100644 Ombi.Common/Processes/ProcessOutput.cs create mode 100644 Ombi.Common/Processes/ProcessProvider.cs create mode 100644 Ombi.Common/Properties/AssemblyInfo.cs create mode 100644 Ombi.Common/ServiceProvider.cs create mode 100644 Ombi.Common/packages.config create mode 100644 Ombi.Updater/AppType.cs create mode 100644 Ombi.Updater/DetectApplicationType.cs create mode 100644 Ombi.Updater/InstallService.cs create mode 100644 Ombi.Updater/TerminateOmbi.cs diff --git a/Ombi.Common/EnvironmentInfo/OsInfo.cs b/Ombi.Common/EnvironmentInfo/OsInfo.cs new file mode 100644 index 000000000..3ced6f227 --- /dev/null +++ b/Ombi.Common/EnvironmentInfo/OsInfo.cs @@ -0,0 +1,54 @@ +using System; +using System.IO; + +namespace Ombi.Common.EnvironmentInfo +{ + public class OsInfo + { + public static Os Os { get; } + + public static bool IsNotWindows => !IsWindows; + public static bool IsLinux => Os == Os.Linux; + public static bool IsOsx => Os == Os.Osx; + public static bool IsWindows => Os == Os.Windows; + + static OsInfo() + { + var platform = Environment.OSVersion.Platform; + + switch (platform) + { + case PlatformID.Win32NT: + { + Os = Os.Windows; + break; + } + case PlatformID.MacOSX: + case PlatformID.Unix: + { + // Sometimes Mac OS reports itself as Unix + if (Directory.Exists("/System/Library/CoreServices/") && + (File.Exists("/System/Library/CoreServices/SystemVersion.plist") || + File.Exists("/System/Library/CoreServices/ServerVersion.plist")) + ) + { + Os = Os.Osx; + } + else + { + Os = Os.Linux; + } + break; + } + } + } + + } + + public enum Os + { + Windows, + Linux, + Osx + } +} \ No newline at end of file diff --git a/Ombi.Common/EnvironmentInfo/PlatformInfo.cs b/Ombi.Common/EnvironmentInfo/PlatformInfo.cs new file mode 100644 index 000000000..045dc26e3 --- /dev/null +++ b/Ombi.Common/EnvironmentInfo/PlatformInfo.cs @@ -0,0 +1,42 @@ +using System; + +namespace Ombi.Common.EnvironmentInfo +{ + public enum PlatformType + { + DotNet = 0, + Mono = 1 + } + + public interface IPlatformInfo + { + Version Version { get; } + } + + public abstract class PlatformInfo : IPlatformInfo + { + static PlatformInfo() + { + Platform = Type.GetType("Mono.Runtime") != null ? PlatformType.Mono : PlatformType.DotNet; + } + + public static PlatformType Platform { get; } + public static bool IsMono => Platform == PlatformType.Mono; + public static bool IsDotNet => Platform == PlatformType.DotNet; + + public static string PlatformName + { + get + { + if (IsDotNet) + { + return ".NET"; + } + + return "Mono"; + } + } + + public abstract Version Version { get; } + } +} \ No newline at end of file diff --git a/Ombi.Common/Ombi.Common.csproj b/Ombi.Common/Ombi.Common.csproj new file mode 100644 index 000000000..c8c1a53ef --- /dev/null +++ b/Ombi.Common/Ombi.Common.csproj @@ -0,0 +1,61 @@ + + + + + Debug + AnyCPU + {BFD45569-90CF-47CA-B575-C7B0FF97F67B} + Library + Properties + Ombi.Common + Ombi.Common + v4.5 + 512 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\NLog.4.3.6\lib\net45\NLog.dll + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Ombi.Common/Processes/ProcessInfo.cs b/Ombi.Common/Processes/ProcessInfo.cs new file mode 100644 index 000000000..1686f4b80 --- /dev/null +++ b/Ombi.Common/Processes/ProcessInfo.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Ombi.Common.Processes +{ + public class ProcessInfo + { + public int Id { get; set; } + public string Name { get; set; } + public string StartPath { get; set; } + + public override string ToString() + { + return string.Format("{0}:{1} [{2}]", Id, Name ?? "Unknown", StartPath ?? "Unknown"); + } + } +} diff --git a/Ombi.Common/Processes/ProcessOutput.cs b/Ombi.Common/Processes/ProcessOutput.cs new file mode 100644 index 000000000..dc0edee2d --- /dev/null +++ b/Ombi.Common/Processes/ProcessOutput.cs @@ -0,0 +1,59 @@ + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Ombi.Common.Processes +{ + public class ProcessOutput + { + public int ExitCode { get; set; } + public List Lines { get; set; } + + public ProcessOutput() + { + Lines = new List(); + } + + public List Standard + { + get + { + return Lines.Where(c => c.Level == ProcessOutputLevel.Standard).ToList(); + } + } + + public List Error + { + get + { + return Lines.Where(c => c.Level == ProcessOutputLevel.Error).ToList(); + } + } + } + + public class ProcessOutputLine + { + public ProcessOutputLevel Level { get; set; } + public string Content { get; set; } + public DateTime Time { get; set; } + + public ProcessOutputLine(ProcessOutputLevel level, string content) + { + Level = level; + Content = content; + Time = DateTime.UtcNow; + } + + public override string ToString() + { + return string.Format("{0} - {1} - {2}", Time, Level, Content); + } + } + + public enum ProcessOutputLevel + { + Standard = 0, + Error = 1 + } +} \ No newline at end of file diff --git a/Ombi.Common/Processes/ProcessProvider.cs b/Ombi.Common/Processes/ProcessProvider.cs new file mode 100644 index 000000000..86d8d808a --- /dev/null +++ b/Ombi.Common/Processes/ProcessProvider.cs @@ -0,0 +1,343 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.ComponentModel; +using System.Diagnostics; +using System.IO; +using System.Linq; +using NLog; +using Ombi.Common.EnvironmentInfo; + +namespace Ombi.Common.Processes +{ + public interface IProcessProvider + { + int GetCurrentProcessId(); + ProcessInfo GetCurrentProcess(); + ProcessInfo GetProcessById(int id); + List FindProcessByName(string name); + void OpenDefaultBrowser(string url); + void WaitForExit(System.Diagnostics.Process process); + void SetPriority(int processId, ProcessPriorityClass priority); + void KillAll(string processName); + void Kill(int processId); + bool Exists(int processId); + bool Exists(string processName); + ProcessPriorityClass GetCurrentProcessPriority(); + System.Diagnostics.Process Start(string path, string args = null, StringDictionary environmentVariables = null, Action onOutputDataReceived = null, Action onErrorDataReceived = null); + System.Diagnostics.Process SpawnNewProcess(string path, string args = null, StringDictionary environmentVariables = null); + ProcessOutput StartAndCapture(string path, string args = null, StringDictionary environmentVariables = null); + } + + public class ProcessProvider : IProcessProvider + { + + private static readonly Logger _logger = LogManager.GetCurrentClassLogger(); + + public const string OmbiProcessName = "Ombi"; + + //public ProcessProvider(Logger logger) + //{ + // _logger = logger; + //} + + public int GetCurrentProcessId() + { + return Process.GetCurrentProcess().Id; + } + + public ProcessInfo GetCurrentProcess() + { + return ConvertToProcessInfo(Process.GetCurrentProcess()); + } + + public bool Exists(int processId) + { + return GetProcessById(processId) != null; + } + + public bool Exists(string processName) + { + return GetProcessesByName(processName).Any(); + } + + public ProcessPriorityClass GetCurrentProcessPriority() + { + return Process.GetCurrentProcess().PriorityClass; + } + + public ProcessInfo GetProcessById(int id) + { + _logger.Debug("Finding process with Id:{0}", id); + + var processInfo = ConvertToProcessInfo(Process.GetProcesses().FirstOrDefault(p => p.Id == id)); + + if (processInfo == null) + { + _logger.Warn("Unable to find process with ID {0}", id); + } + else + { + _logger.Debug("Found process {0}", processInfo.ToString()); + } + + return processInfo; + } + + public List FindProcessByName(string name) + { + return GetProcessesByName(name).Select(ConvertToProcessInfo).Where(c => c != null).ToList(); + } + + public void OpenDefaultBrowser(string url) + { + _logger.Info("Opening URL [{0}]", url); + + var process = new Process + { + StartInfo = new ProcessStartInfo(url) + { + UseShellExecute = true + } + }; + + process.Start(); + } + + public Process Start(string path, string args = null, StringDictionary environmentVariables = null, Action onOutputDataReceived = null, Action onErrorDataReceived = null) + { + if (PlatformInfo.IsMono && path.EndsWith(".exe", StringComparison.InvariantCultureIgnoreCase)) + { + args = GetMonoArgs(path, args); + path = "mono"; + } + + var logger = LogManager.GetLogger(new FileInfo(path).Name); + + var startInfo = new ProcessStartInfo(path, args) + { + CreateNoWindow = true, + UseShellExecute = false, + RedirectStandardError = true, + RedirectStandardOutput = true, + RedirectStandardInput = true + }; + + if (environmentVariables != null) + { + foreach (DictionaryEntry environmentVariable in environmentVariables) + { + startInfo.EnvironmentVariables.Add(environmentVariable.Key.ToString(), environmentVariable.Value.ToString()); + } + } + + logger.Debug("Starting {0} {1}", path, args); + + var process = new Process + { + StartInfo = startInfo + }; + + process.OutputDataReceived += (sender, eventArgs) => + { + if (string.IsNullOrWhiteSpace(eventArgs.Data)) return; + + logger.Debug(eventArgs.Data); + + onOutputDataReceived?.Invoke(eventArgs.Data); + }; + + process.ErrorDataReceived += (sender, eventArgs) => + { + if (string.IsNullOrWhiteSpace(eventArgs.Data)) return; + + logger.Error(eventArgs.Data); + + onErrorDataReceived?.Invoke(eventArgs.Data); + }; + + process.Start(); + + process.BeginErrorReadLine(); + process.BeginOutputReadLine(); + + return process; + } + + public Process SpawnNewProcess(string path, string args = null, StringDictionary environmentVariables = null) + { + if (PlatformInfo.IsMono && path.EndsWith(".exe", StringComparison.InvariantCultureIgnoreCase)) + { + args = GetMonoArgs(path, args); + path = "mono"; + } + + _logger.Debug("Starting {0} {1}", path, args); + + var startInfo = new ProcessStartInfo(path, args); + var process = new Process + { + StartInfo = startInfo + }; + + process.Start(); + + return process; + } + + public ProcessOutput StartAndCapture(string path, string args = null, StringDictionary environmentVariables = null) + { + var output = new ProcessOutput(); + var process = Start(path, args, environmentVariables, s => output.Lines.Add(new ProcessOutputLine(ProcessOutputLevel.Standard, s)), + error => output.Lines.Add(new ProcessOutputLine(ProcessOutputLevel.Error, error))); + + process.WaitForExit(); + output.ExitCode = process.ExitCode; + + return output; + } + + public void WaitForExit(Process process) + { + _logger.Debug("Waiting for process {0} to exit.", process.ProcessName); + + process.WaitForExit(); + } + + public void SetPriority(int processId, ProcessPriorityClass priority) + { + var process = Process.GetProcessById(processId); + + _logger.Info("Updating [{0}] process priority from {1} to {2}", + process.ProcessName, + process.PriorityClass, + priority); + + process.PriorityClass = priority; + } + + public void Kill(int processId) + { + var process = Process.GetProcesses().FirstOrDefault(p => p.Id == processId); + + if (process == null) + { + _logger.Warn("Cannot find process with id: {0}", processId); + return; + } + + process.Refresh(); + + if (process.Id != Process.GetCurrentProcess().Id && process.HasExited) + { + _logger.Debug("Process has already exited"); + return; + } + + _logger.Info("[{0}]: Killing process", process.Id); + process.Kill(); + _logger.Info("[{0}]: Waiting for exit", process.Id); + process.WaitForExit(); + _logger.Info("[{0}]: Process terminated successfully", process.Id); + } + + public void KillAll(string processName) + { + var processes = GetProcessesByName(processName); + + _logger.Debug("Found {0} processes to kill", processes.Count); + + foreach (var processInfo in processes) + { + if (processInfo.Id == Process.GetCurrentProcess().Id) + { + _logger.Debug("Tried killing own process, skipping: {0} [{1}]", processInfo.Id, processInfo.ProcessName); + continue; + } + + _logger.Debug("Killing process: {0} [{1}]", processInfo.Id, processInfo.ProcessName); + Kill(processInfo.Id); + } + } + + private ProcessInfo ConvertToProcessInfo(Process process) + { + if (process == null) return null; + + process.Refresh(); + + ProcessInfo processInfo = null; + + try + { + if (process.Id <= 0) return null; + + processInfo = new ProcessInfo + { + Id = process.Id, + Name = process.ProcessName, + StartPath = GetExeFileName(process) + }; + + if (process.Id != Process.GetCurrentProcess().Id && process.HasExited) + { + processInfo = null; + } + } + catch (Win32Exception e) + { + _logger.Warn(e, "Couldn't get process info for " + process.ProcessName); + } + + return processInfo; + + } + + private static string GetExeFileName(Process process) + { + if (process.MainModule.FileName != "mono.exe") + { + return process.MainModule.FileName; + } + + return process.Modules.Cast().FirstOrDefault(module => module.ModuleName.ToLower().EndsWith(".exe")).FileName; + } + + private List GetProcessesByName(string name) + { + //TODO: move this to an OS specific class + + var monoProcesses = Process.GetProcessesByName("mono") + .Union(Process.GetProcessesByName("mono-sgen")) + .Where(process => + process.Modules.Cast() + .Any(module => + module.ModuleName.ToLower() == name.ToLower() + ".exe")); + + var processes = Process.GetProcessesByName(name) + .Union(monoProcesses).ToList(); + + _logger.Debug("Found {0} processes with the name: {1}", processes.Count, name); + + try + { + foreach (var process in processes) + { + _logger.Debug(" - [{0}] {1}", process.Id, process.ProcessName); + } + } + catch + { + // Don't crash on gettings some log data. + } + + return processes; + } + + private string GetMonoArgs(string path, string args) + { + return string.Format("--debug {0} {1}", path, args); + } + } +} diff --git a/Ombi.Common/Properties/AssemblyInfo.cs b/Ombi.Common/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..af987bb95 --- /dev/null +++ b/Ombi.Common/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +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("Ombi.Common")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Ombi.Common")] +[assembly: AssemblyCopyright("Copyright © 2017")] +[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("bfd45569-90cf-47ca-b575-c7b0ff97f67b")] + +// 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/Ombi.Common/ServiceProvider.cs b/Ombi.Common/ServiceProvider.cs new file mode 100644 index 000000000..4441e7291 --- /dev/null +++ b/Ombi.Common/ServiceProvider.cs @@ -0,0 +1,203 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2017 Jamie Rees +// File: ServiceProvider.cs +// Created By: Jamie Rees +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// ************************************************************************/ +#endregion + +using System; +using System.Collections.Specialized; +using System.Configuration.Install; +using System.Diagnostics; +using System.Linq; +using System.ServiceProcess; +using NLog; +using Ombi.Common.Processes; + +namespace Ombi.Common +{ + public interface IServiceProvider + { + bool ServiceExist(string name); + bool IsServiceRunning(string name); + void Install(string serviceName); + void Run(ServiceBase service); + ServiceController GetService(string serviceName); + void Stop(string serviceName); + void Start(string serviceName); + ServiceControllerStatus GetStatus(string serviceName); + void Restart(string serviceName); + } + + public class ServiceProvider : IServiceProvider + { + public const string OmbiServiceName = "Ombi"; + + private readonly IProcessProvider _processProvider; + + private static readonly Logger _logger = LogManager.GetCurrentClassLogger(); + + + public ServiceProvider(IProcessProvider processProvider) + { + _processProvider = processProvider; + } + + public virtual bool ServiceExist(string name) + { + _logger.Debug("Checking if service {0} exists.", name); + return + ServiceController.GetServices().Any( + s => string.Equals(s.ServiceName, name, StringComparison.InvariantCultureIgnoreCase)); + } + + public virtual bool IsServiceRunning(string name) + { + _logger.Debug("Checking if '{0}' service is running", name); + + var service = ServiceController.GetServices() + .SingleOrDefault(s => string.Equals(s.ServiceName, name, StringComparison.InvariantCultureIgnoreCase)); + + return service != null && ( + service.Status != ServiceControllerStatus.Stopped || + service.Status == ServiceControllerStatus.StopPending || + service.Status == ServiceControllerStatus.Paused || + service.Status == ServiceControllerStatus.PausePending); + } + + public virtual void Install(string serviceName) + { + _logger.Info("Installing service '{0}'", serviceName); + + + var installer = new ServiceProcessInstaller + { + Account = ServiceAccount.LocalSystem + }; + + var serviceInstaller = new ServiceInstaller(); + + + string[] cmdline = { @"/assemblypath=" + Process.GetCurrentProcess().MainModule.FileName }; + + var context = new InstallContext("service_install.log", cmdline); + serviceInstaller.Context = context; + serviceInstaller.DisplayName = serviceName; + serviceInstaller.ServiceName = serviceName; + serviceInstaller.Description = "Ombi Application Server"; + serviceInstaller.StartType = ServiceStartMode.Automatic; + serviceInstaller.ServicesDependedOn = new[] { "EventLog", "Tcpip", "http" }; + + serviceInstaller.Parent = installer; + + serviceInstaller.Install(new ListDictionary()); + + _logger.Info("Service Has installed successfully."); + } + + public virtual void Run(ServiceBase service) + { + ServiceBase.Run(service); + } + + public virtual ServiceController GetService(string serviceName) + { + return ServiceController.GetServices().FirstOrDefault(c => string.Equals(c.ServiceName, serviceName, StringComparison.InvariantCultureIgnoreCase)); + } + + public virtual void Stop(string serviceName) + { + _logger.Info("Stopping {0} Service...", serviceName); + var service = GetService(serviceName); + if (service == null) + { + _logger.Warn("Unable to stop {0}. no service with that name exists.", serviceName); + return; + } + + _logger.Info("Service is currently {0}", service.Status); + + if (service.Status != ServiceControllerStatus.Stopped) + { + service.Stop(); + service.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(60)); + + service.Refresh(); + if (service.Status == ServiceControllerStatus.Stopped) + { + _logger.Info("{0} has stopped successfully.", serviceName); + } + else + { + _logger.Error("Service stop request has timed out. {0}", service.Status); + } + } + else + { + _logger.Warn("Service {0} is already in stopped state.", service.ServiceName); + } + } + + public ServiceControllerStatus GetStatus(string serviceName) + { + return GetService(serviceName).Status; + } + + public void Start(string serviceName) + { + _logger.Info("Starting {0} Service...", serviceName); + var service = GetService(serviceName); + if (service == null) + { + _logger.Warn("Unable to start '{0}' no service with that name exists.", serviceName); + return; + } + + if (service.Status != ServiceControllerStatus.Paused && service.Status != ServiceControllerStatus.Stopped) + { + _logger.Warn("Service is in a state that can't be started. Current status: {0}", service.Status); + } + + service.Start(); + + service.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromSeconds(60)); + service.Refresh(); + + if (service.Status == ServiceControllerStatus.Running) + { + _logger.Info("{0} has started successfully.", serviceName); + } + else + { + _logger.Error("Service start request has timed out. {0}", service.Status); + } + } + + public void Restart(string serviceName) + { + var args = string.Format("/C net.exe stop \"{0}\" && net.exe start \"{0}\"", serviceName); + + _processProvider.Start("cmd.exe", args); + } + } +} \ No newline at end of file diff --git a/Ombi.Common/packages.config b/Ombi.Common/packages.config new file mode 100644 index 000000000..f05a0e060 --- /dev/null +++ b/Ombi.Common/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Ombi.Updater/AppType.cs b/Ombi.Updater/AppType.cs new file mode 100644 index 000000000..a75a95675 --- /dev/null +++ b/Ombi.Updater/AppType.cs @@ -0,0 +1,35 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2017 Jamie Rees +// File: AppType.cs +// Created By: Jamie Rees +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// ************************************************************************/ +#endregion +namespace Ombi.Updater +{ + public enum AppType + { + Normal, + Console, + Service + } +} \ No newline at end of file diff --git a/Ombi.Updater/DetectApplicationType.cs b/Ombi.Updater/DetectApplicationType.cs new file mode 100644 index 000000000..73e50231a --- /dev/null +++ b/Ombi.Updater/DetectApplicationType.cs @@ -0,0 +1,39 @@ +using Ombi.Common; +using Ombi.Common.EnvironmentInfo; +using Ombi.Common.Processes; + +namespace Ombi.Updater +{ + public class DetectApplicationType + { + public DetectApplicationType() + { + _processProvider = new ProcessProvider(); + _serviceProvider = new ServiceProvider(_processProvider); + } + + private readonly IServiceProvider _serviceProvider; + private readonly IProcessProvider _processProvider; + public AppType GetAppType() + { + if (OsInfo.IsNotWindows) + { + // Technically it is the console, but it has been renamed for mono (Linux/OS X) + return AppType.Normal; + } + + if (_serviceProvider.ServiceExist(ServiceProvider.OmbiServiceName) + ) + { + return AppType.Service; + } + + if (_processProvider.Exists(ProcessProvider.OmbiProcessName)) + { + return AppType.Console; + } + + return AppType.Normal; + } + } +} diff --git a/Ombi.Updater/InstallService.cs b/Ombi.Updater/InstallService.cs new file mode 100644 index 000000000..502f2ae39 --- /dev/null +++ b/Ombi.Updater/InstallService.cs @@ -0,0 +1,57 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2017 Jamie Rees +// File: InstallService.cs +// Created By: Jamie Rees +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// ************************************************************************/ +#endregion + +using System.Linq; +using Ombi.Common; +using Ombi.Common.EnvironmentInfo; +using Ombi.Common.Processes; + +namespace Ombi.Updater +{ + public class InstallService + { + public void Start(string installFolder) + { + var dector = new DetectApplicationType(); + var processProvider = new ProcessProvider(); + + var processId = processProvider.FindProcessByName(ProcessProvider.OmbiProcessName)?.FirstOrDefault()?.Id ?? -1; + + // Log if process is -1 + + var appType = dector.GetAppType(); + processProvider.FindProcessByName(ProcessProvider.OmbiProcessName); + + if (OsInfo.IsWindows) + { + var terminator = new TerminateOmbi(new ServiceProvider(processProvider), processProvider); + terminator.Terminate(processId); + } + + } + } +} \ No newline at end of file diff --git a/Ombi.Updater/Ombi.Updater.csproj b/Ombi.Updater/Ombi.Updater.csproj index 5e0641ded..881b9badd 100644 --- a/Ombi.Updater/Ombi.Updater.csproj +++ b/Ombi.Updater/Ombi.Updater.csproj @@ -13,7 +13,7 @@ true full false - bin\Debug + bin\Debug\Updater\ DEBUG; prompt 4 @@ -22,12 +22,15 @@ full true - bin\Release + bin\Release\Updater\ prompt 4 true + + ..\packages\NLog.4.3.6\lib\net45\NLog.dll + ..\packages\Polly-Signed.4.3.0\lib\net45\Polly.dll True @@ -38,12 +41,20 @@ + + + + + + {bfd45569-90cf-47ca-b575-c7b0ff97f67b} + Ombi.Common + {DD7DC444-D3BF-4027-8AB9-EFC71F5EC581} Ombi.Core diff --git a/Ombi.Updater/TerminateOmbi.cs b/Ombi.Updater/TerminateOmbi.cs new file mode 100644 index 000000000..f72bc54d2 --- /dev/null +++ b/Ombi.Updater/TerminateOmbi.cs @@ -0,0 +1,88 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2017 Jamie Rees +// File: TerminateOmbi.cs +// Created By: Jamie Rees +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// ************************************************************************/ +#endregion + +using System; +using NLog; +using Ombi.Common; +using Ombi.Common.EnvironmentInfo; +using Ombi.Common.Processes; +using IServiceProvider = Ombi.Common.IServiceProvider; + +namespace Ombi.Updater +{ + public interface ITerminateOmbi + { + void Terminate(int processId); + } + + public class TerminateOmbi : ITerminateOmbi + { + private readonly IServiceProvider _serviceProvider; + private readonly IProcessProvider _processProvider; + + private static Logger _logger = LogManager.GetCurrentClassLogger(); + + public TerminateOmbi(IServiceProvider serviceProvider, IProcessProvider processProvider) + { + _serviceProvider = serviceProvider; + _processProvider = processProvider; + } + + public void Terminate(int processId) + { + if (OsInfo.IsWindows) + { + _logger.Info("Stopping all running services"); + + if (_serviceProvider.ServiceExist(ServiceProvider.OmbiServiceName)) + { + try + { + _logger.Info("NzbDrone Service is installed and running"); + _serviceProvider.Stop(ServiceProvider.OmbiServiceName); + } + catch (Exception e) + { + _logger.Error(e, "couldn't stop service"); + } + } + + _logger.Info("Killing all running processes"); + + _processProvider.KillAll(ProcessProvider.OmbiProcessName); + } + else + { + _logger.Info("Killing all running processes"); + + _processProvider.KillAll(ProcessProvider.OmbiProcessName); + + _processProvider.Kill(processId); + } + } + } +} \ No newline at end of file diff --git a/Ombi.Updater/packages.config b/Ombi.Updater/packages.config index 4a06c0f59..6bc1f0299 100644 --- a/Ombi.Updater/packages.config +++ b/Ombi.Updater/packages.config @@ -1,4 +1,5 @@  + \ No newline at end of file diff --git a/Ombi.sln b/Ombi.sln index 984651728..2eefc0648 100644 --- a/Ombi.sln +++ b/Ombi.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 +# Visual Studio 15 +VisualStudioVersion = 15.0.26206.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.UI", "Ombi.UI\Ombi.UI.csproj", "{68F5F5F3-B8BB-4911-875F-6F00AAE04EA6}" EndProject @@ -39,6 +39,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Helpers.Tests", "Ombi. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Core.Migration", "Ombi.Core.Migration\Ombi.Core.Migration.csproj", "{8406EE57-D533-47C0-9302-C6B5F8C31E55}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Common", "Ombi.Common\Ombi.Common.csproj", "{BFD45569-90CF-47CA-B575-C7B0FF97F67B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -97,6 +99,10 @@ Global {8406EE57-D533-47C0-9302-C6B5F8C31E55}.Debug|Any CPU.Build.0 = Debug|Any CPU {8406EE57-D533-47C0-9302-C6B5F8C31E55}.Release|Any CPU.ActiveCfg = Release|Any CPU {8406EE57-D533-47C0-9302-C6B5F8C31E55}.Release|Any CPU.Build.0 = Release|Any CPU + {BFD45569-90CF-47CA-B575-C7B0FF97F67B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BFD45569-90CF-47CA-B575-C7B0FF97F67B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BFD45569-90CF-47CA-B575-C7B0FF97F67B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BFD45569-90CF-47CA-B575-C7B0FF97F67B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE