Better Service dependency handling (#1535)

This commit is contained in:
srkizer 2023-11-29 06:20:16 +09:00 committed by GitHub
parent fcebd15077
commit b66be84b93
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 415 additions and 197 deletions

View file

@ -1,4 +1,3 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
@ -40,7 +39,7 @@ namespace Dalamud.Plugin.Internal;
/// Class responsible for loading and unloading plugins.
/// NOTE: ALL plugin exposed services are marked as dependencies for PluginManager in Service{T}.
/// </summary>
[ServiceManager.EarlyLoadedService]
[ServiceManager.BlockingEarlyLoadedService]
#pragma warning disable SA1015
// DalamudTextureWrap registers textures to dispose with IM
@ -85,6 +84,9 @@ internal partial class PluginManager : IDisposable, IServiceType
[ServiceManager.ServiceDependency]
private readonly HappyHttpClient happyHttpClient = Service<HappyHttpClient>.Get();
[ServiceManager.ServiceDependency]
private readonly ChatGui chatGui = Service<ChatGui>.Get();
static PluginManager()
{
DalamudApiLevel = typeof(PluginManager).Assembly.GetName().Version!.Major;
@ -131,12 +133,13 @@ internal partial class PluginManager : IDisposable, IServiceType
throw new InvalidDataException("Couldn't deserialize banned plugins manifest.");
}
this.openInstallerWindowPluginChangelogsLink = Service<ChatGui>.Get().AddChatLinkHandler("Dalamud", 1003, (_, _) =>
this.openInstallerWindowPluginChangelogsLink = this.chatGui.AddChatLinkHandler("Dalamud", 1003, (_, _) =>
{
Service<DalamudInterface>.GetNullable()?.OpenPluginInstallerTo(PluginInstallerWindow.PluginInstallerOpenKind.Changelogs);
});
this.configuration.PluginTestingOptIns ??= new List<PluginTestingOptIn>();
this.configuration.PluginTestingOptIns ??= new();
this.MainRepo = PluginRepository.CreateMainRepo(this.happyHttpClient);
this.ApplyPatches();
}
@ -199,6 +202,11 @@ internal partial class PluginManager : IDisposable, IServiceType
}
}
/// <summary>
/// Gets the main repository.
/// </summary>
public PluginRepository MainRepo { get; }
/// <summary>
/// Gets a list of all plugin repositories. The main repo should always be first.
/// </summary>
@ -284,11 +292,9 @@ internal partial class PluginManager : IDisposable, IServiceType
/// <param name="header">The header text to send to chat prior to any update info.</param>
public void PrintUpdatedPlugins(List<PluginUpdateStatus>? updateMetadata, string header)
{
var chatGui = Service<ChatGui>.Get();
if (updateMetadata is { Count: > 0 })
{
chatGui.Print(new XivChatEntry
this.chatGui.Print(new XivChatEntry
{
Message = new SeString(new List<Payload>()
{
@ -307,11 +313,11 @@ internal partial class PluginManager : IDisposable, IServiceType
{
if (metadata.Status == PluginUpdateStatus.StatusKind.Success)
{
chatGui.Print(Locs.DalamudPluginUpdateSuccessful(metadata.Name, metadata.Version));
this.chatGui.Print(Locs.DalamudPluginUpdateSuccessful(metadata.Name, metadata.Version));
}
else
{
chatGui.Print(new XivChatEntry
this.chatGui.Print(new XivChatEntry
{
Message = Locs.DalamudPluginUpdateFailed(metadata.Name, metadata.Version, PluginUpdateStatus.LocalizeUpdateStatusKind(metadata.Status)),
Type = XivChatType.Urgent,
@ -407,10 +413,10 @@ internal partial class PluginManager : IDisposable, IServiceType
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public async Task SetPluginReposFromConfigAsync(bool notify)
{
var repos = new List<PluginRepository>() { PluginRepository.MainRepo };
var repos = new List<PluginRepository> { this.MainRepo };
repos.AddRange(this.configuration.ThirdRepoList
.Where(repo => repo.IsEnabled)
.Select(repo => new PluginRepository(repo.Url, repo.IsEnabled)));
.Select(repo => new PluginRepository(this.happyHttpClient, repo.Url, repo.IsEnabled)));
this.Repos = repos;
await this.ReloadPluginMastersAsync(notify);

View file

@ -267,10 +267,6 @@ internal class LocalPlugin : IDisposable
var pluginManager = await Service<PluginManager>.GetAsync();
var dalamud = await Service<Dalamud>.GetAsync();
// UiBuilder constructor requires the following two.
await Service<InterfaceManager>.GetAsync();
await Service<GameFontManager>.GetAsync();
if (this.manifest.LoadRequiredState == 0)
_ = await Service<InterfaceManager.InterfaceManagerWithScene>.GetAsync();

View file

@ -28,47 +28,44 @@ internal class PluginRepository
private static readonly ModuleLog Log = new("PLUGINR");
private static readonly HttpClient HttpClient = new(new SocketsHttpHandler
{
AutomaticDecompression = DecompressionMethods.All,
ConnectCallback = Service<HappyHttpClient>.Get().SharedHappyEyeballsCallback.ConnectCallback,
})
{
Timeout = TimeSpan.FromSeconds(20),
DefaultRequestHeaders =
{
Accept =
{
new MediaTypeWithQualityHeaderValue("application/json"),
},
CacheControl = new CacheControlHeaderValue
{
NoCache = true,
},
UserAgent =
{
new ProductInfoHeaderValue("Dalamud", Util.AssemblyVersion),
},
},
};
private readonly HttpClient httpClient;
/// <summary>
/// Initializes a new instance of the <see cref="PluginRepository"/> class.
/// </summary>
/// <param name="happyHttpClient">An instance of <see cref="HappyHttpClient"/>.</param>
/// <param name="pluginMasterUrl">The plugin master URL.</param>
/// <param name="isEnabled">Whether the plugin repo is enabled.</param>
public PluginRepository(string pluginMasterUrl, bool isEnabled)
public PluginRepository(HappyHttpClient happyHttpClient, string pluginMasterUrl, bool isEnabled)
{
this.httpClient = new(new SocketsHttpHandler
{
AutomaticDecompression = DecompressionMethods.All,
ConnectCallback = happyHttpClient.SharedHappyEyeballsCallback.ConnectCallback,
})
{
Timeout = TimeSpan.FromSeconds(20),
DefaultRequestHeaders =
{
Accept =
{
new MediaTypeWithQualityHeaderValue("application/json"),
},
CacheControl = new CacheControlHeaderValue
{
NoCache = true,
},
UserAgent =
{
new ProductInfoHeaderValue("Dalamud", Util.AssemblyVersion),
},
},
};
this.PluginMasterUrl = pluginMasterUrl;
this.IsThirdParty = pluginMasterUrl != MainRepoUrl;
this.IsEnabled = isEnabled;
}
/// <summary>
/// Gets a new instance of the <see cref="PluginRepository"/> class for the main repo.
/// </summary>
public static PluginRepository MainRepo => new(MainRepoUrl, true);
/// <summary>
/// Gets the pluginmaster.json URL.
/// </summary>
@ -94,6 +91,14 @@ internal class PluginRepository
/// </summary>
public PluginRepositoryState State { get; private set; }
/// <summary>
/// Gets a new instance of the <see cref="PluginRepository"/> class for the main repo.
/// </summary>
/// <param name="happyHttpClient">An instance of <see cref="HappyHttpClient"/>.</param>
/// <returns>The new instance of main repository.</returns>
public static PluginRepository CreateMainRepo(HappyHttpClient happyHttpClient) =>
new(happyHttpClient, MainRepoUrl, true);
/// <summary>
/// Reload the plugin master asynchronously in a task.
/// </summary>
@ -107,7 +112,7 @@ internal class PluginRepository
{
Log.Information($"Fetching repo: {this.PluginMasterUrl}");
using var response = await HttpClient.GetAsync(this.PluginMasterUrl);
using var response = await this.httpClient.GetAsync(this.PluginMasterUrl);
response.EnsureSuccessStatusCode();
var data = await response.Content.ReadAsStringAsync();