using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Dalamud.Logging.Internal;
using Dalamud.Plugin.Internal.Types;
using Newtonsoft.Json;
namespace Dalamud.Plugin.Internal
{
///
/// This class represents a single plugin repository.
///
internal class PluginRepository
{
private const string DalamudPluginsMasterUrl = "https://kamori.goats.dev/Plugin/PluginMaster";
private static readonly ModuleLog Log = new("PLUGINR");
private static readonly HttpClient HttpClient = new()
{
DefaultRequestHeaders =
{
CacheControl = new CacheControlHeaderValue
{
NoCache = true,
},
},
};
///
/// Initializes a new instance of the class.
///
/// The plugin master URL.
/// Whether the plugin repo is enabled.
public PluginRepository(string pluginMasterUrl, bool isEnabled)
{
this.PluginMasterUrl = pluginMasterUrl;
this.IsThirdParty = pluginMasterUrl != DalamudPluginsMasterUrl;
this.IsEnabled = isEnabled;
}
///
/// Gets a new instance of the class for the main repo.
///
public static PluginRepository MainRepo => new(DalamudPluginsMasterUrl, true);
///
/// Gets the pluginmaster.json URL.
///
public string PluginMasterUrl { get; }
///
/// Gets a value indicating whether this plugin repository is from a third party.
///
public bool IsThirdParty { get; }
///
/// Gets a value indicating whether this repo is enabled.
///
public bool IsEnabled { get; }
///
/// Gets the plugin master list of available plugins.
///
public ReadOnlyCollection? PluginMaster { get; private set; }
///
/// Gets the initialization state of the plugin repository.
///
public PluginRepositoryState State { get; private set; }
///
/// Reload the plugin master asynchronously in a task.
///
/// The new state.
public async Task ReloadPluginMasterAsync()
{
this.State = PluginRepositoryState.InProgress;
this.PluginMaster = new List().AsReadOnly();
try
{
Log.Information($"Fetching repo: {this.PluginMasterUrl}");
using var response = await HttpClient.GetAsync(this.PluginMasterUrl);
response.EnsureSuccessStatusCode();
var data = await response.Content.ReadAsStringAsync();
var pluginMaster = JsonConvert.DeserializeObject>(data);
if (pluginMaster == null)
{
throw new Exception("Deserialized PluginMaster was null.");
}
pluginMaster.Sort((pm1, pm2) => pm1.Name.CompareTo(pm2.Name));
// Set the source for each remote manifest. Allows for checking if is 3rd party.
foreach (var manifest in pluginMaster)
{
manifest.SourceRepo = this;
}
this.PluginMaster = pluginMaster.AsReadOnly();
Log.Debug($"Successfully fetched repo: {this.PluginMasterUrl}");
this.State = PluginRepositoryState.Success;
}
catch (Exception ex)
{
Log.Error(ex, $"PluginMaster failed: {this.PluginMasterUrl}");
this.State = PluginRepositoryState.Fail;
}
}
}
}