using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.IO; using System.Linq; using System.Net.Mime; using System.Threading; using System.Threading.Tasks; using Jellyfin.Api.Attributes; using Jellyfin.Api.Constants; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Net; using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; using MediaBrowser.Model.IO; using MediaBrowser.Model.Net; using MediaBrowser.Model.System; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; namespace Jellyfin.Api.Controllers { /// /// The system controller. /// public class SystemController : BaseJellyfinApiController { private readonly IServerApplicationHost _appHost; private readonly IApplicationPaths _appPaths; private readonly IFileSystem _fileSystem; private readonly INetworkManager _network; private readonly ILogger _logger; /// /// Initializes a new instance of the class. /// /// Instance of interface. /// Instance of interface. /// Instance of interface. /// Instance of interface. /// Instance of interface. public SystemController( IServerConfigurationManager serverConfigurationManager, IServerApplicationHost appHost, IFileSystem fileSystem, INetworkManager network, ILogger logger) { _appPaths = serverConfigurationManager.ApplicationPaths; _appHost = appHost; _fileSystem = fileSystem; _network = network; _logger = logger; } /// /// Gets information about the server. /// /// Information retrieved. /// A with info about the system. [HttpGet("Info")] [Authorize(Policy = Policies.FirstTimeSetupOrIgnoreParentalControl)] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> GetSystemInfo() { return await _appHost.GetSystemInfo(CancellationToken.None).ConfigureAwait(false); } /// /// Gets public information about the server. /// /// Information retrieved. /// A with public info about the system. [HttpGet("Info/Public")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> GetPublicSystemInfo() { return await _appHost.GetPublicSystemInfo(CancellationToken.None).ConfigureAwait(false); } /// /// Pings the system. /// /// Information retrieved. /// The server name. [HttpGet("Ping", Name = "GetPingSystem")] [HttpPost("Ping", Name = "PostPingSystem")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult PingSystem() { return _appHost.Name; } /// /// Restarts the application. /// /// Server restarted. /// No content. Server restarted. [HttpPost("Restart")] [Authorize(Policy = Policies.LocalAccessOrRequiresElevation)] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult RestartApplication() { Task.Run(async () => { await Task.Delay(100).ConfigureAwait(false); _appHost.Restart(); }); return NoContent(); } /// /// Shuts down the application. /// /// Server shut down. /// No content. Server shut down. [HttpPost("Shutdown")] [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult ShutdownApplication() { Task.Run(async () => { await Task.Delay(100).ConfigureAwait(false); await _appHost.Shutdown().ConfigureAwait(false); }); return NoContent(); } /// /// Gets a list of available server log files. /// /// Information retrieved. /// An array of with the available log files. [HttpGet("Logs")] [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult GetServerLogs() { IEnumerable files; try { files = _fileSystem.GetFiles(_appPaths.LogDirectoryPath, new[] { ".txt", ".log" }, true, false); } catch (IOException ex) { _logger.LogError(ex, "Error getting logs"); files = Enumerable.Empty(); } var result = files.Select(i => new LogFile { DateCreated = _fileSystem.GetCreationTimeUtc(i), DateModified = _fileSystem.GetLastWriteTimeUtc(i), Name = i.Name, Size = i.Length }) .OrderByDescending(i => i.DateModified) .ThenByDescending(i => i.DateCreated) .ThenBy(i => i.Name) .ToArray(); return result; } /// /// Gets information about the request endpoint. /// /// Information retrieved. /// with information about the endpoint. [HttpGet("Endpoint")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult GetEndpointInfo() { return new EndPointInfo { IsLocal = Request.HttpContext.Connection.LocalIpAddress.Equals(Request.HttpContext.Connection.RemoteIpAddress), IsInNetwork = _network.IsInLocalNetwork(Request.HttpContext.Connection.RemoteIpAddress.ToString()) }; } /// /// Gets a log file. /// /// The name of the log file to get. /// Log file retrieved. /// The log file. [HttpGet("Logs/Log")] [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesFile(MediaTypeNames.Text.Plain)] public ActionResult GetLogFile([FromQuery, Required] string? name) { var file = _fileSystem.GetFiles(_appPaths.LogDirectoryPath) .First(i => string.Equals(i.Name, name, StringComparison.OrdinalIgnoreCase)); return File(file.FullName, MediaTypeNames.Text.Plain); } /// /// Gets wake on lan information. /// /// Information retrieved. /// An with the WakeOnLan infos. [HttpGet("WakeOnLanInfo")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetWakeOnLanInfo() { var result = _appHost.GetWakeOnLanInfo(); return Ok(result); } } }