using System; using System.Collections.Generic; using System.Threading.Tasks; using API.Interfaces.Services; using API.SignalR; using API.SignalR.Presence; using Flurl.Http; using Kavita.Common.EnvironmentInfo; using MarkdownDeep; using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; namespace API.Services.Tasks { internal class GithubReleaseMetadata { /// /// Name of the Tag /// v0.4.3 /// public string Tag_Name { get; init; } /// /// Name of the Release /// public string Name { get; init; } /// /// Body of the Release /// public string Body { get; init; } /// /// Url of the release on Github /// public string Html_Url { get; init; } } public class VersionUpdaterService : IVersionUpdaterService { private readonly ILogger _logger; private readonly IHubContext _messageHub; private readonly IPresenceTracker _tracker; private readonly Markdown _markdown = new MarkdownDeep.Markdown(); public VersionUpdaterService(ILogger logger, IHubContext messageHub, IPresenceTracker tracker) { _logger = logger; _messageHub = messageHub; _tracker = tracker; } /// /// Scheduled Task that checks if a newer version is available. If it is, will check if User is currently connected and push /// a message. /// public async Task CheckForUpdate() { var update = await GetGithubRelease(); if (update == null || string.IsNullOrEmpty(update.Tag_Name)) return; var admins = await _tracker.GetOnlineAdmins(); var version = update.Tag_Name.Replace("v", string.Empty); var updateVersion = new Version(version); if (BuildInfo.Version < updateVersion) { _logger.LogInformation("Server is out of date. Current: {CurrentVersion}. Available: {AvailableUpdate}", BuildInfo.Version, updateVersion); await SendEvent(update, admins); } else if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == Environments.Development) { _logger.LogInformation("Server is up to date. Current: {CurrentVersion}", BuildInfo.Version); await SendEvent(update, admins); } } private async Task SendEvent(GithubReleaseMetadata update, IReadOnlyList admins) { var version = update.Tag_Name.Replace("v", string.Empty); var updateVersion = new Version(version); var connections = new List(); foreach (var admin in admins) { connections.AddRange(await _tracker.GetConnectionsForUser(admin)); } await _messageHub.Clients.Users(admins).SendAsync("UpdateAvailable", new SignalRMessage { Name = "UpdateAvailable", Body = new { CurrentVersion = version, UpdateVersion = updateVersion.ToString(), UpdateBody = _markdown.Transform(update.Body.Trim()), UpdateTitle = update.Name, UpdateUrl = update.Html_Url, IsDocker = new OsInfo(Array.Empty()).IsDocker } }); } private static async Task GetGithubRelease() { var update = await "https://api.github.com/repos/Kareadita/Kavita/releases/latest" .WithHeader("Accept", "application/json") .WithHeader("User-Agent", "Kavita") .GetJsonAsync(); return update; } } }