using BDInfo;
using MediaBrowser.ClickOnce;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Kernel;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
using MediaBrowser.IsoMounter;
using MediaBrowser.Logging.Nlog;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Updates;
using MediaBrowser.Networking.Management;
using MediaBrowser.Networking.Udp;
using MediaBrowser.Networking.Web;
using MediaBrowser.Networking.WebSocket;
using MediaBrowser.Server.Uninstall;
using MediaBrowser.ServerApplication.Implementations;
using Microsoft.Win32;
using SimpleInjector;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Cache;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace MediaBrowser.ServerApplication
{
///
/// Interaction logic for App.xaml
///
public partial class App : Application, IApplicationHost
{
///
/// Defines the entry point of the application.
///
[STAThread]
public static void Main()
{
var application = new App(new NLogger("App"));
application.Run();
}
///
/// Gets the instance.
///
/// The instance.
public static App Instance
{
get
{
return Current as App;
}
}
///
/// The single instance mutex
///
private Mutex SingleInstanceMutex;
///
/// Gets or sets the kernel.
///
/// The kernel.
protected IKernel Kernel { get; set; }
///
/// Gets or sets the logger.
///
/// The logger.
protected ILogger Logger { get; set; }
///
/// Gets or sets the log file path.
///
/// The log file path.
public string LogFilePath { get; private set; }
///
/// The container
///
private Container _container = new Container();
///
/// Initializes a new instance of the class.
///
/// The logger.
public App(ILogger logger)
{
Logger = logger;
InitializeComponent();
}
///
/// Gets the name of the product.
///
/// The name of the product.
protected string ProductName
{
get { return Globals.ProductName; }
}
///
/// Gets the name of the publisher.
///
/// The name of the publisher.
protected string PublisherName
{
get { return Globals.PublisherName; }
}
///
/// Gets the name of the suite.
///
/// The name of the suite.
protected string SuiteName
{
get { return Globals.SuiteName; }
}
///
/// Gets the name of the uninstaller file.
///
/// The name of the uninstaller file.
protected string UninstallerFileName
{
get { return "MediaBrowser.Server.Uninstall.exe"; }
}
///
/// Gets or sets the iso manager.
///
/// The iso manager.
private IIsoManager IsoManager { get; set; }
///
/// Gets or sets a value indicating whether [last run at startup value].
///
/// null if [last run at startup value] contains no value, true if [last run at startup value]; otherwise, false.
private bool? LastRunAtStartupValue { get; set; }
///
/// Raises the event.
///
/// A that contains the event data.
protected override void OnStartup(StartupEventArgs e)
{
bool createdNew;
SingleInstanceMutex = new Mutex(true, @"Local\" + GetType().Assembly.GetName().Name, out createdNew);
if (!createdNew)
{
SingleInstanceMutex = null;
Shutdown();
return;
}
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
LoadKernel();
SystemEvents.SessionEnding += SystemEvents_SessionEnding;
}
///
/// Handles the UnhandledException event of the CurrentDomain control.
///
/// The source of the event.
/// The instance containing the event data.
void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
var exception = (Exception)e.ExceptionObject;
Logger.ErrorException("UnhandledException", exception);
MessageBox.Show("Unhandled exception: " + exception.Message);
}
///
/// Handles the SessionEnding event of the SystemEvents control.
///
/// The source of the event.
/// The instance containing the event data.
void SystemEvents_SessionEnding(object sender, SessionEndingEventArgs e)
{
// Try to shut down gracefully
Shutdown();
}
///
/// Loads the kernel.
///
protected async void LoadKernel()
{
Kernel = new Kernel(this, Logger);
RegisterResources();
try
{
new MainWindow(Logger).Show();
var now = DateTime.UtcNow;
await Kernel.Init();
var done = (DateTime.UtcNow - now);
Logger.Info("Kernel.Init completed in {0}{1} minutes and {2} seconds.", done.Hours > 0 ? done.Hours + " Hours " : "", done.Minutes, done.Seconds);
await OnKernelLoaded();
}
catch (Exception ex)
{
Logger.ErrorException("Error launching application", ex);
MessageBox.Show("There was an error launching Media Browser: " + ex.Message);
// Shutdown the app with an error code
Shutdown(1);
}
}
///
/// Called when [kernel loaded].
///
/// Task.
protected Task OnKernelLoaded()
{
return Task.Run(() =>
{
Kernel.ConfigurationUpdated += Kernel_ConfigurationUpdated;
ConfigureClickOnceStartup();
});
}
///
/// Handles the ConfigurationUpdated event of the Kernel control.
///
/// The source of the event.
/// The instance containing the event data.
void Kernel_ConfigurationUpdated(object sender, EventArgs e)
{
if (!LastRunAtStartupValue.HasValue || LastRunAtStartupValue.Value != Kernel.Configuration.RunAtStartup)
{
ConfigureClickOnceStartup();
}
}
///
/// Configures the click once startup.
///
private void ConfigureClickOnceStartup()
{
try
{
ClickOnceHelper.ConfigureClickOnceStartupIfInstalled(PublisherName, ProductName, SuiteName, Kernel.Configuration.RunAtStartup, UninstallerFileName);
LastRunAtStartupValue = Kernel.Configuration.RunAtStartup;
}
catch (Exception ex)
{
Logger.ErrorException("Error configuring ClickOnce", ex);
}
}
///
/// Raises the event.
///
/// An that contains the event data.
protected override void OnExit(ExitEventArgs e)
{
ReleaseMutex();
base.OnExit(e);
Kernel.Dispose();
}
///
/// Releases the mutex.
///
private void ReleaseMutex()
{
if (SingleInstanceMutex == null)
{
return;
}
SingleInstanceMutex.ReleaseMutex();
SingleInstanceMutex.Close();
SingleInstanceMutex.Dispose();
SingleInstanceMutex = null;
}
///
/// Opens the dashboard.
///
public static void OpenDashboard()
{
OpenDashboardPage("dashboard.html");
}
///
/// Opens the dashboard page.
///
/// The page.
public static void OpenDashboardPage(string page)
{
var url = "http://localhost:" + Controller.Kernel.Instance.Configuration.HttpServerPortNumber + "/" +
Controller.Kernel.Instance.WebApplicationName + "/dashboard/" + page;
url = AddAutoLoginToDashboardUrl(url);
OpenUrl(url);
}
///
/// Adds the auto login to dashboard URL.
///
/// The URL.
/// System.String.
public static string AddAutoLoginToDashboardUrl(string url)
{
var user = Controller.Kernel.Instance.Users.FirstOrDefault(u => u.Configuration.IsAdministrator);
if (user != null)
{
if (url.IndexOf('?') == -1)
{
url += "?u=" + user.Id;
}
else
{
url += "&u=" + user.Id;
}
}
return url;
}
///
/// Opens the URL.
///
/// The URL.
public static void OpenUrl(string url)
{
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = url
},
EnableRaisingEvents = true
};
process.Exited += ProcessExited;
process.Start();
}
///
/// Processes the exited.
///
/// The sender.
/// The instance containing the event data.
static void ProcessExited(object sender, EventArgs e)
{
((Process)sender).Dispose();
}
///
/// Restarts this instance.
///
///
public void Restart()
{
Dispatcher.Invoke(ReleaseMutex);
Kernel.Dispose();
System.Windows.Forms.Application.Restart();
Dispatcher.Invoke(Shutdown);
}
///
/// Reloads the logger.
///
///
public void ReloadLogger()
{
LogFilePath = Path.Combine(Kernel.ApplicationPaths.LogDirectoryPath, "Server-" + DateTime.Now.Ticks + ".log");
NlogManager.AddFileTarget(LogFilePath, Kernel.Configuration.EnableDebugLevelLogging);
}
///
/// Gets the image.
///
/// The URI.
/// Image.
/// uri
public Image GetImage(string uri)
{
if (string.IsNullOrEmpty(uri))
{
throw new ArgumentNullException("uri");
}
return GetImage(new Uri(uri));
}
///
/// Gets the image.
///
/// The URI.
/// Image.
/// uri
public Image GetImage(Uri uri)
{
if (uri == null)
{
throw new ArgumentNullException("uri");
}
return new Image { Source = GetBitmapImage(uri) };
}
///
/// Gets the bitmap image.
///
/// The URI.
/// BitmapImage.
/// uri
public BitmapImage GetBitmapImage(string uri)
{
if (string.IsNullOrEmpty(uri))
{
throw new ArgumentNullException("uri");
}
return GetBitmapImage(new Uri(uri));
}
///
/// Gets the bitmap image.
///
/// The URI.
/// BitmapImage.
/// uri
public BitmapImage GetBitmapImage(Uri uri)
{
if (uri == null)
{
throw new ArgumentNullException("uri");
}
var bitmap = new BitmapImage
{
CreateOptions = BitmapCreateOptions.DelayCreation,
CacheOption = BitmapCacheOption.OnDemand,
UriCachePolicy = new RequestCachePolicy(RequestCacheLevel.CacheIfAvailable)
};
bitmap.BeginInit();
bitmap.UriSource = uri;
bitmap.EndInit();
RenderOptions.SetBitmapScalingMode(bitmap, BitmapScalingMode.Fant);
return bitmap;
}
///
/// Gets or sets a value indicating whether this instance can self update.
///
/// true if this instance can self update; otherwise, false.
public bool CanSelfUpdate
{
get { return ClickOnceHelper.IsNetworkDeployed; }
}
///
/// Checks for update.
///
/// The cancellation token.
/// The progress.
/// Task{CheckForUpdateResult}.
public Task CheckForApplicationUpdate(CancellationToken cancellationToken, IProgress progress)
{
return new ApplicationUpdateCheck().CheckForApplicationUpdate(cancellationToken, progress);
}
///
/// Updates the application.
///
/// The cancellation token.
/// The progress.
/// Task.
public Task UpdateApplication(CancellationToken cancellationToken, IProgress progress)
{
return new ApplicationUpdater().UpdateApplication(cancellationToken, progress);
}
///
/// Registers resources that classes will depend on
///
private void RegisterResources()
{
RegisterSingleInstance(this);
RegisterSingleInstance(Logger);
IsoManager = new PismoIsoManager(Logger);
RegisterSingleInstance(IsoManager);
RegisterSingleInstance(() => new BdInfoExaminer());
RegisterSingleInstance(() => new NetworkManager());
RegisterSingleInstance(() => new DotNetZipClient());
RegisterSingleInstance(() => new AlchemyServer(Logger));
Register(typeof(IUdpServer), typeof(UdpServer));
RegisterSingleInstance(() => new HttpServer(this, Kernel, Logger, "Media Browser", "index.html"));
}
///
/// Creates an instance of type and resolves all constructor dependancies
///
/// The type.
/// System.Object.
public object CreateInstance(Type type)
{
try
{
return _container.GetInstance(type);
}
catch
{
Logger.Error("Error creating {0}", type.Name);
throw;
}
}
///
/// Registers the specified obj.
///
///
/// The obj.
public void RegisterSingleInstance(T obj)
where T : class
{
_container.RegisterSingle(obj);
}
///
/// Registers the specified func.
///
///
/// The func.
public void Register(Func func)
where T : class
{
_container.Register(func);
}
///
/// Registers the single instance.
///
///
/// The func.
public void RegisterSingleInstance(Func func)
where T : class
{
_container.RegisterSingle(func);
}
///
/// Resolves this instance.
///
///
/// ``0.
public T Resolve()
{
return (T)_container.GetRegistration(typeof(T), true).GetInstance();
}
///
/// Resolves this instance.
///
///
/// ``0.
public T TryResolve()
{
var result = _container.GetRegistration(typeof(T), false);
if (result == null)
{
return default(T);
}
return (T)result.GetInstance();
}
///
/// Registers the specified service type.
///
/// Type of the service.
/// Type of the concrete.
public void Register(Type serviceType, Type implementation)
{
_container.Register(serviceType, implementation);
}
}
}