123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228 |
- using System;
- using System.Collections.Generic;
- using System.ComponentModel.DataAnnotations;
- using System.IO;
- using System.Linq;
- using System.Net.Mime;
- using Jellyfin.Api.Attributes;
- using Jellyfin.Api.Models.SystemInfoDtos;
- using MediaBrowser.Common.Api;
- using MediaBrowser.Common.Configuration;
- using MediaBrowser.Common.Extensions;
- using MediaBrowser.Common.Net;
- using MediaBrowser.Controller;
- 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;
- /// <summary>
- /// The system controller.
- /// </summary>
- public class SystemController : BaseJellyfinApiController
- {
- private readonly ILogger<SystemController> _logger;
- private readonly IServerApplicationHost _appHost;
- private readonly IApplicationPaths _appPaths;
- private readonly IFileSystem _fileSystem;
- private readonly INetworkManager _networkManager;
- private readonly ISystemManager _systemManager;
- /// <summary>
- /// Initializes a new instance of the <see cref="SystemController"/> class.
- /// </summary>
- /// <param name="logger">Instance of <see cref="ILogger{SystemController}"/> interface.</param>
- /// <param name="appPaths">Instance of <see cref="IServerApplicationPaths"/> interface.</param>
- /// <param name="appHost">Instance of <see cref="IServerApplicationHost"/> interface.</param>
- /// <param name="fileSystem">Instance of <see cref="IFileSystem"/> interface.</param>
- /// <param name="networkManager">Instance of <see cref="INetworkManager"/> interface.</param>
- /// <param name="systemManager">Instance of <see cref="ISystemManager"/> interface.</param>
- public SystemController(
- ILogger<SystemController> logger,
- IServerApplicationHost appHost,
- IServerApplicationPaths appPaths,
- IFileSystem fileSystem,
- INetworkManager networkManager,
- ISystemManager systemManager)
- {
- _logger = logger;
- _appHost = appHost;
- _appPaths = appPaths;
- _fileSystem = fileSystem;
- _networkManager = networkManager;
- _systemManager = systemManager;
- }
- /// <summary>
- /// Gets information about the server.
- /// </summary>
- /// <response code="200">Information retrieved.</response>
- /// <response code="403">User does not have permission to retrieve information.</response>
- /// <returns>A <see cref="SystemInfo"/> with info about the system.</returns>
- [HttpGet("Info")]
- [Authorize(Policy = Policies.FirstTimeSetupOrIgnoreParentalControl)]
- [ProducesResponseType(StatusCodes.Status200OK)]
- [ProducesResponseType(StatusCodes.Status403Forbidden)]
- public ActionResult<SystemInfo> GetSystemInfo()
- => _systemManager.GetSystemInfo(Request);
- /// <summary>
- /// Gets information about the server.
- /// </summary>
- /// <response code="200">Information retrieved.</response>
- /// <response code="403">User does not have permission to retrieve information.</response>
- /// <returns>A <see cref="SystemInfo"/> with info about the system.</returns>
- [HttpGet("Info/Storage")]
- [Authorize(Policy = Policies.RequiresElevation)]
- [ProducesResponseType(StatusCodes.Status200OK)]
- [ProducesResponseType(StatusCodes.Status403Forbidden)]
- public ActionResult<SystemStorageDto> GetSystemStorage()
- => Ok(SystemStorageDto.FromSystemStorageInfo(_systemManager.GetSystemStorageInfo()));
- /// <summary>
- /// Gets public information about the server.
- /// </summary>
- /// <response code="200">Information retrieved.</response>
- /// <returns>A <see cref="PublicSystemInfo"/> with public info about the system.</returns>
- [HttpGet("Info/Public")]
- [ProducesResponseType(StatusCodes.Status200OK)]
- public ActionResult<PublicSystemInfo> GetPublicSystemInfo()
- => _systemManager.GetPublicSystemInfo(Request);
- /// <summary>
- /// Pings the system.
- /// </summary>
- /// <response code="200">Information retrieved.</response>
- /// <returns>The server name.</returns>
- [HttpGet("Ping", Name = "GetPingSystem")]
- [HttpPost("Ping", Name = "PostPingSystem")]
- [ProducesResponseType(StatusCodes.Status200OK)]
- public ActionResult<string> PingSystem()
- => _appHost.Name;
- /// <summary>
- /// Restarts the application.
- /// </summary>
- /// <response code="204">Server restarted.</response>
- /// <response code="403">User does not have permission to restart server.</response>
- /// <returns>No content. Server restarted.</returns>
- [HttpPost("Restart")]
- [Authorize(Policy = Policies.LocalAccessOrRequiresElevation)]
- [ProducesResponseType(StatusCodes.Status204NoContent)]
- [ProducesResponseType(StatusCodes.Status403Forbidden)]
- public ActionResult RestartApplication()
- {
- _systemManager.Restart();
- return NoContent();
- }
- /// <summary>
- /// Shuts down the application.
- /// </summary>
- /// <response code="204">Server shut down.</response>
- /// <response code="403">User does not have permission to shutdown server.</response>
- /// <returns>No content. Server shut down.</returns>
- [HttpPost("Shutdown")]
- [Authorize(Policy = Policies.RequiresElevation)]
- [ProducesResponseType(StatusCodes.Status204NoContent)]
- [ProducesResponseType(StatusCodes.Status403Forbidden)]
- public ActionResult ShutdownApplication()
- {
- _systemManager.Shutdown();
- return NoContent();
- }
- /// <summary>
- /// Gets a list of available server log files.
- /// </summary>
- /// <response code="200">Information retrieved.</response>
- /// <response code="403">User does not have permission to get server logs.</response>
- /// <returns>An array of <see cref="LogFile"/> with the available log files.</returns>
- [HttpGet("Logs")]
- [Authorize(Policy = Policies.RequiresElevation)]
- [ProducesResponseType(StatusCodes.Status200OK)]
- [ProducesResponseType(StatusCodes.Status403Forbidden)]
- public ActionResult<LogFile[]> GetServerLogs()
- {
- IEnumerable<FileSystemMetadata> files;
- try
- {
- files = _fileSystem.GetFiles(_appPaths.LogDirectoryPath, new[] { ".txt", ".log" }, true, false);
- }
- catch (IOException ex)
- {
- _logger.LogError(ex, "Error getting logs");
- files = Enumerable.Empty<FileSystemMetadata>();
- }
- 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;
- }
- /// <summary>
- /// Gets information about the request endpoint.
- /// </summary>
- /// <response code="200">Information retrieved.</response>
- /// <response code="403">User does not have permission to get endpoint information.</response>
- /// <returns><see cref="EndPointInfo"/> with information about the endpoint.</returns>
- [HttpGet("Endpoint")]
- [Authorize]
- [ProducesResponseType(StatusCodes.Status200OK)]
- [ProducesResponseType(StatusCodes.Status403Forbidden)]
- public ActionResult<EndPointInfo> GetEndpointInfo()
- {
- return new EndPointInfo
- {
- IsLocal = HttpContext.IsLocal(),
- IsInNetwork = _networkManager.IsInLocalNetwork(HttpContext.GetNormalizedRemoteIP())
- };
- }
- /// <summary>
- /// Gets a log file.
- /// </summary>
- /// <param name="name">The name of the log file to get.</param>
- /// <response code="200">Log file retrieved.</response>
- /// <response code="403">User does not have permission to get log files.</response>
- /// <response code="404">Could not find a log file with the name.</response>
- /// <returns>The log file.</returns>
- [HttpGet("Logs/Log")]
- [Authorize(Policy = Policies.RequiresElevation)]
- [ProducesResponseType(StatusCodes.Status200OK)]
- [ProducesResponseType(StatusCodes.Status403Forbidden)]
- [ProducesResponseType(StatusCodes.Status404NotFound)]
- [ProducesFile(MediaTypeNames.Text.Plain)]
- public ActionResult GetLogFile([FromQuery, Required] string name)
- {
- var file = _fileSystem
- .GetFiles(_appPaths.LogDirectoryPath)
- .FirstOrDefault(i => string.Equals(i.Name, name, StringComparison.OrdinalIgnoreCase));
- if (file is null)
- {
- return NotFound("Log file not found.");
- }
- // For older files, assume fully static
- var fileShare = file.LastWriteTimeUtc < DateTime.UtcNow.AddHours(-1) ? FileShare.Read : FileShare.ReadWrite;
- FileStream stream = new FileStream(file.FullName, FileMode.Open, FileAccess.Read, fileShare, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous);
- return File(stream, "text/plain; charset=utf-8");
- }
- }
|