btcpayserver/BTCPayServer/HostedServices/PluginUpdateFetcher.cs
d11n a962e60de9
More Translations (#6318)
* Store selector

* Footer

* Notifications

* Checkout Appearance

* Users list

* Forms

* Emails

* Pay Button

* Edit Dictionary

* Remove newlines, fix typos

* Forms

* Pull payments and payouts

* Various pages

* Use local docs link

* Fix

* Even more translations

* Fixes #6325

* Account pages

* Notifications

* Placeholders

* Various pages and components

* Add more
2024-10-25 22:48:53 +09:00

122 lines
4.8 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using BTCPayServer.Abstractions.Contracts;
using BTCPayServer.Configuration;
using BTCPayServer.Controllers;
using BTCPayServer.Plugins;
using BTCPayServer.Services;
using BTCPayServer.Services.Notifications;
using BTCPayServer.Services.Notifications.Blobs;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;
namespace BTCPayServer.HostedServices
{
internal class PluginUpdateNotification : BaseNotification
{
private const string TYPE = "pluginupdate";
internal class Handler(LinkGenerator linkGenerator, BTCPayServerOptions options, IStringLocalizer stringLocalizer) : NotificationHandler<PluginUpdateNotification>
{
private IStringLocalizer StringLocalizer { get; } = stringLocalizer;
public override string NotificationType => TYPE;
public override (string identifier, string name)[] Meta
{
get
{
return new (string identifier, string name)[] {(TYPE, StringLocalizer["Plugin update"])};
}
}
protected override void FillViewModel(PluginUpdateNotification notification, NotificationViewModel vm)
{
vm.Identifier = notification.Identifier;
vm.Type = notification.NotificationType;
vm.Body = StringLocalizer["New {0} plugin version {1} released!", notification.Name, notification.Version];
vm.ActionLink = linkGenerator.GetPathByAction(nameof(UIServerController.ListPlugins),
"UIServer",
new {plugin = notification.PluginIdentifier}, options.RootPath);
}
}
public PluginUpdateNotification()
{
}
public PluginUpdateNotification(PluginService.AvailablePlugin plugin)
{
Name = plugin.Name;
PluginIdentifier = plugin.Identifier;
Version = plugin.Version.ToString();
}
public string PluginIdentifier { get; set; }
public string Name { get; set; }
public string Version { get; set; }
public override string Identifier => TYPE;
public override string NotificationType => TYPE;
}
public class PluginVersionCheckerDataHolder
{
public Dictionary<string, Version> LastVersions { get; set; }
}
public class PluginUpdateFetcher(SettingsRepository settingsRepository, NotificationSender notificationSender, PluginService pluginService)
: IPeriodicTask
{
public async Task Do(CancellationToken cancellationToken)
{
var dh = await settingsRepository.GetSettingAsync<PluginVersionCheckerDataHolder>() ??
new PluginVersionCheckerDataHolder();
dh.LastVersions ??= new Dictionary<string, Version>();
var disabledPlugins = pluginService.GetDisabledPlugins();
var installedPlugins =
pluginService.LoadedPlugins.ToDictionary(plugin => plugin.Identifier, plugin => plugin.Version);
var remotePlugins = await pluginService.GetRemotePlugins(null);
//take the latest version of each plugin
var remotePluginsList = remotePlugins
.GroupBy(plugin => plugin.Identifier)
.Select(group => group.OrderByDescending(plugin => plugin.Version).First())
.Where(pair => installedPlugins.ContainsKey(pair.Identifier) || disabledPlugins.ContainsKey(pair.Name))
.ToDictionary(plugin => plugin.Identifier, plugin => plugin.Version);
var notify = new HashSet<string>();
foreach (var pair in remotePluginsList)
{
if (dh.LastVersions.TryGetValue(pair.Key, out var lastVersion) && lastVersion >= pair.Value)
continue;
if (installedPlugins.TryGetValue(pair.Key, out var installedVersion) && installedVersion < pair.Value)
{
notify.Add(pair.Key);
}
else if (disabledPlugins.TryGetValue(pair.Key, out var disabledVersion) && disabledVersion < pair.Value)
{
notify.Add(pair.Key);
}
}
dh.LastVersions = remotePluginsList;
foreach (string pluginUpdate in notify)
{
var plugin = remotePlugins.First(p => p.Identifier == pluginUpdate);
await notificationSender.SendNotification(new AdminScope(), new PluginUpdateNotification(plugin));
}
await settingsRepository.UpdateSetting(dh);
}
}
}