merge master into profiles

This commit is contained in:
goat 2023-05-28 16:06:05 +02:00
commit fe6196d0ad
No known key found for this signature in database
GPG key ID: 49E2AA8C6A76498B
57 changed files with 1118 additions and 287 deletions

View file

@ -22,6 +22,7 @@ using Dalamud.Game.Text.SeStringHandling.Payloads;
using Dalamud.Interface.Internal;
using Dalamud.IoC.Internal;
using Dalamud.Logging.Internal;
using Dalamud.Networking.Http;
using Dalamud.Plugin.Internal.Exceptions;
using Dalamud.Plugin.Internal.Profiles;
using Dalamud.Plugin.Internal.Types;
@ -41,6 +42,9 @@ namespace Dalamud.Plugin.Internal;
// DalamudTextureWrap registers textures to dispose with IM
[InherentDependency<InterfaceManager>]
// LocalPlugin uses ServiceContainer to create scopes
[InherentDependency<ServiceContainer>]
#pragma warning restore SA1015
internal partial class PluginManager : IDisposable, IServiceType
{
@ -54,15 +58,6 @@ internal partial class PluginManager : IDisposable, IServiceType
/// </summary>
public const int PluginWaitBeforeFreeDefault = 1000; // upped from 500ms, seems more stable
private const string DevPluginsDisclaimerFilename = "DONT_USE_THIS_FOLDER.txt";
private const string DevPluginsDisclaimerText = @"Hey!
The devPlugins folder is deprecated and will be removed soon. Please don't use it anymore for plugin development.
Instead, open the Dalamud settings and add the path to your plugins build output folder as a dev plugin location.
Remove your devPlugin from this folder.
Thanks and have fun!";
private static readonly ModuleLog Log = new("PLUGINM");
private readonly object pluginListLock = new();
@ -81,22 +76,17 @@ Thanks and have fun!";
[ServiceManager.ServiceDependency]
private readonly ProfileManager profileManager = Service<ProfileManager>.Get();
[ServiceManager.ServiceDependency]
private readonly HappyHttpClient happyHttpClient = Service<HappyHttpClient>.Get();
[ServiceManager.ServiceConstructor]
private PluginManager()
{
this.pluginDirectory = new DirectoryInfo(this.startInfo.PluginDirectory!);
this.devPluginDirectory = new DirectoryInfo(this.startInfo.DefaultPluginDirectory!);
if (!this.pluginDirectory.Exists)
this.pluginDirectory.Create();
if (!this.devPluginDirectory.Exists)
this.devPluginDirectory.Create();
var disclaimerFileName = Path.Combine(this.devPluginDirectory.FullName, DevPluginsDisclaimerFilename);
if (!File.Exists(disclaimerFileName))
File.WriteAllText(disclaimerFileName, DevPluginsDisclaimerText);
this.SafeMode = EnvironmentConfiguration.DalamudNoPlugins || this.configuration.PluginSafeMode || this.startInfo.NoLoadPlugins;
try
@ -391,9 +381,6 @@ Thanks and have fun!";
if (!this.pluginDirectory.Exists)
this.pluginDirectory.Create();
if (!this.devPluginDirectory.Exists)
this.devPluginDirectory.Create();
// Add installed plugins. These are expected to be in a specific format so we can look for exactly that.
foreach (var pluginDir in this.pluginDirectory.GetDirectories())
{
@ -434,7 +421,7 @@ Thanks and have fun!";
}
// devPlugins are more freeform. Look for any dll and hope to get lucky.
var devDllFiles = this.devPluginDirectory.GetFiles("*.dll", SearchOption.AllDirectories).ToList();
var devDllFiles = new List<FileInfo>();
foreach (var setting in this.configuration.DevPluginLoadLocations)
{
@ -657,11 +644,8 @@ Thanks and have fun!";
/// </summary>
public void ScanDevPlugins()
{
if (!this.devPluginDirectory.Exists)
this.devPluginDirectory.Create();
// devPlugins are more freeform. Look for any dll and hope to get lucky.
var devDllFiles = this.devPluginDirectory.GetFiles("*.dll", SearchOption.AllDirectories).ToList();
var devDllFiles = new List<FileInfo>();
foreach (var setting in this.configuration.DevPluginLoadLocations)
{
@ -736,7 +720,7 @@ Thanks and have fun!";
var downloadUrl = useTesting ? repoManifest.DownloadLinkTesting : repoManifest.DownloadLinkInstall;
var version = useTesting ? repoManifest.TestingAssemblyVersion : repoManifest.AssemblyVersion;
var response = await Util.HttpClient.GetAsync(downloadUrl);
var response = await this.happyHttpClient.SharedHttpClient.GetAsync(downloadUrl);
response.EnsureSuccessStatusCode();
var outputDir = new DirectoryInfo(Path.Combine(this.pluginDirectory.FullName, repoManifest.InternalName, version?.ToString() ?? string.Empty));
@ -1078,8 +1062,9 @@ Thanks and have fun!";
/// </summary>
/// <param name="ignoreDisabled">Ignore disabled plugins.</param>
/// <param name="dryRun">Perform a dry run, don't install anything.</param>
/// <param name="autoUpdate">If this action was performed as part of an auto-update.</param>
/// <returns>Success or failure and a list of updated plugin metadata.</returns>
public async Task<List<PluginUpdateStatus>> UpdatePluginsAsync(bool ignoreDisabled, bool dryRun)
public async Task<List<PluginUpdateStatus>> UpdatePluginsAsync(bool ignoreDisabled, bool dryRun, bool autoUpdate = false)
{
Log.Information("Starting plugin update");
@ -1104,6 +1089,9 @@ Thanks and have fun!";
}
this.NotifyInstalledPluginsChanged();
this.NotifyPluginsForStateChange(
autoUpdate ? PluginListInvalidationKind.AutoUpdate : PluginListInvalidationKind.Update,
updatedList.Select(x => x.InternalName));
Log.Information("Plugin update OK.");
@ -1394,6 +1382,20 @@ Thanks and have fun!";
this.OnInstalledPluginsChanged?.InvokeSafely();
}
private void NotifyPluginsForStateChange(PluginListInvalidationKind kind, IEnumerable<string> affectedInternalNames)
{
foreach (var installedPlugin in this.InstalledPlugins)
{
if (!installedPlugin.IsLoaded || installedPlugin.DalamudInterface == null)
continue;
installedPlugin.DalamudInterface.NotifyActivePluginsChanged(
kind,
// ReSharper disable once PossibleMultipleEnumeration
affectedInternalNames.Contains(installedPlugin.Manifest.InternalName));
}
}
private static class Locs
{
public static string DalamudPluginUpdateSuccessful(string name, Version version) => Loc.Localize("DalamudPluginUpdateSuccessful", " 》 {0} updated to v{1}.").Format(name, version);

View file

@ -11,6 +11,7 @@ using Dalamud.Game.Gui.Dtr;
using Dalamud.Interface.GameFonts;
using Dalamud.Interface.Internal;
using Dalamud.IoC.Internal;
using Dalamud.Logging;
using Dalamud.Logging.Internal;
using Dalamud.Plugin.Internal.Exceptions;
using Dalamud.Plugin.Internal.Loader;
@ -181,10 +182,15 @@ internal class LocalPlugin : IDisposable
public AssemblyName? AssemblyName { get; private set; }
/// <summary>
/// Gets the plugin name, directly from the plugin or if it is not loaded from the manifest.
/// Gets the plugin name from the manifest.
/// </summary>
public string Name => this.Manifest.Name;
/// <summary>
/// Gets the plugin internal name from the manifest.
/// </summary>
public string InternalName => this.Manifest.InternalName;
/// <summary>
/// Gets an optional reason, if the plugin is banned.
/// </summary>
@ -247,6 +253,11 @@ internal class LocalPlugin : IDisposable
public bool ApplicableForLoad => !this.IsBanned && !this.IsDecommissioned && !this.IsOrphaned && !this.IsOutdated
&& !(!this.IsDev && this.State == PluginState.UnloadError) && this.CheckPolicy();
/// <summary>
/// Gets the service scope for this plugin.
/// </summary>
public IServiceScope? ServiceScope { get; private set; }
/// <inheritdoc/>
public void Dispose()
{
@ -268,6 +279,9 @@ internal class LocalPlugin : IDisposable
this.DalamudInterface?.ExplicitDispose();
this.DalamudInterface = null;
this.ServiceScope?.Dispose();
this.ServiceScope = null;
this.pluginType = null;
this.pluginAssembly = null;
@ -314,8 +328,13 @@ internal class LocalPlugin : IDisposable
case PluginState.Loaded:
throw new InvalidPluginOperationException($"Unable to load {this.Name}, already loaded");
case PluginState.LoadError:
throw new InvalidPluginOperationException(
$"Unable to load {this.Name}, load previously faulted, unload first");
if (!this.IsDev)
{
throw new InvalidPluginOperationException(
$"Unable to load {this.Name}, load previously faulted, unload first");
}
break;
case PluginState.UnloadError:
if (!this.IsDev)
{
@ -423,17 +442,20 @@ internal class LocalPlugin : IDisposable
PluginManager.PluginLocations[this.pluginType.Assembly.FullName] = new PluginPatchData(this.DllFile);
this.DalamudInterface =
new DalamudPluginInterface(this.pluginAssembly.GetName().Name!, this.DllFile, reason, this.IsDev, this.Manifest);
new DalamudPluginInterface(this, reason);
this.ServiceScope = ioc.GetScope();
this.ServiceScope.RegisterPrivateScopes(this); // Add this LocalPlugin as a private scope, so services can get it
if (this.Manifest.LoadSync && this.Manifest.LoadRequiredState is 0 or 1)
{
this.instance = await framework.RunOnFrameworkThread(
() => ioc.CreateAsync(this.pluginType!, this.DalamudInterface!)) as IDalamudPlugin;
() => this.ServiceScope.CreateAsync(this.pluginType!, this.DalamudInterface!)) as IDalamudPlugin;
}
else
{
this.instance =
await ioc.CreateAsync(this.pluginType!, this.DalamudInterface!) as IDalamudPlugin;
await this.ServiceScope.CreateAsync(this.pluginType!, this.DalamudInterface!) as IDalamudPlugin;
}
if (this.instance == null)
@ -458,7 +480,9 @@ internal class LocalPlugin : IDisposable
catch (Exception ex)
{
this.State = PluginState.LoadError;
Log.Error(ex, $"Error while loading {this.Name}");
if (ex is not BannedPluginException)
Log.Error(ex, $"Error while loading {this.Name}");
throw;
}
@ -479,6 +503,7 @@ internal class LocalPlugin : IDisposable
{
var configuration = Service<DalamudConfiguration>.Get();
var framework = Service<Framework>.GetNullable();
var ioc = await Service<ServiceContainer>.GetAsync();
await this.pluginLoadStateLock.WaitAsync();
try
@ -517,6 +542,9 @@ internal class LocalPlugin : IDisposable
this.DalamudInterface?.ExplicitDispose();
this.DalamudInterface = null;
this.ServiceScope?.Dispose();
this.ServiceScope = null;
this.pluginType = null;
this.pluginAssembly = null;

View file

@ -3,11 +3,13 @@ using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Dalamud.Logging.Internal;
using Dalamud.Networking.Http;
using Newtonsoft.Json;
namespace Dalamud.Plugin.Internal.Types;
@ -24,7 +26,11 @@ internal class PluginRepository
private static readonly ModuleLog Log = new("PLUGINR");
private static readonly HttpClient HttpClient = new()
private static readonly HttpClient HttpClient = new(new SocketsHttpHandler
{
AutomaticDecompression = DecompressionMethods.All,
ConnectCallback = Service<HappyHttpClient>.Get().SharedHappyEyeballsCallback.ConnectCallback,
})
{
Timeout = TimeSpan.FromSeconds(20),
DefaultRequestHeaders =