mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-05-24 09:37:54 +01:00
isolated clickonce dependancies
This commit is contained in:
@@ -1,146 +0,0 @@
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Common.Kernel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Logging;
|
||||
|
||||
namespace MediaBrowser.Common.Api.Logging
|
||||
{
|
||||
/// <summary>
|
||||
/// Class ScheduledTasksWebSocketListener
|
||||
/// </summary>
|
||||
[Export(typeof(IWebSocketListener))]
|
||||
public class LogFileWebSocketListener : BasePeriodicWebSocketListener<IKernel, IEnumerable<string>, LogFileWebSocketState>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the name.
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
protected override string Name
|
||||
{
|
||||
get { return "LogFile"; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LogFileWebSocketListener" /> class.
|
||||
/// </summary>
|
||||
/// <param name="logger">The logger.</param>
|
||||
[ImportingConstructor]
|
||||
public LogFileWebSocketListener([Import("logger")] ILogger logger)
|
||||
: base(logger)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the specified kernel.
|
||||
/// </summary>
|
||||
/// <param name="kernel">The kernel.</param>
|
||||
public override void Initialize(IKernel kernel)
|
||||
{
|
||||
base.Initialize(kernel);
|
||||
|
||||
kernel.LoggerLoaded += kernel_LoggerLoaded;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the data to send.
|
||||
/// </summary>
|
||||
/// <param name="state">The state.</param>
|
||||
/// <returns>IEnumerable{System.String}.</returns>
|
||||
protected override async Task<IEnumerable<string>> GetDataToSend(LogFileWebSocketState state)
|
||||
{
|
||||
if (!string.Equals(Kernel.LogFilePath, state.LastLogFilePath))
|
||||
{
|
||||
state.LastLogFilePath = Kernel.LogFilePath;
|
||||
state.StartLine = 0;
|
||||
}
|
||||
|
||||
var lines = await GetLogLines(state.LastLogFilePath, state.StartLine).ConfigureAwait(false);
|
||||
|
||||
state.StartLine += lines.Count;
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases unmanaged and - optionally - managed resources.
|
||||
/// </summary>
|
||||
/// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
|
||||
protected override void Dispose(bool dispose)
|
||||
{
|
||||
if (dispose)
|
||||
{
|
||||
Kernel.LoggerLoaded -= kernel_LoggerLoaded;
|
||||
}
|
||||
base.Dispose(dispose);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the LoggerLoaded event of the kernel control.
|
||||
/// </summary>
|
||||
/// <param name="sender">The source of the event.</param>
|
||||
/// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
|
||||
void kernel_LoggerLoaded(object sender, EventArgs e)
|
||||
{
|
||||
// Reset the startline for each connection whenever the logger reloads
|
||||
lock (ActiveConnections)
|
||||
{
|
||||
foreach (var connection in ActiveConnections)
|
||||
{
|
||||
connection.Item4.StartLine = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the log lines.
|
||||
/// </summary>
|
||||
/// <param name="logFilePath">The log file path.</param>
|
||||
/// <param name="startLine">The start line.</param>
|
||||
/// <returns>Task{IEnumerable{System.String}}.</returns>
|
||||
internal static async Task<List<string>> GetLogLines(string logFilePath, int startLine)
|
||||
{
|
||||
var lines = new List<string>();
|
||||
|
||||
using (var fs = new FileStream(logFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, StreamDefaults.DefaultFileStreamBufferSize, true))
|
||||
{
|
||||
using (var reader = new StreamReader(fs))
|
||||
{
|
||||
while (!reader.EndOfStream)
|
||||
{
|
||||
lines.Add(await reader.ReadLineAsync().ConfigureAwait(false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (startLine > 0)
|
||||
{
|
||||
lines = lines.Skip(startLine).ToList();
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class LogFileWebSocketState
|
||||
/// </summary>
|
||||
public class LogFileWebSocketState
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the last log file path.
|
||||
/// </summary>
|
||||
/// <value>The last log file path.</value>
|
||||
public string LastLogFilePath { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the start line.
|
||||
/// </summary>
|
||||
/// <value>The start line.</value>
|
||||
public int StartLine { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,176 +0,0 @@
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Common.ScheduledTasks;
|
||||
using MediaBrowser.Common.Serialization;
|
||||
using MediaBrowser.Model.Tasks;
|
||||
using ServiceStack.ServiceHost;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using ServiceStack.Text.Controller;
|
||||
|
||||
namespace MediaBrowser.Common.Api.ScheduledTasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Class GetScheduledTask
|
||||
/// </summary>
|
||||
[Route("/ScheduledTasks/{Id}", "GET")]
|
||||
public class GetScheduledTask : IReturn<TaskInfo>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the id.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
public Guid Id { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class GetScheduledTasks
|
||||
/// </summary>
|
||||
[Route("/ScheduledTasks", "GET")]
|
||||
public class GetScheduledTasks : IReturn<List<TaskInfo>>
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class StartScheduledTask
|
||||
/// </summary>
|
||||
[Route("/ScheduledTasks/Running/{Id}", "POST")]
|
||||
public class StartScheduledTask : IReturnVoid
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the id.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
public Guid Id { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class StopScheduledTask
|
||||
/// </summary>
|
||||
[Route("/ScheduledTasks/Running/{Id}", "DELETE")]
|
||||
public class StopScheduledTask : IReturnVoid
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the id.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
public Guid Id { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class UpdateScheduledTaskTriggers
|
||||
/// </summary>
|
||||
[Route("/ScheduledTasks/{Id}/Triggers", "POST")]
|
||||
public class UpdateScheduledTaskTriggers : IRequiresRequestStream
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the task id.
|
||||
/// </summary>
|
||||
/// <value>The task id.</value>
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The raw Http Request Input Stream
|
||||
/// </summary>
|
||||
/// <value>The request stream.</value>
|
||||
public Stream RequestStream { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class ScheduledTasksService
|
||||
/// </summary>
|
||||
[Export(typeof(IRestfulService))]
|
||||
public class ScheduledTaskService : BaseRestService
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <returns>IEnumerable{TaskInfo}.</returns>
|
||||
public object Get(GetScheduledTasks request)
|
||||
{
|
||||
var result = Kernel.ScheduledTasks.OrderBy(i => i.Name)
|
||||
.Select(ScheduledTaskHelpers.GetTaskInfo).ToList();
|
||||
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <returns>IEnumerable{TaskInfo}.</returns>
|
||||
public object Get(GetScheduledTask request)
|
||||
{
|
||||
var task = Kernel.ScheduledTasks.FirstOrDefault(i => i.Id == request.Id);
|
||||
|
||||
if (task == null)
|
||||
{
|
||||
throw new ResourceNotFoundException("Task not found");
|
||||
}
|
||||
|
||||
var result = ScheduledTaskHelpers.GetTaskInfo(task);
|
||||
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Posts the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
public void Post(StartScheduledTask request)
|
||||
{
|
||||
var task = Kernel.ScheduledTasks.FirstOrDefault(i => i.Id == request.Id);
|
||||
|
||||
if (task == null)
|
||||
{
|
||||
throw new ResourceNotFoundException("Task not found");
|
||||
}
|
||||
|
||||
task.Execute();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Posts the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
public void Delete(StopScheduledTask request)
|
||||
{
|
||||
var task = Kernel.ScheduledTasks.FirstOrDefault(i => i.Id == request.Id);
|
||||
|
||||
if (task == null)
|
||||
{
|
||||
throw new ResourceNotFoundException("Task not found");
|
||||
}
|
||||
|
||||
task.Cancel();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Posts the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
public void Post(UpdateScheduledTaskTriggers request)
|
||||
{
|
||||
// We need to parse this manually because we told service stack not to with IRequiresRequestStream
|
||||
// https://code.google.com/p/servicestack/source/browse/trunk/Common/ServiceStack.Text/ServiceStack.Text/Controller/PathInfo.cs
|
||||
var pathInfo = PathInfo.Parse(Request.PathInfo);
|
||||
var id = new Guid(pathInfo.GetArgumentValue<string>(1));
|
||||
|
||||
var task = Kernel.ScheduledTasks.FirstOrDefault(i => i.Id == id);
|
||||
|
||||
if (task == null)
|
||||
{
|
||||
throw new ResourceNotFoundException("Task not found");
|
||||
}
|
||||
|
||||
var triggerInfos = JsonSerializer.DeserializeFromStream<TaskTriggerInfo[]>(request.RequestStream);
|
||||
|
||||
task.Triggers = triggerInfos.Select(t => ScheduledTaskHelpers.GetTrigger(t, Kernel));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
using MediaBrowser.Common.Kernel;
|
||||
using MediaBrowser.Common.ScheduledTasks;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Tasks;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Common.Api.ScheduledTasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Class ScheduledTasksWebSocketListener
|
||||
/// </summary>
|
||||
[Export(typeof(IWebSocketListener))]
|
||||
public class ScheduledTasksWebSocketListener : BasePeriodicWebSocketListener<IKernel, IEnumerable<TaskInfo>, object>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the name.
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
protected override string Name
|
||||
{
|
||||
get { return "ScheduledTasksInfo"; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ScheduledTasksWebSocketListener" /> class.
|
||||
/// </summary>
|
||||
/// <param name="logger">The logger.</param>
|
||||
[ImportingConstructor]
|
||||
public ScheduledTasksWebSocketListener([Import("logger")] ILogger logger)
|
||||
: base(logger)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the data to send.
|
||||
/// </summary>
|
||||
/// <param name="state">The state.</param>
|
||||
/// <returns>Task{IEnumerable{TaskInfo}}.</returns>
|
||||
protected override Task<IEnumerable<TaskInfo>> GetDataToSend(object state)
|
||||
{
|
||||
return Task.FromResult(Kernel.ScheduledTasks.OrderBy(i => i.Name)
|
||||
.Select(ScheduledTaskHelpers.GetTaskInfo));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
using MediaBrowser.Common.Kernel;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Common.Api
|
||||
{
|
||||
/// <summary>
|
||||
/// Class SystemInfoWebSocketListener
|
||||
/// </summary>
|
||||
[Export(typeof(IWebSocketListener))]
|
||||
public class SystemInfoWebSocketListener : BasePeriodicWebSocketListener<IKernel, Model.System.SystemInfo, object>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the name.
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
protected override string Name
|
||||
{
|
||||
get { return "SystemInfo"; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SystemInfoWebSocketListener" /> class.
|
||||
/// </summary>
|
||||
/// <param name="logger">The logger.</param>
|
||||
[ImportingConstructor]
|
||||
public SystemInfoWebSocketListener([Import("logger")] ILogger logger)
|
||||
: base(logger)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the data to send.
|
||||
/// </summary>
|
||||
/// <param name="state">The state.</param>
|
||||
/// <returns>Task{SystemInfo}.</returns>
|
||||
protected override Task<Model.System.SystemInfo> GetDataToSend(object state)
|
||||
{
|
||||
return Task.FromResult(Kernel.GetSystemInfo());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,6 @@ using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace MediaBrowser.Common.Extensions
|
||||
{
|
||||
@@ -46,24 +45,6 @@ namespace MediaBrowser.Common.Extensions
|
||||
return val.Split(new[] { separator }, options);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes an action after a specified delay
|
||||
/// </summary>
|
||||
/// <param name="dispatcher">The dispatcher.</param>
|
||||
/// <param name="action">The action.</param>
|
||||
/// <param name="delayMs">The delay ms.</param>
|
||||
public static void InvokeWithDelay(this Dispatcher dispatcher, Action action, long delayMs)
|
||||
{
|
||||
var timer = new DispatcherTimer(DispatcherPriority.Normal, dispatcher);
|
||||
timer.Interval = TimeSpan.FromMilliseconds(delayMs);
|
||||
timer.Tick += (sender, args) =>
|
||||
{
|
||||
timer.Stop();
|
||||
action();
|
||||
};
|
||||
timer.Start();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides a non-blocking method to start a process and wait asynchronously for it to exit
|
||||
/// </summary>
|
||||
|
||||
@@ -13,7 +13,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.ComponentModel.Composition.Hosting;
|
||||
using System.Deployment.Application;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -155,12 +154,6 @@ namespace MediaBrowser.Common.Kernel
|
||||
/// <value><c>true</c> if this instance is first run; otherwise, <c>false</c>.</value>
|
||||
public bool IsFirstRun { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The version of the application to display
|
||||
/// </summary>
|
||||
/// <value>The display version.</value>
|
||||
public string DisplayVersion { get { return ApplicationVersion.ToString(); } }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance has changes that require the entire application to restart.
|
||||
/// </summary>
|
||||
@@ -325,7 +318,10 @@ namespace MediaBrowser.Common.Kernel
|
||||
/// Gets the log file path.
|
||||
/// </summary>
|
||||
/// <value>The log file path.</value>
|
||||
public string LogFilePath { get; private set; }
|
||||
public string LogFilePath
|
||||
{
|
||||
get { return ApplicationHost.LogFilePath; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the logger.
|
||||
@@ -429,7 +425,7 @@ namespace MediaBrowser.Common.Kernel
|
||||
await ReloadComposableParts().ConfigureAwait(false);
|
||||
|
||||
DisposeTcpManager();
|
||||
TcpManager = new TcpManager(this, Logger);
|
||||
TcpManager = new TcpManager(ApplicationHost, this, Logger);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -482,6 +478,7 @@ namespace MediaBrowser.Common.Kernel
|
||||
protected virtual void ComposeExportedValues(CompositionContainer container)
|
||||
{
|
||||
container.ComposeExportedValue("logger", Logger);
|
||||
container.ComposeExportedValue("appHost", ApplicationHost);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -729,8 +726,8 @@ namespace MediaBrowser.Common.Kernel
|
||||
return new SystemInfo
|
||||
{
|
||||
HasPendingRestart = HasPendingRestart,
|
||||
Version = DisplayVersion,
|
||||
IsNetworkDeployed = ApplicationDeployment.IsNetworkDeployed,
|
||||
Version = ApplicationVersion.ToString(),
|
||||
IsNetworkDeployed = ApplicationHost.CanSelfUpdate,
|
||||
WebSocketPortNumber = TcpManager.WebSocketPortNumber,
|
||||
SupportsNativeWebSocket = TcpManager.SupportsNativeWebSocket,
|
||||
FailedPluginAssemblies = FailedPluginAssemblies.ToArray()
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
|
||||
using MediaBrowser.Model.Updates;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Common.Kernel
|
||||
{
|
||||
/// <summary>
|
||||
@@ -15,5 +19,29 @@ namespace MediaBrowser.Common.Kernel
|
||||
/// Reloads the logger.
|
||||
/// </summary>
|
||||
void ReloadLogger();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the log file path.
|
||||
/// </summary>
|
||||
/// <value>The log file path.</value>
|
||||
string LogFilePath { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance can self update.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance can self update; otherwise, <c>false</c>.</value>
|
||||
bool CanSelfUpdate { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Checks for update.
|
||||
/// </summary>
|
||||
/// <returns>Task{CheckForUpdateResult}.</returns>
|
||||
Task<CheckForUpdateResult> CheckForApplicationUpdate(CancellationToken cancellationToken, IProgress<double> progress);
|
||||
|
||||
/// <summary>
|
||||
/// Updates the application.
|
||||
/// </summary>
|
||||
/// <returns>Task.</returns>
|
||||
Task UpdateApplication(CancellationToken cancellationToken, IProgress<double> progress);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,6 +64,11 @@ namespace MediaBrowser.Common.Kernel
|
||||
/// The _logger
|
||||
/// </summary>
|
||||
private readonly ILogger _logger;
|
||||
|
||||
/// <summary>
|
||||
/// The _application host
|
||||
/// </summary>
|
||||
private readonly IApplicationHost _applicationHost;
|
||||
|
||||
/// <summary>
|
||||
/// The _supports native web socket
|
||||
@@ -108,12 +113,14 @@ namespace MediaBrowser.Common.Kernel
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TcpManager" /> class.
|
||||
/// </summary>
|
||||
/// <param name="applicationHost">The application host.</param>
|
||||
/// <param name="kernel">The kernel.</param>
|
||||
/// <param name="logger">The logger.</param>
|
||||
public TcpManager(IKernel kernel, ILogger logger)
|
||||
public TcpManager(IApplicationHost applicationHost, IKernel kernel, ILogger logger)
|
||||
: base(kernel)
|
||||
{
|
||||
_logger = logger;
|
||||
_applicationHost = applicationHost;
|
||||
|
||||
if (kernel.IsFirstRun)
|
||||
{
|
||||
@@ -182,7 +189,7 @@ namespace MediaBrowser.Common.Kernel
|
||||
|
||||
try
|
||||
{
|
||||
HttpServer = new HttpServer(Kernel.HttpServerUrlPrefix, "Media Browser", Kernel, _logger);
|
||||
HttpServer = new HttpServer(Kernel.HttpServerUrlPrefix, "Media Browser", _applicationHost, Kernel, _logger);
|
||||
}
|
||||
catch (HttpListenerException ex)
|
||||
{
|
||||
|
||||
@@ -34,7 +34,8 @@
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ApplicationIcon>Resources\Images\Icon.ico</ApplicationIcon>
|
||||
<ApplicationIcon>
|
||||
</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Alchemy">
|
||||
@@ -94,7 +95,6 @@
|
||||
<Reference Include="System.ComponentModel.Composition" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Deployment" />
|
||||
<Reference Include="System.Management" />
|
||||
<Reference Include="System.Net" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
@@ -118,13 +118,8 @@
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="WindowsBase" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Api\Logging\LogFileWebSocketListener.cs" />
|
||||
<Compile Include="Api\ScheduledTasks\ScheduledTaskService.cs" />
|
||||
<Compile Include="Api\ScheduledTasks\ScheduledTasksWebSocketListener.cs" />
|
||||
<Compile Include="Api\SystemInfoWebSocketListener.cs" />
|
||||
<Compile Include="Events\EventHelper.cs" />
|
||||
<Compile Include="Extensions\BaseExtensions.cs" />
|
||||
<Compile Include="Events\GenericEventArgs.cs" />
|
||||
@@ -156,8 +151,6 @@
|
||||
<Compile Include="Net\MimeTypes.cs" />
|
||||
<Compile Include="Net\NativeWebSocket.cs" />
|
||||
<Compile Include="Net\NetUtils.cs" />
|
||||
<Compile Include="Net\NetworkShares.cs" />
|
||||
<Compile Include="Net\StaticResult.cs" />
|
||||
<Compile Include="Net\UdpServer.cs" />
|
||||
<Compile Include="Net\WebSocketConnection.cs" />
|
||||
<Compile Include="Plugins\BaseUiPlugin.cs" />
|
||||
@@ -193,9 +186,6 @@
|
||||
<Compile Include="ScheduledTasks\IntervalTrigger.cs" />
|
||||
<Compile Include="ScheduledTasks\IScheduledTask.cs" />
|
||||
<Compile Include="ScheduledTasks\WeeklyTrigger.cs" />
|
||||
<Compile Include="Updates\ApplicationUpdateCheck.cs" />
|
||||
<Compile Include="Updates\ApplicationUpdater.cs" />
|
||||
<Compile Include="Updates\ClickOnceHelper.cs" />
|
||||
<Compile Include="Win32\NativeMethods.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -216,9 +206,6 @@
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Resources\Images\Icon.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="README.txt" />
|
||||
<Content Include="swagger-ui\css\screen.css" />
|
||||
|
||||
@@ -45,6 +45,12 @@ namespace MediaBrowser.Common.Net
|
||||
/// <value>The kernel.</value>
|
||||
private IKernel Kernel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the application host.
|
||||
/// </summary>
|
||||
/// <value>The application host.</value>
|
||||
private IApplicationHost ApplicationHost { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This subscribes to HttpListener requests and finds the appropriate BaseHandler to process it
|
||||
/// </summary>
|
||||
@@ -67,11 +73,12 @@ namespace MediaBrowser.Common.Net
|
||||
/// </summary>
|
||||
/// <param name="urlPrefix">The URL.</param>
|
||||
/// <param name="serverName">Name of the product.</param>
|
||||
/// <param name="applicationHost">The application host.</param>
|
||||
/// <param name="kernel">The kernel.</param>
|
||||
/// <param name="logger">The logger.</param>
|
||||
/// <param name="defaultRedirectpath">The default redirectpath.</param>
|
||||
/// <exception cref="System.ArgumentNullException">urlPrefix</exception>
|
||||
public HttpServer(string urlPrefix, string serverName, IKernel kernel, ILogger logger, string defaultRedirectpath = null)
|
||||
public HttpServer(string urlPrefix, string serverName, IApplicationHost applicationHost, IKernel kernel, ILogger logger, string defaultRedirectpath = null)
|
||||
: base()
|
||||
{
|
||||
if (string.IsNullOrEmpty(urlPrefix))
|
||||
@@ -86,9 +93,14 @@ namespace MediaBrowser.Common.Net
|
||||
{
|
||||
throw new ArgumentNullException("logger");
|
||||
}
|
||||
if (applicationHost == null)
|
||||
{
|
||||
throw new ArgumentNullException("applicationHost");
|
||||
}
|
||||
|
||||
DefaultRedirectPath = defaultRedirectpath;
|
||||
_logger = logger;
|
||||
ApplicationHost = applicationHost;
|
||||
|
||||
EndpointHostConfig.Instance.ServiceStackHandlerFactoryPath = null;
|
||||
EndpointHostConfig.Instance.MetadataRedirectPath = "metadata";
|
||||
@@ -144,6 +156,7 @@ namespace MediaBrowser.Common.Net
|
||||
|
||||
container.Register(Kernel);
|
||||
container.Register(_logger);
|
||||
container.Register(ApplicationHost);
|
||||
|
||||
foreach (var service in Kernel.RestServices)
|
||||
{
|
||||
|
||||
@@ -1,644 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace MediaBrowser.Common.Net
|
||||
{
|
||||
/// <summary>
|
||||
/// Type of share
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum ShareType
|
||||
{
|
||||
/// <summary>Disk share</summary>
|
||||
Disk = 0,
|
||||
/// <summary>Printer share</summary>
|
||||
Printer = 1,
|
||||
/// <summary>Device share</summary>
|
||||
Device = 2,
|
||||
/// <summary>IPC share</summary>
|
||||
IPC = 3,
|
||||
/// <summary>Special share</summary>
|
||||
Special = -2147483648, // 0x80000000,
|
||||
}
|
||||
|
||||
#region Share
|
||||
|
||||
/// <summary>
|
||||
/// Information about a local share
|
||||
/// </summary>
|
||||
public class Share
|
||||
{
|
||||
#region Private data
|
||||
|
||||
private string _server;
|
||||
private string _netName;
|
||||
private string _path;
|
||||
private ShareType _shareType;
|
||||
private string _remark;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="Server"></param>
|
||||
/// <param name="shi"></param>
|
||||
public Share(string server, string netName, string path, ShareType shareType, string remark)
|
||||
{
|
||||
if (ShareType.Special == shareType && "IPC$" == netName)
|
||||
{
|
||||
shareType |= ShareType.IPC;
|
||||
}
|
||||
|
||||
_server = server;
|
||||
_netName = netName;
|
||||
_path = path;
|
||||
_shareType = shareType;
|
||||
_remark = remark;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// The name of the computer that this share belongs to
|
||||
/// </summary>
|
||||
public string Server
|
||||
{
|
||||
get { return _server; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Share name
|
||||
/// </summary>
|
||||
public string NetName
|
||||
{
|
||||
get { return _netName; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Local path
|
||||
/// </summary>
|
||||
public string Path
|
||||
{
|
||||
get { return _path; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Share type
|
||||
/// </summary>
|
||||
public ShareType ShareType
|
||||
{
|
||||
get { return _shareType; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Comment
|
||||
/// </summary>
|
||||
public string Remark
|
||||
{
|
||||
get { return _remark; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this is a file system share
|
||||
/// </summary>
|
||||
public bool IsFileSystem
|
||||
{
|
||||
get
|
||||
{
|
||||
// Shared device
|
||||
if (0 != (_shareType & ShareType.Device)) return false;
|
||||
// IPC share
|
||||
if (0 != (_shareType & ShareType.IPC)) return false;
|
||||
// Shared printer
|
||||
if (0 != (_shareType & ShareType.Printer)) return false;
|
||||
|
||||
// Standard disk share
|
||||
if (0 == (_shareType & ShareType.Special)) return true;
|
||||
|
||||
// Special disk share (e.g. C$)
|
||||
if (ShareType.Special == _shareType && null != _netName && 0 != _netName.Length)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the root of a disk-based share
|
||||
/// </summary>
|
||||
public DirectoryInfo Root
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsFileSystem)
|
||||
{
|
||||
if (null == _server || 0 == _server.Length)
|
||||
if (null == _path || 0 == _path.Length)
|
||||
return new DirectoryInfo(ToString());
|
||||
else
|
||||
return new DirectoryInfo(_path);
|
||||
else
|
||||
return new DirectoryInfo(ToString());
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Returns the path to this share
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override string ToString()
|
||||
{
|
||||
if (null == _server || 0 == _server.Length)
|
||||
{
|
||||
return string.Format(@"\\{0}\{1}", Environment.MachineName, _netName);
|
||||
}
|
||||
else
|
||||
return string.Format(@"\\{0}\{1}", _server, _netName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this share matches the local path
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
public bool MatchesPath(string path)
|
||||
{
|
||||
if (!IsFileSystem) return false;
|
||||
if (null == path || 0 == path.Length) return true;
|
||||
|
||||
return path.ToLower().StartsWith(_path.ToLower());
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// A collection of shares
|
||||
/// </summary>
|
||||
public class ShareCollection : ReadOnlyCollectionBase
|
||||
{
|
||||
#region Platform
|
||||
|
||||
/// <summary>
|
||||
/// Is this an NT platform?
|
||||
/// </summary>
|
||||
protected static bool IsNT
|
||||
{
|
||||
get { return (PlatformID.Win32NT == Environment.OSVersion.Platform); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this is Windows 2000 or higher
|
||||
/// </summary>
|
||||
protected static bool IsW2KUp
|
||||
{
|
||||
get
|
||||
{
|
||||
OperatingSystem os = Environment.OSVersion;
|
||||
if (PlatformID.Win32NT == os.Platform && os.Version.Major >= 5)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Interop
|
||||
|
||||
#region Constants
|
||||
|
||||
/// <summary>Maximum path length</summary>
|
||||
protected const int MAX_PATH = 260;
|
||||
/// <summary>No error</summary>
|
||||
protected const int NO_ERROR = 0;
|
||||
/// <summary>Access denied</summary>
|
||||
protected const int ERROR_ACCESS_DENIED = 5;
|
||||
/// <summary>Access denied</summary>
|
||||
protected const int ERROR_WRONG_LEVEL = 124;
|
||||
/// <summary>More data available</summary>
|
||||
protected const int ERROR_MORE_DATA = 234;
|
||||
/// <summary>Not connected</summary>
|
||||
protected const int ERROR_NOT_CONNECTED = 2250;
|
||||
/// <summary>Level 1</summary>
|
||||
protected const int UNIVERSAL_NAME_INFO_LEVEL = 1;
|
||||
/// <summary>Max extries (9x)</summary>
|
||||
protected const int MAX_SI50_ENTRIES = 20;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Structures
|
||||
|
||||
/// <summary>Unc name</summary>
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
protected struct UNIVERSAL_NAME_INFO
|
||||
{
|
||||
[MarshalAs(UnmanagedType.LPTStr)]
|
||||
public string lpUniversalName;
|
||||
}
|
||||
|
||||
/// <summary>Share information, NT, level 2</summary>
|
||||
/// <remarks>
|
||||
/// Requires admin rights to work.
|
||||
/// </remarks>
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||
protected struct SHARE_INFO_2
|
||||
{
|
||||
[MarshalAs(UnmanagedType.LPWStr)]
|
||||
public string NetName;
|
||||
public ShareType ShareType;
|
||||
[MarshalAs(UnmanagedType.LPWStr)]
|
||||
public string Remark;
|
||||
public int Permissions;
|
||||
public int MaxUsers;
|
||||
public int CurrentUsers;
|
||||
[MarshalAs(UnmanagedType.LPWStr)]
|
||||
public string Path;
|
||||
[MarshalAs(UnmanagedType.LPWStr)]
|
||||
public string Password;
|
||||
}
|
||||
|
||||
/// <summary>Share information, NT, level 1</summary>
|
||||
/// <remarks>
|
||||
/// Fallback when no admin rights.
|
||||
/// </remarks>
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||
protected struct SHARE_INFO_1
|
||||
{
|
||||
[MarshalAs(UnmanagedType.LPWStr)]
|
||||
public string NetName;
|
||||
public ShareType ShareType;
|
||||
[MarshalAs(UnmanagedType.LPWStr)]
|
||||
public string Remark;
|
||||
}
|
||||
|
||||
/// <summary>Share information, Win9x</summary>
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
|
||||
protected struct SHARE_INFO_50
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 13)]
|
||||
public string NetName;
|
||||
|
||||
public byte bShareType;
|
||||
public ushort Flags;
|
||||
|
||||
[MarshalAs(UnmanagedType.LPTStr)]
|
||||
public string Remark;
|
||||
[MarshalAs(UnmanagedType.LPTStr)]
|
||||
public string Path;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)]
|
||||
public string PasswordRW;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)]
|
||||
public string PasswordRO;
|
||||
|
||||
public ShareType ShareType
|
||||
{
|
||||
get { return (ShareType)((int)bShareType & 0x7F); }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Share information level 1, Win9x</summary>
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
|
||||
protected struct SHARE_INFO_1_9x
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 13)]
|
||||
public string NetName;
|
||||
public byte Padding;
|
||||
|
||||
public ushort bShareType;
|
||||
|
||||
[MarshalAs(UnmanagedType.LPTStr)]
|
||||
public string Remark;
|
||||
|
||||
public ShareType ShareType
|
||||
{
|
||||
get { return (ShareType)((int)bShareType & 0x7FFF); }
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Functions
|
||||
|
||||
/// <summary>Get a UNC name</summary>
|
||||
[DllImport("mpr", CharSet = CharSet.Auto)]
|
||||
protected static extern int WNetGetUniversalName(string lpLocalPath,
|
||||
int dwInfoLevel, ref UNIVERSAL_NAME_INFO lpBuffer, ref int lpBufferSize);
|
||||
|
||||
/// <summary>Get a UNC name</summary>
|
||||
[DllImport("mpr", CharSet = CharSet.Auto)]
|
||||
protected static extern int WNetGetUniversalName(string lpLocalPath,
|
||||
int dwInfoLevel, IntPtr lpBuffer, ref int lpBufferSize);
|
||||
|
||||
/// <summary>Enumerate shares (NT)</summary>
|
||||
[DllImport("netapi32", CharSet = CharSet.Unicode)]
|
||||
protected static extern int NetShareEnum(string lpServerName, int dwLevel,
|
||||
out IntPtr lpBuffer, int dwPrefMaxLen, out int entriesRead,
|
||||
out int totalEntries, ref int hResume);
|
||||
|
||||
/// <summary>Enumerate shares (9x)</summary>
|
||||
[DllImport("svrapi", CharSet = CharSet.Ansi)]
|
||||
protected static extern int NetShareEnum(
|
||||
[MarshalAs(UnmanagedType.LPTStr)] string lpServerName, int dwLevel,
|
||||
IntPtr lpBuffer, ushort cbBuffer, out ushort entriesRead,
|
||||
out ushort totalEntries);
|
||||
|
||||
/// <summary>Free the buffer (NT)</summary>
|
||||
[DllImport("netapi32")]
|
||||
protected static extern int NetApiBufferFree(IntPtr lpBuffer);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Enumerate shares
|
||||
|
||||
/// <summary>
|
||||
/// Enumerates the shares on Windows NT
|
||||
/// </summary>
|
||||
/// <param name="server">The server name</param>
|
||||
/// <param name="shares">The ShareCollection</param>
|
||||
protected static void EnumerateSharesNT(string server, ShareCollection shares)
|
||||
{
|
||||
int level = 2;
|
||||
int entriesRead, totalEntries, nRet, hResume = 0;
|
||||
IntPtr pBuffer = IntPtr.Zero;
|
||||
|
||||
try
|
||||
{
|
||||
nRet = NetShareEnum(server, level, out pBuffer, -1,
|
||||
out entriesRead, out totalEntries, ref hResume);
|
||||
|
||||
if (ERROR_ACCESS_DENIED == nRet)
|
||||
{
|
||||
//Need admin for level 2, drop to level 1
|
||||
level = 1;
|
||||
nRet = NetShareEnum(server, level, out pBuffer, -1,
|
||||
out entriesRead, out totalEntries, ref hResume);
|
||||
}
|
||||
|
||||
if (NO_ERROR == nRet && entriesRead > 0)
|
||||
{
|
||||
Type t = (2 == level) ? typeof(SHARE_INFO_2) : typeof(SHARE_INFO_1);
|
||||
int offset = Marshal.SizeOf(t);
|
||||
|
||||
for (int i = 0, lpItem = pBuffer.ToInt32(); i < entriesRead; i++, lpItem += offset)
|
||||
{
|
||||
IntPtr pItem = new IntPtr(lpItem);
|
||||
if (1 == level)
|
||||
{
|
||||
SHARE_INFO_1 si = (SHARE_INFO_1)Marshal.PtrToStructure(pItem, t);
|
||||
shares.Add(si.NetName, string.Empty, si.ShareType, si.Remark);
|
||||
}
|
||||
else
|
||||
{
|
||||
SHARE_INFO_2 si = (SHARE_INFO_2)Marshal.PtrToStructure(pItem, t);
|
||||
shares.Add(si.NetName, si.Path, si.ShareType, si.Remark);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Clean up buffer allocated by system
|
||||
if (IntPtr.Zero != pBuffer)
|
||||
NetApiBufferFree(pBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enumerates the shares on Windows 9x
|
||||
/// </summary>
|
||||
/// <param name="server">The server name</param>
|
||||
/// <param name="shares">The ShareCollection</param>
|
||||
protected static void EnumerateShares9x(string server, ShareCollection shares)
|
||||
{
|
||||
int level = 50;
|
||||
int nRet = 0;
|
||||
ushort entriesRead, totalEntries;
|
||||
|
||||
Type t = typeof(SHARE_INFO_50);
|
||||
int size = Marshal.SizeOf(t);
|
||||
ushort cbBuffer = (ushort)(MAX_SI50_ENTRIES * size);
|
||||
//On Win9x, must allocate buffer before calling API
|
||||
IntPtr pBuffer = Marshal.AllocHGlobal(cbBuffer);
|
||||
|
||||
try
|
||||
{
|
||||
nRet = NetShareEnum(server, level, pBuffer, cbBuffer,
|
||||
out entriesRead, out totalEntries);
|
||||
|
||||
if (ERROR_WRONG_LEVEL == nRet)
|
||||
{
|
||||
level = 1;
|
||||
t = typeof(SHARE_INFO_1_9x);
|
||||
size = Marshal.SizeOf(t);
|
||||
|
||||
nRet = NetShareEnum(server, level, pBuffer, cbBuffer,
|
||||
out entriesRead, out totalEntries);
|
||||
}
|
||||
|
||||
if (NO_ERROR == nRet || ERROR_MORE_DATA == nRet)
|
||||
{
|
||||
for (int i = 0, lpItem = pBuffer.ToInt32(); i < entriesRead; i++, lpItem += size)
|
||||
{
|
||||
IntPtr pItem = new IntPtr(lpItem);
|
||||
|
||||
if (1 == level)
|
||||
{
|
||||
SHARE_INFO_1_9x si = (SHARE_INFO_1_9x)Marshal.PtrToStructure(pItem, t);
|
||||
shares.Add(si.NetName, string.Empty, si.ShareType, si.Remark);
|
||||
}
|
||||
else
|
||||
{
|
||||
SHARE_INFO_50 si = (SHARE_INFO_50)Marshal.PtrToStructure(pItem, t);
|
||||
shares.Add(si.NetName, si.Path, si.ShareType, si.Remark);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
Console.WriteLine(nRet);
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
//Clean up buffer
|
||||
Marshal.FreeHGlobal(pBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enumerates the shares
|
||||
/// </summary>
|
||||
/// <param name="server">The server name</param>
|
||||
/// <param name="shares">The ShareCollection</param>
|
||||
protected static void EnumerateShares(string server, ShareCollection shares)
|
||||
{
|
||||
if (null != server && 0 != server.Length && !IsW2KUp)
|
||||
{
|
||||
server = server.ToUpper();
|
||||
|
||||
// On NT4, 9x and Me, server has to start with "\\"
|
||||
if (!('\\' == server[0] && '\\' == server[1]))
|
||||
server = @"\\" + server;
|
||||
}
|
||||
|
||||
if (IsNT)
|
||||
EnumerateSharesNT(server, shares);
|
||||
else
|
||||
EnumerateShares9x(server, shares);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region Static methods
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if fileName is a valid local file-name of the form:
|
||||
/// X:\, where X is a drive letter from A-Z
|
||||
/// </summary>
|
||||
/// <param name="fileName">The filename to check</param>
|
||||
/// <returns></returns>
|
||||
public static bool IsValidFilePath(string fileName)
|
||||
{
|
||||
if (null == fileName || 0 == fileName.Length) return false;
|
||||
|
||||
char drive = char.ToUpper(fileName[0]);
|
||||
if ('A' > drive || drive > 'Z')
|
||||
return false;
|
||||
|
||||
else if (Path.VolumeSeparatorChar != fileName[1])
|
||||
return false;
|
||||
else if (Path.DirectorySeparatorChar != fileName[2])
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>The name of the server this collection represents</summary>
|
||||
private string _server;
|
||||
|
||||
#region Constructor
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor - local machine
|
||||
/// </summary>
|
||||
public ShareCollection()
|
||||
{
|
||||
_server = string.Empty;
|
||||
EnumerateShares(_server, this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="Server"></param>
|
||||
public ShareCollection(string server)
|
||||
{
|
||||
_server = server;
|
||||
EnumerateShares(_server, this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Add
|
||||
|
||||
protected void Add(Share share)
|
||||
{
|
||||
InnerList.Add(share);
|
||||
}
|
||||
|
||||
protected void Add(string netName, string path, ShareType shareType, string remark)
|
||||
{
|
||||
InnerList.Add(new Share(_server, netName, path, shareType, remark));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Returns the name of the server this collection represents
|
||||
/// </summary>
|
||||
public string Server
|
||||
{
|
||||
get { return _server; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the <see cref="Share"/> at the specified index.
|
||||
/// </summary>
|
||||
public Share this[int index]
|
||||
{
|
||||
get { return (Share)InnerList[index]; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the <see cref="Share"/> which matches a given local path
|
||||
/// </summary>
|
||||
/// <param name="path">The path to match</param>
|
||||
public Share this[string path]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (null == path || 0 == path.Length) return null;
|
||||
|
||||
path = Path.GetFullPath(path);
|
||||
if (!IsValidFilePath(path)) return null;
|
||||
|
||||
Share match = null;
|
||||
|
||||
for (int i = 0; i < InnerList.Count; i++)
|
||||
{
|
||||
Share s = (Share)InnerList[i];
|
||||
|
||||
if (s.IsFileSystem && s.MatchesPath(path))
|
||||
{
|
||||
//Store first match
|
||||
if (null == match)
|
||||
match = s;
|
||||
|
||||
// If this has a longer path,
|
||||
// and this is a disk share or match is a special share,
|
||||
// then this is a better match
|
||||
else if (match.Path.Length < s.Path.Length)
|
||||
{
|
||||
if (ShareType.Disk == s.ShareType || ShareType.Disk != match.ShareType)
|
||||
match = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Copy this collection to an array
|
||||
/// </summary>
|
||||
/// <param name="array"></param>
|
||||
/// <param name="index"></param>
|
||||
public void CopyTo(Share[] array, int index)
|
||||
{
|
||||
InnerList.CopyTo(array, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Common.Net
|
||||
{
|
||||
public class StaticResult
|
||||
{
|
||||
public Stream Stream { get; set; }
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 146 KiB |
@@ -171,7 +171,7 @@ namespace MediaBrowser.Common.ScheduledTasks
|
||||
/// Gets the current progress.
|
||||
/// </summary>
|
||||
/// <value>The current progress.</value>
|
||||
public TaskProgress CurrentProgress { get; private set; }
|
||||
public double? CurrentProgress { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The _triggers
|
||||
@@ -246,7 +246,7 @@ namespace MediaBrowser.Common.ScheduledTasks
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <param name="progress">The progress.</param>
|
||||
/// <returns>Task.</returns>
|
||||
protected abstract Task ExecuteInternal(CancellationToken cancellationToken, IProgress<TaskProgress> progress);
|
||||
protected abstract Task ExecuteInternal(CancellationToken cancellationToken, IProgress<double> progress);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the task
|
||||
@@ -355,7 +355,7 @@ namespace MediaBrowser.Common.ScheduledTasks
|
||||
|
||||
Logger.Info("Executing {0}", Name);
|
||||
|
||||
var progress = new Progress<TaskProgress>();
|
||||
var progress = new Progress<double>();
|
||||
|
||||
progress.ProgressChanged += progress_ProgressChanged;
|
||||
|
||||
@@ -426,7 +426,7 @@ namespace MediaBrowser.Common.ScheduledTasks
|
||||
/// </summary>
|
||||
/// <param name="sender">The sender.</param>
|
||||
/// <param name="e">The e.</param>
|
||||
void progress_ProgressChanged(object sender, TaskProgress e)
|
||||
void progress_ProgressChanged(object sender, double e)
|
||||
{
|
||||
CurrentProgress = e;
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace MediaBrowser.Common.ScheduledTasks
|
||||
/// Gets the current progress.
|
||||
/// </summary>
|
||||
/// <value>The current progress.</value>
|
||||
TaskProgress CurrentProgress { get; }
|
||||
double? CurrentProgress { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the task
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace MediaBrowser.Common.ScheduledTasks
|
||||
return new TaskInfo
|
||||
{
|
||||
Name = task.Name,
|
||||
CurrentProgress = task.CurrentProgress,
|
||||
CurrentProgressPercentage = task.CurrentProgress,
|
||||
State = task.State,
|
||||
Id = task.Id,
|
||||
LastExecutionResult = task.LastExecutionResult,
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace MediaBrowser.Common.ScheduledTasks.Tasks
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <param name="progress">The progress.</param>
|
||||
/// <returns>Task.</returns>
|
||||
protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress<TaskProgress> progress)
|
||||
protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress<double> progress)
|
||||
{
|
||||
return Task.Run(() =>
|
||||
{
|
||||
@@ -51,7 +51,7 @@ namespace MediaBrowser.Common.ScheduledTasks.Tasks
|
||||
/// <param name="directory">The directory.</param>
|
||||
/// <param name="minDateModified">The min date modified.</param>
|
||||
/// <param name="progress">The progress.</param>
|
||||
private void DeleteCacheFilesFromDirectory(CancellationToken cancellationToken, string directory, DateTime minDateModified, IProgress<TaskProgress> progress)
|
||||
private void DeleteCacheFilesFromDirectory(CancellationToken cancellationToken, string directory, DateTime minDateModified, IProgress<double> progress)
|
||||
{
|
||||
var filesToDelete = new DirectoryInfo(directory).EnumerateFileSystemInfos("*", SearchOption.AllDirectories)
|
||||
.Where(f => !f.Attributes.HasFlag(FileAttributes.Directory) && f.LastWriteTimeUtc < minDateModified)
|
||||
@@ -64,7 +64,7 @@ namespace MediaBrowser.Common.ScheduledTasks.Tasks
|
||||
double percent = index;
|
||||
percent /= filesToDelete.Count;
|
||||
|
||||
progress.Report(new TaskProgress { Description = file.FullName, PercentComplete = 100 * percent });
|
||||
progress.Report(100 * percent);
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
@@ -73,7 +73,7 @@ namespace MediaBrowser.Common.ScheduledTasks.Tasks
|
||||
index++;
|
||||
}
|
||||
|
||||
progress.Report(new TaskProgress { PercentComplete = 100 });
|
||||
progress.Report(100);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace MediaBrowser.Common.ScheduledTasks.Tasks
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <param name="progress">The progress.</param>
|
||||
/// <returns>Task.</returns>
|
||||
protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress<TaskProgress> progress)
|
||||
protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress<double> progress)
|
||||
{
|
||||
return Task.Run(() =>
|
||||
{
|
||||
@@ -51,7 +51,7 @@ namespace MediaBrowser.Common.ScheduledTasks.Tasks
|
||||
double percent = index;
|
||||
percent /= filesToDelete.Count;
|
||||
|
||||
progress.Report(new TaskProgress { Description = file.FullName, PercentComplete = 100 * percent });
|
||||
progress.Report(100 * percent);
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
@@ -60,7 +60,7 @@ namespace MediaBrowser.Common.ScheduledTasks.Tasks
|
||||
index++;
|
||||
}
|
||||
|
||||
progress.Report(new TaskProgress { PercentComplete = 100 });
|
||||
progress.Report(100);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -31,11 +31,11 @@ namespace MediaBrowser.Common.ScheduledTasks.Tasks
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <param name="progress">The progress.</param>
|
||||
/// <returns>Task.</returns>
|
||||
protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress<TaskProgress> progress)
|
||||
protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress<double> progress)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
progress.Report(new TaskProgress { PercentComplete = 0 });
|
||||
progress.Report(0);
|
||||
|
||||
return Task.Run(() => Kernel.ReloadLogger());
|
||||
}
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
using MediaBrowser.Common.Kernel;
|
||||
using MediaBrowser.Common.Updates;
|
||||
using MediaBrowser.Model.Tasks;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Deployment.Application;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -16,6 +13,21 @@ namespace MediaBrowser.Common.ScheduledTasks.Tasks
|
||||
[Export(typeof(IScheduledTask))]
|
||||
public class SystemUpdateTask : BaseScheduledTask<IKernel>
|
||||
{
|
||||
/// <summary>
|
||||
/// The _app host
|
||||
/// </summary>
|
||||
private readonly IApplicationHost _appHost;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SystemUpdateTask" /> class.
|
||||
/// </summary>
|
||||
/// <param name="appHost">The app host.</param>
|
||||
[ImportingConstructor]
|
||||
public SystemUpdateTask([Import("appHost")] IApplicationHost appHost)
|
||||
{
|
||||
_appHost = appHost;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the triggers that define when the task will run
|
||||
/// </summary>
|
||||
@@ -37,26 +49,26 @@ namespace MediaBrowser.Common.ScheduledTasks.Tasks
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <param name="progress">The progress.</param>
|
||||
/// <returns>Task.</returns>
|
||||
protected override async Task ExecuteInternal(CancellationToken cancellationToken, IProgress<TaskProgress> progress)
|
||||
protected override async Task ExecuteInternal(CancellationToken cancellationToken, IProgress<double> progress)
|
||||
{
|
||||
if (!ApplicationDeployment.IsNetworkDeployed) return;
|
||||
if (!_appHost.CanSelfUpdate) return;
|
||||
|
||||
EventHandler<TaskProgress> innerProgressHandler = (sender, e) => progress.Report(new TaskProgress { PercentComplete = e.PercentComplete * .1 });
|
||||
EventHandler<double> innerProgressHandler = (sender, e) => progress.Report(e * .1);
|
||||
|
||||
// Create a progress object for the update check
|
||||
var innerProgress = new Progress<TaskProgress>();
|
||||
var innerProgress = new Progress<double>();
|
||||
innerProgress.ProgressChanged += innerProgressHandler;
|
||||
|
||||
var updateInfo = await new ApplicationUpdateCheck().CheckForApplicationUpdate(cancellationToken, innerProgress).ConfigureAwait(false);
|
||||
var updateInfo = await _appHost.CheckForApplicationUpdate(cancellationToken, innerProgress).ConfigureAwait(false);
|
||||
|
||||
// Release the event handler
|
||||
innerProgress.ProgressChanged -= innerProgressHandler;
|
||||
|
||||
progress.Report(new TaskProgress { PercentComplete = 10 });
|
||||
progress.Report(10);
|
||||
|
||||
if (!updateInfo.UpdateAvailable)
|
||||
if (!updateInfo.IsUpdateAvailable)
|
||||
{
|
||||
progress.Report(new TaskProgress { PercentComplete = 100 });
|
||||
progress.Report(100);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -66,12 +78,12 @@ namespace MediaBrowser.Common.ScheduledTasks.Tasks
|
||||
{
|
||||
Logger.Info("Update Revision {0} available. Updating...", updateInfo.AvailableVersion);
|
||||
|
||||
innerProgressHandler = (sender, e) => progress.Report(new TaskProgress { PercentComplete = (e.PercentComplete * .9) + .1 });
|
||||
innerProgressHandler = (sender, e) => progress.Report((e * .9) + .1);
|
||||
|
||||
innerProgress = new Progress<TaskProgress>();
|
||||
innerProgress = new Progress<double>();
|
||||
innerProgress.ProgressChanged += innerProgressHandler;
|
||||
|
||||
await new ApplicationUpdater().UpdateApplication(cancellationToken, innerProgress).ConfigureAwait(false);
|
||||
await _appHost.UpdateApplication(cancellationToken, innerProgress).ConfigureAwait(false);
|
||||
|
||||
// Release the event handler
|
||||
innerProgress.ProgressChanged -= innerProgressHandler;
|
||||
@@ -83,7 +95,7 @@ namespace MediaBrowser.Common.ScheduledTasks.Tasks
|
||||
Logger.Info("A new version of Media Browser is available.");
|
||||
}
|
||||
|
||||
progress.Report(new TaskProgress { PercentComplete = 100 });
|
||||
progress.Report(100);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
using MediaBrowser.Model.Tasks;
|
||||
using System;
|
||||
using System.Deployment.Application;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Common.Updates
|
||||
{
|
||||
/// <summary>
|
||||
/// Class ApplicationUpdateCheck
|
||||
/// </summary>
|
||||
public class ApplicationUpdateCheck
|
||||
{
|
||||
/// <summary>
|
||||
/// The _task completion source
|
||||
/// </summary>
|
||||
private TaskCompletionSource<CheckForUpdateCompletedEventArgs> _taskCompletionSource;
|
||||
|
||||
/// <summary>
|
||||
/// The _progress
|
||||
/// </summary>
|
||||
private IProgress<TaskProgress> _progress;
|
||||
|
||||
/// <summary>
|
||||
/// Checks for application update.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <param name="progress">The progress.</param>
|
||||
/// <returns>Task{CheckForUpdateCompletedEventArgs}.</returns>
|
||||
/// <exception cref="System.InvalidOperationException">Current deployment is not a ClickOnce deployment</exception>
|
||||
public Task<CheckForUpdateCompletedEventArgs> CheckForApplicationUpdate(CancellationToken cancellationToken, IProgress<TaskProgress> progress)
|
||||
{
|
||||
if (!ApplicationDeployment.IsNetworkDeployed)
|
||||
{
|
||||
throw new InvalidOperationException("Current deployment is not network deployed.");
|
||||
}
|
||||
|
||||
_progress = progress;
|
||||
|
||||
_taskCompletionSource = new TaskCompletionSource<CheckForUpdateCompletedEventArgs>();
|
||||
|
||||
var deployment = ApplicationDeployment.CurrentDeployment;
|
||||
|
||||
cancellationToken.Register(deployment.CheckForUpdateAsyncCancel);
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
deployment.CheckForUpdateCompleted += deployment_CheckForUpdateCompleted;
|
||||
deployment.CheckForUpdateProgressChanged += deployment_CheckForUpdateProgressChanged;
|
||||
|
||||
deployment.CheckForUpdateAsync();
|
||||
|
||||
return _taskCompletionSource.Task;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the CheckForUpdateCompleted event of the deployment control.
|
||||
/// </summary>
|
||||
/// <param name="sender">The source of the event.</param>
|
||||
/// <param name="e">The <see cref="CheckForUpdateCompletedEventArgs" /> instance containing the event data.</param>
|
||||
void deployment_CheckForUpdateCompleted(object sender, CheckForUpdateCompletedEventArgs e)
|
||||
{
|
||||
var deployment = ApplicationDeployment.CurrentDeployment;
|
||||
|
||||
deployment.CheckForUpdateCompleted -= deployment_CheckForUpdateCompleted;
|
||||
deployment.CheckForUpdateProgressChanged -= deployment_CheckForUpdateProgressChanged;
|
||||
|
||||
if (e.Error != null)
|
||||
{
|
||||
_taskCompletionSource.SetException(e.Error);
|
||||
}
|
||||
else if (e.Cancelled)
|
||||
{
|
||||
_taskCompletionSource.SetCanceled();
|
||||
}
|
||||
else
|
||||
{
|
||||
_taskCompletionSource.SetResult(e);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the CheckForUpdateProgressChanged event of the deployment control.
|
||||
/// </summary>
|
||||
/// <param name="sender">The source of the event.</param>
|
||||
/// <param name="e">The <see cref="DeploymentProgressChangedEventArgs" /> instance containing the event data.</param>
|
||||
void deployment_CheckForUpdateProgressChanged(object sender, DeploymentProgressChangedEventArgs e)
|
||||
{
|
||||
_progress.Report(new TaskProgress { PercentComplete = e.ProgressPercentage });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
using MediaBrowser.Model.Tasks;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Deployment.Application;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Common.Updates
|
||||
{
|
||||
/// <summary>
|
||||
/// Class ApplicationUpdater
|
||||
/// </summary>
|
||||
public class ApplicationUpdater
|
||||
{
|
||||
/// <summary>
|
||||
/// The _task completion source
|
||||
/// </summary>
|
||||
private TaskCompletionSource<AsyncCompletedEventArgs> _taskCompletionSource;
|
||||
|
||||
/// <summary>
|
||||
/// The _progress
|
||||
/// </summary>
|
||||
private IProgress<TaskProgress> _progress;
|
||||
|
||||
/// <summary>
|
||||
/// Updates the application
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <param name="progress">The progress.</param>
|
||||
/// <returns>Task{AsyncCompletedEventArgs}.</returns>
|
||||
/// <exception cref="System.InvalidOperationException">Current deployment is not network deployed.</exception>
|
||||
public Task<AsyncCompletedEventArgs> UpdateApplication(CancellationToken cancellationToken, IProgress<TaskProgress> progress)
|
||||
{
|
||||
if (!ApplicationDeployment.IsNetworkDeployed)
|
||||
{
|
||||
throw new InvalidOperationException("Current deployment is not network deployed.");
|
||||
}
|
||||
|
||||
_progress = progress;
|
||||
|
||||
_taskCompletionSource = new TaskCompletionSource<AsyncCompletedEventArgs>();
|
||||
|
||||
var deployment = ApplicationDeployment.CurrentDeployment;
|
||||
|
||||
cancellationToken.Register(deployment.UpdateAsyncCancel);
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
deployment.UpdateCompleted += deployment_UpdateCompleted;
|
||||
deployment.UpdateProgressChanged += deployment_UpdateProgressChanged;
|
||||
|
||||
deployment.UpdateAsync();
|
||||
|
||||
return _taskCompletionSource.Task;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the UpdateCompleted event of the deployment control.
|
||||
/// </summary>
|
||||
/// <param name="sender">The source of the event.</param>
|
||||
/// <param name="e">The <see cref="AsyncCompletedEventArgs" /> instance containing the event data.</param>
|
||||
void deployment_UpdateCompleted(object sender, AsyncCompletedEventArgs e)
|
||||
{
|
||||
var deployment = ApplicationDeployment.CurrentDeployment;
|
||||
|
||||
deployment.UpdateCompleted -= deployment_UpdateCompleted;
|
||||
deployment.UpdateProgressChanged -= deployment_UpdateProgressChanged;
|
||||
|
||||
if (e.Error != null)
|
||||
{
|
||||
_taskCompletionSource.SetException(e.Error);
|
||||
}
|
||||
else if (e.Cancelled)
|
||||
{
|
||||
_taskCompletionSource.SetCanceled();
|
||||
}
|
||||
else
|
||||
{
|
||||
_taskCompletionSource.SetResult(e);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the UpdateProgressChanged event of the deployment control.
|
||||
/// </summary>
|
||||
/// <param name="sender">The source of the event.</param>
|
||||
/// <param name="e">The <see cref="DeploymentProgressChangedEventArgs" /> instance containing the event data.</param>
|
||||
void deployment_UpdateProgressChanged(object sender, DeploymentProgressChangedEventArgs e)
|
||||
{
|
||||
_progress.Report(new TaskProgress { PercentComplete = e.ProgressPercentage });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,217 +0,0 @@
|
||||
using Microsoft.Win32;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Security.AccessControl;
|
||||
|
||||
namespace MediaBrowser.Common.Updates
|
||||
{
|
||||
/// <summary>
|
||||
/// Class ClickOnceHelper
|
||||
/// </summary>
|
||||
public class ClickOnceHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// The uninstall string
|
||||
/// </summary>
|
||||
private const string UninstallString = "UninstallString";
|
||||
/// <summary>
|
||||
/// The display name key
|
||||
/// </summary>
|
||||
private const string DisplayNameKey = "DisplayName";
|
||||
/// <summary>
|
||||
/// The uninstall string file
|
||||
/// </summary>
|
||||
private const string UninstallStringFile = "UninstallString.bat";
|
||||
/// <summary>
|
||||
/// The appref extension
|
||||
/// </summary>
|
||||
private const string ApprefExtension = ".appref-ms";
|
||||
/// <summary>
|
||||
/// The uninstall registry key
|
||||
/// </summary>
|
||||
private readonly RegistryKey UninstallRegistryKey;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the location.
|
||||
/// </summary>
|
||||
/// <value>The location.</value>
|
||||
private static string Location
|
||||
{
|
||||
get { return Assembly.GetExecutingAssembly().Location; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the publisher.
|
||||
/// </summary>
|
||||
/// <value>The name of the publisher.</value>
|
||||
public string PublisherName { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets the name of the product.
|
||||
/// </summary>
|
||||
/// <value>The name of the product.</value>
|
||||
public string ProductName { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets the uninstall file.
|
||||
/// </summary>
|
||||
/// <value>The uninstall file.</value>
|
||||
public string UninstallFile { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets the name of the suite.
|
||||
/// </summary>
|
||||
/// <value>The name of the suite.</value>
|
||||
public string SuiteName { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ClickOnceHelper" /> class.
|
||||
/// </summary>
|
||||
/// <param name="publisherName">Name of the publisher.</param>
|
||||
/// <param name="productName">Name of the product.</param>
|
||||
/// <param name="suiteName">Name of the suite.</param>
|
||||
public ClickOnceHelper(string publisherName, string productName, string suiteName)
|
||||
{
|
||||
PublisherName = publisherName;
|
||||
ProductName = productName;
|
||||
SuiteName = suiteName;
|
||||
|
||||
var publisherFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), PublisherName);
|
||||
|
||||
if (!Directory.Exists(publisherFolder))
|
||||
{
|
||||
Directory.CreateDirectory(publisherFolder);
|
||||
}
|
||||
|
||||
UninstallFile = Path.Combine(publisherFolder, UninstallStringFile);
|
||||
|
||||
UninstallRegistryKey = GetUninstallRegistryKeyByProductName(ProductName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the shortcut path.
|
||||
/// </summary>
|
||||
/// <returns>System.String.</returns>
|
||||
private string GetShortcutPath()
|
||||
{
|
||||
var allProgramsPath = Environment.GetFolderPath(Environment.SpecialFolder.Programs);
|
||||
|
||||
var shortcutPath = Path.Combine(allProgramsPath, PublisherName);
|
||||
|
||||
if (!string.IsNullOrEmpty(SuiteName))
|
||||
{
|
||||
shortcutPath = Path.Combine(shortcutPath, SuiteName);
|
||||
}
|
||||
|
||||
return Path.Combine(shortcutPath, ProductName) + ApprefExtension;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the startup shortcut path.
|
||||
/// </summary>
|
||||
/// <returns>System.String.</returns>
|
||||
private string GetStartupShortcutPath()
|
||||
{
|
||||
var startupPath = Environment.GetFolderPath(Environment.SpecialFolder.Startup);
|
||||
|
||||
return Path.Combine(startupPath, ProductName) + ApprefExtension;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the shortcut to startup.
|
||||
/// </summary>
|
||||
public void AddShortcutToStartup()
|
||||
{
|
||||
var startupPath = GetStartupShortcutPath();
|
||||
|
||||
if (!File.Exists(startupPath))
|
||||
{
|
||||
File.Copy(GetShortcutPath(), startupPath);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the shortcut from startup.
|
||||
/// </summary>
|
||||
public void RemoveShortcutFromStartup()
|
||||
{
|
||||
var startupPath = GetStartupShortcutPath();
|
||||
|
||||
if (File.Exists(startupPath))
|
||||
{
|
||||
File.Delete(startupPath);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the uninstall parameters.
|
||||
/// </summary>
|
||||
/// <param name="uninstallerFileName">Name of the uninstaller file.</param>
|
||||
public void UpdateUninstallParameters(string uninstallerFileName)
|
||||
{
|
||||
if (UninstallRegistryKey != null)
|
||||
{
|
||||
UpdateUninstallString(uninstallerFileName);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the uninstall registry key by product.
|
||||
/// </summary>
|
||||
/// <param name="productName">Name of the product.</param>
|
||||
/// <returns>RegistryKey.</returns>
|
||||
private RegistryKey GetUninstallRegistryKeyByProductName(string productName)
|
||||
{
|
||||
var subKey = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Uninstall");
|
||||
|
||||
if (subKey == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return subKey.GetSubKeyNames()
|
||||
.Select(name => subKey.OpenSubKey(name, RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.QueryValues | RegistryRights.ReadKey | RegistryRights.SetValue))
|
||||
.Where(application => application != null)
|
||||
.FirstOrDefault(application => application.GetValueNames().Where(appKey => appKey.Equals(DisplayNameKey)).Any(appKey => application.GetValue(appKey).Equals(productName)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the uninstall string.
|
||||
/// </summary>
|
||||
/// <param name="uninstallerFileName">Name of the uninstaller file.</param>
|
||||
private void UpdateUninstallString(string uninstallerFileName)
|
||||
{
|
||||
var uninstallString = (string)UninstallRegistryKey.GetValue(UninstallString);
|
||||
|
||||
if (!string.IsNullOrEmpty(UninstallFile) && uninstallString.StartsWith("rundll32.exe", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
File.WriteAllText(UninstallFile, uninstallString);
|
||||
}
|
||||
|
||||
var str = String.Format("\"{0}\" uninstall", Path.Combine(Path.GetDirectoryName(Location), uninstallerFileName));
|
||||
|
||||
UninstallRegistryKey.SetValue(UninstallString, str);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Uninstalls this instance.
|
||||
/// </summary>
|
||||
public void Uninstall()
|
||||
{
|
||||
RemoveShortcutFromStartup();
|
||||
|
||||
var uninstallString = File.ReadAllText(UninstallFile);
|
||||
|
||||
new Process
|
||||
{
|
||||
StartInfo =
|
||||
{
|
||||
Arguments = uninstallString.Substring(uninstallString.IndexOf(" ", StringComparison.OrdinalIgnoreCase) + 1),
|
||||
FileName = uninstallString.Substring(0, uninstallString.IndexOf(" ", StringComparison.OrdinalIgnoreCase)),
|
||||
UseShellExecute = false
|
||||
}
|
||||
|
||||
}.Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user