< Summary - Jellyfin

Information
Class: Jellyfin.Api.Controllers.SystemController
Assembly: Jellyfin.Api
File(s): /srv/git/jellyfin/Jellyfin.Api/Controllers/SystemController.cs
Line coverage
35%
Covered lines: 19
Uncovered lines: 34
Coverable lines: 53
Total lines: 229
Line coverage: 35.8%
Branch coverage
25%
Covered branches: 1
Total branches: 4
Branch coverage: 25%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
GetSystemInfo()100%210%
GetSystemStorage()100%210%
GetPublicSystemInfo()100%210%
PingSystem()100%210%
RestartApplication()100%210%
ShutdownApplication()100%210%
GetServerLogs()100%210%
GetEndpointInfo()100%210%
GetLogFile(...)25%5462.5%

File(s)

/srv/git/jellyfin/Jellyfin.Api/Controllers/SystemController.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.ComponentModel.DataAnnotations;
 4using System.IO;
 5using System.Linq;
 6using System.Net.Mime;
 7using Jellyfin.Api.Attributes;
 8using Jellyfin.Api.Constants;
 9using Jellyfin.Api.Models.SystemInfoDtos;
 10using MediaBrowser.Common.Api;
 11using MediaBrowser.Common.Configuration;
 12using MediaBrowser.Common.Extensions;
 13using MediaBrowser.Common.Net;
 14using MediaBrowser.Controller;
 15using MediaBrowser.Model.IO;
 16using MediaBrowser.Model.Net;
 17using MediaBrowser.Model.System;
 18using Microsoft.AspNetCore.Authorization;
 19using Microsoft.AspNetCore.Http;
 20using Microsoft.AspNetCore.Mvc;
 21using Microsoft.Extensions.Logging;
 22
 23namespace Jellyfin.Api.Controllers;
 24
 25/// <summary>
 26/// The system controller.
 27/// </summary>
 28public class SystemController : BaseJellyfinApiController
 29{
 30    private readonly ILogger<SystemController> _logger;
 31    private readonly IServerApplicationHost _appHost;
 32    private readonly IApplicationPaths _appPaths;
 33    private readonly IFileSystem _fileSystem;
 34    private readonly INetworkManager _networkManager;
 35    private readonly ISystemManager _systemManager;
 36
 37    /// <summary>
 38    /// Initializes a new instance of the <see cref="SystemController"/> class.
 39    /// </summary>
 40    /// <param name="logger">Instance of <see cref="ILogger{SystemController}"/> interface.</param>
 41    /// <param name="appPaths">Instance of <see cref="IServerApplicationPaths"/> interface.</param>
 42    /// <param name="appHost">Instance of <see cref="IServerApplicationHost"/> interface.</param>
 43    /// <param name="fileSystem">Instance of <see cref="IFileSystem"/> interface.</param>
 44    /// <param name="networkManager">Instance of <see cref="INetworkManager"/> interface.</param>
 45    /// <param name="systemManager">Instance of <see cref="ISystemManager"/> interface.</param>
 146    public SystemController(
 147        ILogger<SystemController> logger,
 148        IServerApplicationHost appHost,
 149        IServerApplicationPaths appPaths,
 150        IFileSystem fileSystem,
 151        INetworkManager networkManager,
 152        ISystemManager systemManager)
 53    {
 154        _logger = logger;
 155        _appHost = appHost;
 156        _appPaths = appPaths;
 157        _fileSystem = fileSystem;
 158        _networkManager = networkManager;
 159        _systemManager = systemManager;
 160    }
 61
 62    /// <summary>
 63    /// Gets information about the server.
 64    /// </summary>
 65    /// <response code="200">Information retrieved.</response>
 66    /// <response code="403">User does not have permission to retrieve information.</response>
 67    /// <returns>A <see cref="SystemInfo"/> with info about the system.</returns>
 68    [HttpGet("Info")]
 69    [Authorize(Policy = Policies.FirstTimeSetupOrIgnoreParentalControl)]
 70    [ProducesResponseType(StatusCodes.Status200OK)]
 71    [ProducesResponseType(StatusCodes.Status403Forbidden)]
 72    public ActionResult<SystemInfo> GetSystemInfo()
 073        => _systemManager.GetSystemInfo(Request);
 74
 75    /// <summary>
 76    /// Gets information about the server.
 77    /// </summary>
 78    /// <response code="200">Information retrieved.</response>
 79    /// <response code="403">User does not have permission to retrieve information.</response>
 80    /// <returns>A <see cref="SystemInfo"/> with info about the system.</returns>
 81    [HttpGet("Info/Storage")]
 82    [Authorize(Policy = Policies.RequiresElevation)]
 83    [ProducesResponseType(StatusCodes.Status200OK)]
 84    [ProducesResponseType(StatusCodes.Status403Forbidden)]
 85    public ActionResult<SystemStorageDto> GetSystemStorage()
 086        => Ok(SystemStorageDto.FromSystemStorageInfo(_systemManager.GetSystemStorageInfo()));
 87
 88    /// <summary>
 89    /// Gets public information about the server.
 90    /// </summary>
 91    /// <response code="200">Information retrieved.</response>
 92    /// <returns>A <see cref="PublicSystemInfo"/> with public info about the system.</returns>
 93    [HttpGet("Info/Public")]
 94    [ProducesResponseType(StatusCodes.Status200OK)]
 95    public ActionResult<PublicSystemInfo> GetPublicSystemInfo()
 096        => _systemManager.GetPublicSystemInfo(Request);
 97
 98    /// <summary>
 99    /// Pings the system.
 100    /// </summary>
 101    /// <response code="200">Information retrieved.</response>
 102    /// <returns>The server name.</returns>
 103    [HttpGet("Ping", Name = "GetPingSystem")]
 104    [HttpPost("Ping", Name = "PostPingSystem")]
 105    [ProducesResponseType(StatusCodes.Status200OK)]
 106    public ActionResult<string> PingSystem()
 0107        => _appHost.Name;
 108
 109    /// <summary>
 110    /// Restarts the application.
 111    /// </summary>
 112    /// <response code="204">Server restarted.</response>
 113    /// <response code="403">User does not have permission to restart server.</response>
 114    /// <returns>No content. Server restarted.</returns>
 115    [HttpPost("Restart")]
 116    [Authorize(Policy = Policies.LocalAccessOrRequiresElevation)]
 117    [ProducesResponseType(StatusCodes.Status204NoContent)]
 118    [ProducesResponseType(StatusCodes.Status403Forbidden)]
 119    public ActionResult RestartApplication()
 120    {
 0121        _systemManager.Restart();
 0122        return NoContent();
 123    }
 124
 125    /// <summary>
 126    /// Shuts down the application.
 127    /// </summary>
 128    /// <response code="204">Server shut down.</response>
 129    /// <response code="403">User does not have permission to shutdown server.</response>
 130    /// <returns>No content. Server shut down.</returns>
 131    [HttpPost("Shutdown")]
 132    [Authorize(Policy = Policies.RequiresElevation)]
 133    [ProducesResponseType(StatusCodes.Status204NoContent)]
 134    [ProducesResponseType(StatusCodes.Status403Forbidden)]
 135    public ActionResult ShutdownApplication()
 136    {
 0137        _systemManager.Shutdown();
 0138        return NoContent();
 139    }
 140
 141    /// <summary>
 142    /// Gets a list of available server log files.
 143    /// </summary>
 144    /// <response code="200">Information retrieved.</response>
 145    /// <response code="403">User does not have permission to get server logs.</response>
 146    /// <returns>An array of <see cref="LogFile"/> with the available log files.</returns>
 147    [HttpGet("Logs")]
 148    [Authorize(Policy = Policies.RequiresElevation)]
 149    [ProducesResponseType(StatusCodes.Status200OK)]
 150    [ProducesResponseType(StatusCodes.Status403Forbidden)]
 151    public ActionResult<LogFile[]> GetServerLogs()
 152    {
 153        IEnumerable<FileSystemMetadata> files;
 154
 155        try
 156        {
 0157            files = _fileSystem.GetFiles(_appPaths.LogDirectoryPath, new[] { ".txt", ".log" }, true, false);
 0158        }
 0159        catch (IOException ex)
 160        {
 0161            _logger.LogError(ex, "Error getting logs");
 0162            files = Enumerable.Empty<FileSystemMetadata>();
 0163        }
 164
 0165        var result = files.Select(i => new LogFile
 0166        {
 0167            DateCreated = _fileSystem.GetCreationTimeUtc(i),
 0168            DateModified = _fileSystem.GetLastWriteTimeUtc(i),
 0169            Name = i.Name,
 0170            Size = i.Length
 0171        })
 0172            .OrderByDescending(i => i.DateModified)
 0173            .ThenByDescending(i => i.DateCreated)
 0174            .ThenBy(i => i.Name)
 0175            .ToArray();
 176
 0177        return result;
 178    }
 179
 180    /// <summary>
 181    /// Gets information about the request endpoint.
 182    /// </summary>
 183    /// <response code="200">Information retrieved.</response>
 184    /// <response code="403">User does not have permission to get endpoint information.</response>
 185    /// <returns><see cref="EndPointInfo"/> with information about the endpoint.</returns>
 186    [HttpGet("Endpoint")]
 187    [Authorize]
 188    [ProducesResponseType(StatusCodes.Status200OK)]
 189    [ProducesResponseType(StatusCodes.Status403Forbidden)]
 190    public ActionResult<EndPointInfo> GetEndpointInfo()
 191    {
 0192        return new EndPointInfo
 0193        {
 0194            IsLocal = HttpContext.IsLocal(),
 0195            IsInNetwork = _networkManager.IsInLocalNetwork(HttpContext.GetNormalizedRemoteIP())
 0196        };
 197    }
 198
 199    /// <summary>
 200    /// Gets a log file.
 201    /// </summary>
 202    /// <param name="name">The name of the log file to get.</param>
 203    /// <response code="200">Log file retrieved.</response>
 204    /// <response code="403">User does not have permission to get log files.</response>
 205    /// <response code="404">Could not find a log file with the name.</response>
 206    /// <returns>The log file.</returns>
 207    [HttpGet("Logs/Log")]
 208    [Authorize(Policy = Policies.RequiresElevation)]
 209    [ProducesResponseType(StatusCodes.Status200OK)]
 210    [ProducesResponseType(StatusCodes.Status403Forbidden)]
 211    [ProducesResponseType(StatusCodes.Status404NotFound)]
 212    [ProducesFile(MediaTypeNames.Text.Plain)]
 213    public ActionResult GetLogFile([FromQuery, Required] string name)
 214    {
 1215        var file = _fileSystem
 1216            .GetFiles(_appPaths.LogDirectoryPath)
 1217            .FirstOrDefault(i => string.Equals(i.Name, name, StringComparison.OrdinalIgnoreCase));
 218
 1219        if (file is null)
 220        {
 1221            return NotFound("Log file not found.");
 222        }
 223
 224        // For older files, assume fully static
 0225        var fileShare = file.LastWriteTimeUtc < DateTime.UtcNow.AddHours(-1) ? FileShare.Read : FileShare.ReadWrite;
 0226        FileStream stream = new FileStream(file.FullName, FileMode.Open, FileAccess.Read, fileShare, IODefaults.FileStre
 0227        return File(stream, "text/plain; charset=utf-8");
 228    }
 229}