Fixed #1760 and improvements on the auto updater.

We may now support windows services... #1460
pull/1653/merge
Jamie 7 years ago
parent 3edb4a485a
commit 02135bc550

@ -0,0 +1,10 @@
using System.Runtime.InteropServices;
using Ombi.Settings.Settings.Models;
namespace Ombi.Core.Models.UI
{
public class UpdateSettingsViewModel : UpdateSettings
{
public bool IsWindows => RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
}
}

@ -1,5 +1,6 @@
using System.Security.Principal; using System.Threading.Tasks;
using System.Threading.Tasks; using Microsoft.EntityFrameworkCore;
using Ombi.Core.Authentication;
using Ombi.Core.Rule.Interfaces; using Ombi.Core.Rule.Interfaces;
using Ombi.Helpers; using Ombi.Helpers;
using Ombi.Store.Entities; using Ombi.Store.Entities;
@ -9,40 +10,38 @@ namespace Ombi.Core.Rule.Rules.Specific
{ {
public class SendNotificationRule : SpecificRule, ISpecificRule<object> public class SendNotificationRule : SpecificRule, ISpecificRule<object>
{ {
public SendNotificationRule(IPrincipal principal) public SendNotificationRule(OmbiUserManager um)
{ {
User = principal; UserManager = um;
} }
public override SpecificRules Rule => SpecificRules.CanSendNotification; public override SpecificRules Rule => SpecificRules.CanSendNotification;
private IPrincipal User { get; } private OmbiUserManager UserManager { get; }
public Task<RuleResult> Execute(object obj) public async Task<RuleResult> Execute(object obj)
{ {
var req = (BaseRequest)obj; var req = (BaseRequest)obj;
var sendNotification = !req.Approved; /*|| !prSettings.IgnoreNotifyForAutoApprovedRequests;*/ var sendNotification = !req.Approved; /*|| !prSettings.IgnoreNotifyForAutoApprovedRequests;*/
var requestedUser = await UserManager.Users.FirstOrDefaultAsync(x => x.Id == req.RequestedUserId);
if (req.RequestType == RequestType.Movie) if (req.RequestType == RequestType.Movie)
{ {
sendNotification = !User.IsInRole(OmbiRoles.AutoApproveMovie); sendNotification = !await UserManager.IsInRoleAsync(requestedUser, OmbiRoles.AutoApproveMovie);
} }
else if(req.RequestType == RequestType.TvShow) else if(req.RequestType == RequestType.TvShow)
{ {
sendNotification = !User.IsInRole(OmbiRoles.AutoApproveTv); sendNotification = !await UserManager.IsInRoleAsync(requestedUser, OmbiRoles.AutoApproveTv);
} }
if (await UserManager.IsInRoleAsync(requestedUser, OmbiRoles.Admin))
if (User.IsInRole(OmbiRoles.Admin))
{ {
sendNotification = false; // Don't bother sending a notification if the user is an admin sendNotification = false; // Don't bother sending a notification if the user is an admin
} }
return new RuleResult
return Task.FromResult(new RuleResult
{ {
Success = sendNotification Success = sendNotification
}); };
} }
} }
} }

@ -1,5 +1,6 @@
using AutoMapper; using AutoMapper;
using Ombi.Core.Models.UI; using Ombi.Core.Models.UI;
using Ombi.Settings.Settings.Models;
using Ombi.Settings.Settings.Models.Notifications; using Ombi.Settings.Settings.Models.Notifications;
namespace Ombi.Mapping.Profiles namespace Ombi.Mapping.Profiles
@ -15,6 +16,7 @@ namespace Ombi.Mapping.Profiles
CreateMap<PushoverNotificationViewModel, PushoverSettings>().ReverseMap(); CreateMap<PushoverNotificationViewModel, PushoverSettings>().ReverseMap();
CreateMap<MattermostNotificationsViewModel, MattermostNotificationSettings>().ReverseMap(); CreateMap<MattermostNotificationsViewModel, MattermostNotificationSettings>().ReverseMap();
CreateMap<TelegramNotificationsViewModel, TelegramSettings>().ReverseMap(); CreateMap<TelegramNotificationsViewModel, TelegramSettings>().ReverseMap();
CreateMap<UpdateSettingsViewModel, UpdateSettings>().ReverseMap();
} }
} }
} }

@ -8,6 +8,7 @@ using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Reflection; using System.Reflection;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Hangfire; using Hangfire;
using Hangfire.Console; using Hangfire.Console;
@ -144,7 +145,8 @@ namespace Ombi.Schedule.Jobs.Ombi
// Temp Path // Temp Path
Directory.CreateDirectory(tempPath); Directory.CreateDirectory(tempPath);
if (settings.UseScript)
if (settings.UseScript && !settings.WindowsService)
{ {
RunScript(settings, download.Url); RunScript(settings, download.Url);
return; return;
@ -188,7 +190,6 @@ namespace Ombi.Schedule.Jobs.Ombi
var updaterFile = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), var updaterFile = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location),
"TempUpdate", $"Ombi.Updater{updaterExtension}"); "TempUpdate", $"Ombi.Updater{updaterExtension}");
// There must be an update // There must be an update
var start = new ProcessStartInfo var start = new ProcessStartInfo
{ {
@ -229,7 +230,31 @@ namespace Ombi.Schedule.Jobs.Ombi
var currentLocation = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); var currentLocation = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
var processName = (settings.ProcessName.HasValue() ? settings.ProcessName : "Ombi"); var processName = (settings.ProcessName.HasValue() ? settings.ProcessName : "Ombi");
return string.Join(" ", currentLocation, processName, url?.Value ?? string.Empty, storage?.Value ?? string.Empty); var sb = new StringBuilder();
sb.Append($"--applicationPath \"{currentLocation}\" --processname \"{processName}\" " );
if (settings.WindowsService)
{
sb.Append($"--windowsServiceName \"{settings.WindowsServiceName}\" ");
}
var sb2 = new StringBuilder();
var hasStartupArgs = false;
if (url?.Value.HasValue() ?? false)
{
hasStartupArgs = true;
sb2.Append(url.Value);
}
if (storage?.Value.HasValue() ?? false)
{
hasStartupArgs = true;
sb2.Append(storage.Value);
}
if (hasStartupArgs)
{
sb.Append($"--startupArgs {sb2.ToString()}");
}
return sb.ToString();
//return string.Join(" ", currentLocation, processName, url?.Value ?? string.Empty, storage?.Value ?? string.Empty);
} }
private void RunScript(UpdateSettings settings, string downloadUrl) private void RunScript(UpdateSettings settings, string downloadUrl)

@ -6,8 +6,9 @@
public string Username { get; set; } public string Username { get; set; }
public string Password { get; set; } public string Password { get; set; }
public string ProcessName { get; set; } public string ProcessName { get; set; }
public bool UseScript { get; set; } public bool UseScript { get; set; }
public string ScriptLocation { get; set; } public string ScriptLocation { get; set; }
public string WindowsServiceName { get; set; }
public bool WindowsService { get; set; }
} }
} }

@ -11,7 +11,7 @@ namespace Ombi.Updater
ProcessInfo GetCurrentProcess(); ProcessInfo GetCurrentProcess();
int GetCurrentProcessId(); int GetCurrentProcessId();
ProcessInfo GetProcessById(int id); ProcessInfo GetProcessById(int id);
void Kill(int processId); void Kill(StartupOptions opts);
void KillAll(string processName); void KillAll(string processName);
void SetPriority(int processId, ProcessPriorityClass priority); void SetPriority(int processId, ProcessPriorityClass priority);
void WaitForExit(Process process); void WaitForExit(Process process);

@ -21,7 +21,7 @@ namespace Ombi.Updater
{ {
// Kill Ombi Process // Kill Ombi Process
var p = new ProcessProvider(); var p = new ProcessProvider();
p.Kill(opt.OmbiProcessId); p.Kill(opt);
// Make sure the process has been killed // Make sure the process has been killed
while (p.FindProcessByName(opt.ProcessName).Any()) while (p.FindProcessByName(opt.ProcessName).Any())
@ -32,7 +32,8 @@ namespace Ombi.Updater
if (proc != null) if (proc != null)
{ {
_log.LogDebug($"[{proc.Id}] - {proc.Name} - Path: {proc.StartPath}"); _log.LogDebug($"[{proc.Id}] - {proc.Name} - Path: {proc.StartPath}");
p.Kill(proc.Id); opt.OmbiProcessId = proc.Id;
p.Kill(opt);
} }
} }
@ -51,18 +52,36 @@ namespace Ombi.Updater
{ {
fileName = "Ombi"; fileName = "Ombi";
} }
if (options.IsWindowsService)
var start = new ProcessStartInfo
{ {
UseShellExecute = false, var startInfo =
FileName = Path.Combine(options.ApplicationPath,fileName), new ProcessStartInfo
WorkingDirectory = options.ApplicationPath, {
Arguments = options.StartupArgs WindowStyle = ProcessWindowStyle.Hidden,
}; FileName = "cmd.exe",
using (var proc = new Process { StartInfo = start }) Arguments = $"/C net start \"{options.WindowsServiceName}\""
};
using (var process = new Process{StartInfo = startInfo})
{
process.Start();
}
}
else
{ {
proc.Start(); var start = new ProcessStartInfo
{
UseShellExecute = false,
FileName = Path.Combine(options.ApplicationPath, fileName),
WorkingDirectory = options.ApplicationPath,
Arguments = options.StartupArgs
};
using (var proc = new Process { StartInfo = start })
{
proc.Start();
}
} }
_log.LogDebug("Ombi started, now exiting"); _log.LogDebug("Ombi started, now exiting");
Environment.Exit(0); Environment.Exit(0);
} }

@ -11,19 +11,13 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="CommandLineParser" Version="2.1.1-beta" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="2.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="2.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="2.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="2.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.0.0" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.0.0" /> <PackageReference Include="Microsoft.Extensions.Logging" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.0.0" /> <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.0.0" /> <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.0.0" />
<PackageReference Include="Serilog" Version="2.6.0-dev-00892" /> <PackageReference Include="Serilog" Version="2.6.0-dev-00892" />

@ -73,29 +73,46 @@ namespace Ombi.Updater
process.PriorityClass = priority; process.PriorityClass = priority;
} }
public void Kill(int processId) public void Kill(StartupOptions opts)
{ {
var process = Process.GetProcesses().FirstOrDefault(p => p.Id == processId); if (opts.IsWindowsService)
if (process == null)
{ {
Console.WriteLine("Cannot find process with id: {0}", processId); Console.WriteLine("Stopping Service {0}", opts.WindowsServiceName);
return; var process = new Process();
var startInfo =
new ProcessStartInfo
{
WindowStyle = ProcessWindowStyle.Hidden,
FileName = "cmd.exe",
Arguments = $"/C net stop \"{opts.WindowsServiceName}\""
};
process.StartInfo = startInfo;
process.Start();
} }
else
{
var process = Process.GetProcesses().FirstOrDefault(p => p.Id == opts.OmbiProcessId);
process.Refresh(); if (process == null)
{
Console.WriteLine("Cannot find process with id: {0}", opts.OmbiProcessId);
return;
}
if (process.Id != Process.GetCurrentProcess().Id && process.HasExited) process.Refresh();
{
Console.WriteLine("Process has already exited");
return;
}
Console.WriteLine("[{0}]: Killing process", process.Id); if (process.Id != Process.GetCurrentProcess().Id && process.HasExited)
process.Kill(); {
Console.WriteLine("[{0}]: Waiting for exit", process.Id); Console.WriteLine("Process has already exited");
process.WaitForExit(); return;
Console.WriteLine("[{0}]: Process terminated successfully", process.Id); }
Console.WriteLine("[{0}]: Killing process", process.Id);
process.Kill();
Console.WriteLine("[{0}]: Waiting for exit", process.Id);
process.WaitForExit();
Console.WriteLine("[{0}]: Process terminated successfully", process.Id);
}
} }
public void KillAll(string processName) public void KillAll(string processName)
@ -113,7 +130,7 @@ namespace Ombi.Updater
} }
Console.WriteLine("Killing process: {0} [{1}]", processInfo.Id, processInfo.ProcessName); Console.WriteLine("Killing process: {0} [{1}]", processInfo.Id, processInfo.ProcessName);
Kill(processInfo.Id); Kill(new StartupOptions{OmbiProcessId = processInfo.Id});
} }
} }

@ -2,6 +2,7 @@
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using CommandLine;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@ -62,39 +63,26 @@ namespace Ombi.Updater
private static StartupOptions CheckArgs(string[] args) private static StartupOptions CheckArgs(string[] args)
{ {
if(args.Length <= 1) var result = Parser.Default.ParseArguments<StartupOptions>(args);
{ StartupOptions opts = null;
Console.WriteLine("No Args Provided... Exiting"); result.WithParsed(options => opts = options);
Environment.Exit(1); return opts;
}
var startup = new StartupOptions
{
ApplicationPath = args[0],
ProcessName = args[1],
};
if (args.Length == 4)
{
startup.StartupArgs = args[2] + " " + args[3];
}
else if (args.Length == 3)
{
startup.StartupArgs = args[2];
}
var p = new ProcessProvider();
var ombiProc = p.FindProcessByName(startup.ProcessName).FirstOrDefault();
startup.OmbiProcessId = ombiProc?.Id ?? -1;
return startup;
} }
} }
public class StartupOptions public class StartupOptions
{ {
[Option("processname", Required = false, Default = "Ombi")]
public string ProcessName { get; set; } public string ProcessName { get; set; }
[Option("applicationPath", Required = false)]
public string ApplicationPath { get; set; } public string ApplicationPath { get; set; }
[Option("processId", Required = false)]
public int OmbiProcessId { get; set; } public int OmbiProcessId { get; set; }
[Option("startupArgs", Required = false)]
public string StartupArgs { get; set; } public string StartupArgs { get; set; }
[Option("windowsServiceName", Required = false)]
public string WindowsServiceName { get; set; }
public bool IsWindowsService => !string.IsNullOrEmpty(WindowsServiceName);
} }
} }

@ -2,7 +2,7 @@
"profiles": { "profiles": {
"Ombi.Updater": { "Ombi.Updater": {
"commandName": "Project", "commandName": "Project",
"commandLineArgs": "C:\\Users\\Jamie.Rees\\Source\\Repos\\PlexRequests.Net\\src\\Ombi\\bin\\Debug\\netcoreapp1.1 zip" "commandLineArgs": "--applicationPath C:\\\\Users\\\\Jamie.Rees\\\\Source\\\\Repos\\\\test\\\\Ombi\\\\src\\\\Ombi\\\\bin\\\\Debug\\\\netcoreapp2.0 --processname Ombi --windowsServiceName \"World Wide Publishing Service\" --startupArgs http://*:5000"
} }
} }
} }

@ -22,6 +22,9 @@ export interface IUpdateSettings extends ISettings {
processName: string; processName: string;
useScript: boolean; useScript: boolean;
scriptLocation: string; scriptLocation: string;
windowsService: boolean;
windowsServiceName: string;
isWindows: boolean;
} }
export interface IEmbySettings extends ISettings { export interface IEmbySettings extends ISettings {

@ -20,15 +20,31 @@
<label for="autoUpdateEnabled">Enable Automatic Update</label> <label for="autoUpdateEnabled">Enable Automatic Update</label>
</div> </div>
</div> </div>
<div class="form-group" *ngIf="isWindows">
<div class="checkbox">
<input type="checkbox" id="windowsService" formControlName="windowsService">
<label for="windowsService">Running as a Windows Service</label>
</div>
</div>
<div class="form-group"> <div class="form-group" *ngIf="!form.value.windowsService">
<div class="checkbox"> <div class="checkbox">
<input type="checkbox" id="useScript" formControlName="useScript"> <input type="checkbox" id="useScript" formControlName="useScript">
<label for="useScript">Use your own updater script</label> <label for="useScript">Use your own updater script</label>
</div> </div>
</div> </div>
<div [hidden]="!useScript">
<div *ngIf="form.value.windowsService">
<div class="form-group">
<label for="windowsServiceName" class="control-label">Windows Service Name</label>
<input type="text" class="form-control form-control-custom " id="windowsServiceName" name="windowsServiceName" formControlName="windowsServiceName">
</div>
</div>
<div [hidden]="!useScript || form.value.windowsService">
<small>For information how to use this, please press the wiki button at the top of the page</small> <small>For information how to use this, please press the wiki button at the top of the page</small>
<div class="form-group"> <div class="form-group">
<label for="scriptLocation" class="control-label">Script Path</label> <label for="scriptLocation" class="control-label">Script Path</label>
@ -37,7 +53,7 @@
</div> </div>
<div [hidden]="useScript"> <div [hidden]="useScript || form.value.windowsService">
<small >By default the process name is Ombi, but this could be different for your system. We need to know the process name so we can kill that process to update the files.</small> <small >By default the process name is Ombi, but this could be different for your system. We need to know the process name so we can kill that process to update the files.</small>
<div class="form-group"> <div class="form-group">
<label for="processName">Ombi Process Name</label> <label for="processName">Ombi Process Name</label>
@ -51,8 +67,8 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col-md-6" [hidden]="useScript"> <div class="col-md-6" [hidden]="useScript" *ngIf="isWindows">
<small>If you are getting any permissions issues, you can specify a user for the update process to run under (Only supported on Windows).</small> <small>If you are getting any permissions issues, you can specify a user for the update process to run under.</small>
<div class="form-group"> <div class="form-group">
<label for="username" class="control-label">Username</label> <label for="username" class="control-label">Username</label>

@ -12,9 +12,9 @@ export class UpdateComponent implements OnInit {
public form: FormGroup; public form: FormGroup;
public updateAvailable = false; public updateAvailable = false;
public enableUpdateButton = false; public enableUpdateButton = false;
public isWindows = false;
public get useScript() { public get useScript() {
const control = this.form.get("useScript"); const control = this.form.get("useScript");
console.log(control);
return control!.value!; return control!.value!;
} }
@ -33,7 +33,10 @@ export class UpdateComponent implements OnInit {
processName: [x.processName], processName: [x.processName],
useScript: [x.useScript], useScript: [x.useScript],
scriptLocation: [x.scriptLocation], scriptLocation: [x.scriptLocation],
windowsService: [x.windowsService],
windowsServiceName: [x.windowsServiceName],
}); });
this.isWindows = x.isWindows;
this.enableUpdateButton = x.autoUpdateEnabled; this.enableUpdateButton = x.autoUpdateEnabled;
}); });
} }

@ -379,7 +379,9 @@ namespace Ombi.Controllers
[HttpGet("Update")] [HttpGet("Update")]
public async Task<UpdateSettings> UpdateSettings() public async Task<UpdateSettings> UpdateSettings()
{ {
return await Get<UpdateSettings>(); var settings = await Get<UpdateSettings>();
return Mapper.Map<UpdateSettingsViewModel>(settings);
} }
/// <summary> /// <summary>

Loading…
Cancel
Save