add some UI stuff

This commit is contained in:
Stanley Dimant
2022-06-16 18:55:19 +02:00
parent 4f72daa0eb
commit f643b413f2
8 changed files with 311 additions and 150 deletions

View File

@@ -1,6 +1,7 @@
using Dalamud.Configuration; using Dalamud.Configuration;
using Dalamud.Plugin; using Dalamud.Plugin;
using System; using System;
using System.Collections.Generic;
namespace MareSynchronos namespace MareSynchronos
{ {
@@ -10,8 +11,9 @@ namespace MareSynchronos
public int Version { get; set; } = 0; public int Version { get; set; } = 0;
public string CacheFolder { get; set; } = string.Empty; public string CacheFolder { get; set; } = string.Empty;
public string ClientSecret { get; internal set; } = string.Empty; public Dictionary<string, string> ClientSecret { get; internal set; } = new();
public string ApiUri { get; internal set; } = string.Empty; public string ApiUri { get; internal set; } = string.Empty;
public bool UseCustomService { get; internal set; }
// the below exist just to make saving less cumbersome // the below exist just to make saving less cumbersome

View File

@@ -19,10 +19,15 @@ namespace MareSynchronos.Factories
public FileReplacement Create(string gamePath, bool resolve = true) public FileReplacement Create(string gamePath, bool resolve = true)
{ {
if (!ipcManager.CheckPenumbraAPI())
{
throw new System.Exception();
}
var fileReplacement = new FileReplacement(gamePath, ipcManager.PenumbraModDirectory()!); var fileReplacement = new FileReplacement(gamePath, ipcManager.PenumbraModDirectory()!);
if (!resolve) return fileReplacement; if (!resolve) return fileReplacement;
if(clientState.LocalPlayer != null) if (clientState.LocalPlayer != null)
{ {
playerName = clientState.LocalPlayer.Name.ToString(); playerName = clientState.LocalPlayer.Name.ToString();
} }

View File

@@ -12,6 +12,7 @@ using FFXIVClientStructs.FFXIV.Client.System.Resource;
using FFXIVClientStructs.FFXIV.Client.UI; using FFXIVClientStructs.FFXIV.Client.UI;
using FFXIVClientStructs.FFXIV.Component.GUI; using FFXIVClientStructs.FFXIV.Component.GUI;
using MareSynchronos.Factories; using MareSynchronos.Factories;
using MareSynchronos.Managers;
using MareSynchronos.Models; using MareSynchronos.Models;
using Penumbra.GameData.ByteString; using Penumbra.GameData.ByteString;
using Penumbra.Interop.Structs; using Penumbra.Interop.Structs;
@@ -20,6 +21,8 @@ using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
namespace MareSynchronos.Hooks namespace MareSynchronos.Hooks
{ {
@@ -136,7 +139,8 @@ namespace MareSynchronos.Hooks
} }
} }
} }
} catch (Exception ex) }
catch (Exception ex)
{ {
PluginLog.Error(ex, ex.Message); PluginLog.Error(ex, ex.Message);
} }

View File

@@ -112,7 +112,13 @@ namespace MareSynchronos.Managers
// wait one more second just in case // wait one more second just in case
Thread.Sleep(1000); Thread.Sleep(1000);
apiController.SendCharacterData(drawHooks.BuildCharacterCache()).RunSynchronously(); var cache = CreateFullCharacterCache();
while (!cache.IsCompleted)
{
Task.Delay(50);
}
_ = apiController.SendCharacterData(cache.Result);
}); });
} }
@@ -120,12 +126,12 @@ namespace MareSynchronos.Managers
public void PrintRequestedResources() => drawHooks.PrintRequestedResources(); public void PrintRequestedResources() => drawHooks.PrintRequestedResources();
public void DebugJson() private async Task<CharacterCache> CreateFullCharacterCache()
{ {
var cache = drawHooks.BuildCharacterCache(); var cache = drawHooks.BuildCharacterCache();
cache.SetGlamourerData(ipcManager.GlamourerGetCharacterCustomization()!); cache.SetGlamourerData(ipcManager.GlamourerGetCharacterCustomization()!);
cache.JobId = clientState.LocalPlayer!.ClassJob.Id; cache.JobId = clientState.LocalPlayer!.ClassJob.Id;
Task.Run(async () => await Task.Run(async () =>
{ {
while (!cache.IsReady) while (!cache.IsReady)
{ {
@@ -134,10 +140,20 @@ namespace MareSynchronos.Managers
var json = JsonConvert.SerializeObject(cache, Formatting.Indented); var json = JsonConvert.SerializeObject(cache, Formatting.Indented);
cache.CacheHash = Crypto.GetHash(json); cache.CacheHash = Crypto.GetHash(json);
json = JsonConvert.SerializeObject(cache, Formatting.Indented);
PluginLog.Debug(json);
}); });
return cache;
}
public void DebugJson()
{
var cache = CreateFullCharacterCache();
while (!cache.IsCompleted)
{
Task.Delay(50);
}
PluginLog.Debug(JsonConvert.SerializeObject(cache.Result, Formatting.Indented));
} }
} }
} }

View File

@@ -9,65 +9,55 @@ namespace MareSynchronos.Managers
{ {
private readonly DalamudPluginInterface pluginInterface; private readonly DalamudPluginInterface pluginInterface;
private ICallGateSubscriber<object> penumbraInit; private ICallGateSubscriber<object> penumbraInit;
private readonly ICallGateSubscriber<object> penumbraDispose;
private ICallGateSubscriber<string, string, string>? penumbraResolvePath; private ICallGateSubscriber<string, string, string>? penumbraResolvePath;
private ICallGateSubscriber<string>? penumbraResolveModDir; private ICallGateSubscriber<string>? penumbraResolveModDir;
private ICallGateSubscriber<string>? glamourerGetCharacterCustomization; private ICallGateSubscriber<string>? glamourerGetCharacterCustomization;
private ICallGateSubscriber<string, string, object>? glamourerApplyCharacterCustomization; private ICallGateSubscriber<string, string, object>? glamourerApplyCharacterCustomization;
private ICallGateSubscriber<int> penumbraApiVersion;
private ICallGateSubscriber<int> glamourerApiVersion;
private ICallGateSubscriber<string, int, object>? penumbraRedraw; private ICallGateSubscriber<string, int, object>? penumbraRedraw;
public bool Initialized { get; private set; } = false; public bool Initialized { get; private set; } = false;
public event EventHandler? IpcManagerInitialized;
public IpcManager(DalamudPluginInterface pi) public IpcManager(DalamudPluginInterface pi)
{ {
pluginInterface = pi; pluginInterface = pi;
penumbraInit = pluginInterface.GetIpcSubscriber<object>("Penumbra.Initialized"); penumbraInit = pluginInterface.GetIpcSubscriber<object>("Penumbra.Initialized");
penumbraInit.Subscribe(Initialize);
penumbraDispose = pluginInterface.GetIpcSubscriber<object>("Penumbra.Disposed");
penumbraDispose.Subscribe(Uninitialize);
}
private bool CheckPenumbraAPI()
{
try
{
var penumbraApiVersion = pluginInterface.GetIpcSubscriber<int>("Penumbra.ApiVersion").InvokeFunc();
return penumbraApiVersion >= 4;
}
catch
{
return false;
}
}
private bool CheckGlamourerAPI()
{
try
{
var glamourerApiVersion = pluginInterface.GetIpcSubscriber<int>("Glamourer.ApiVersion").InvokeFunc();
return glamourerApiVersion >= 0;
}
catch
{
return false;
}
}
public void Initialize()
{
if (Initialized) return;
if (!CheckPenumbraAPI()) throw new Exception("Penumbra API is outdated or not available");
if (!CheckGlamourerAPI()) throw new Exception("Glamourer API is oudated or not available");
penumbraResolvePath = pluginInterface.GetIpcSubscriber<string, string, string>("Penumbra.ResolveCharacterPath"); penumbraResolvePath = pluginInterface.GetIpcSubscriber<string, string, string>("Penumbra.ResolveCharacterPath");
penumbraResolveModDir = pluginInterface.GetIpcSubscriber<string>("Penumbra.GetModDirectory"); penumbraResolveModDir = pluginInterface.GetIpcSubscriber<string>("Penumbra.GetModDirectory");
penumbraRedraw = pluginInterface.GetIpcSubscriber<string, int, object>("Penumbra.RedrawObjectByName"); penumbraRedraw = pluginInterface.GetIpcSubscriber<string, int, object>("Penumbra.RedrawObjectByName");
glamourerGetCharacterCustomization = pluginInterface.GetIpcSubscriber<string>("Glamourer.GetCharacterCustomization"); glamourerGetCharacterCustomization = pluginInterface.GetIpcSubscriber<string>("Glamourer.GetCharacterCustomization");
glamourerApplyCharacterCustomization = pluginInterface.GetIpcSubscriber<string, string, object>("Glamourer.ApplyCharacterCustomization"); glamourerApplyCharacterCustomization = pluginInterface.GetIpcSubscriber<string, string, object>("Glamourer.ApplyCharacterCustomization");
penumbraApiVersion = pluginInterface.GetIpcSubscriber<int>("Penumbra.ApiVersion");
glamourerApiVersion = pluginInterface.GetIpcSubscriber<int>("Glamourer.ApiVersion");
penumbraInit.Subscribe(() => penumbraRedraw!.InvokeAction("self", 0));
Initialized = true; Initialized = true;
IpcManagerInitialized?.Invoke(this, new EventArgs()); }
PluginLog.Debug("[IPC Manager] initialized");
public bool CheckPenumbraAPI()
{
try
{
return penumbraApiVersion.InvokeFunc() >= 4;
}
catch
{
return false;
}
}
public bool CheckGlamourerAPI()
{
try
{
return glamourerApiVersion.InvokeFunc() >= 0;
}
catch
{
return false;
}
} }
private void Uninitialize() private void Uninitialize()
@@ -82,38 +72,37 @@ namespace MareSynchronos.Managers
public string? PenumbraResolvePath(string path, string characterName) public string? PenumbraResolvePath(string path, string characterName)
{ {
if (!Initialized) return null; if (!CheckPenumbraAPI()) return null;
return penumbraResolvePath!.InvokeFunc(path, characterName); return penumbraResolvePath!.InvokeFunc(path, characterName);
} }
public string? PenumbraModDirectory() public string? PenumbraModDirectory()
{ {
if (!Initialized) return null; if (!CheckPenumbraAPI()) return null;
return penumbraResolveModDir!.InvokeFunc(); return penumbraResolveModDir!.InvokeFunc();
} }
public string? GlamourerGetCharacterCustomization() public string? GlamourerGetCharacterCustomization()
{ {
if (!Initialized) return null; if (!CheckGlamourerAPI()) return null;
return glamourerGetCharacterCustomization!.InvokeFunc(); return glamourerGetCharacterCustomization!.InvokeFunc();
} }
public void GlamourerApplyCharacterCustomization(string customization, string characterName) public void GlamourerApplyCharacterCustomization(string customization, string characterName)
{ {
if (!Initialized) return; if (!CheckGlamourerAPI()) return;
glamourerApplyCharacterCustomization!.InvokeAction(customization, characterName); glamourerApplyCharacterCustomization!.InvokeAction(customization, characterName);
} }
public void PenumbraRedraw(string actorName) public void PenumbraRedraw(string actorName)
{ {
if (!Initialized) return; if (!CheckPenumbraAPI()) return;
penumbraRedraw!.InvokeAction(actorName, 0); penumbraRedraw!.InvokeAction(actorName, 0);
} }
public void Dispose() public void Dispose()
{ {
Uninitialize(); Uninitialize();
IpcManagerInitialized = null;
} }
} }
} }

View File

@@ -20,6 +20,7 @@ using Newtonsoft.Json;
using MareSynchronos.Managers; using MareSynchronos.Managers;
using LZ4; using LZ4;
using MareSynchronos.WebAPI; using MareSynchronos.WebAPI;
using Dalamud.Interface.Windowing;
namespace MareSynchronos namespace MareSynchronos
{ {
@@ -30,9 +31,10 @@ namespace MareSynchronos
private readonly Framework framework; private readonly Framework framework;
private readonly GameGui gameGui; private readonly GameGui gameGui;
private readonly ObjectTable objectTable; private readonly ObjectTable objectTable;
private readonly WindowSystem windowSystem;
private readonly ApiController apiController; private readonly ApiController apiController;
private CharacterManager? characterManager; private CharacterManager? characterManager;
private IpcManager? ipcManager; private IpcManager ipcManager;
public Plugin(DalamudPluginInterface pluginInterface, CommandManager commandManager, public Plugin(DalamudPluginInterface pluginInterface, CommandManager commandManager,
Framework framework, ObjectTable objectTable, ClientState clientState, GameGui gameGui) Framework framework, ObjectTable objectTable, ClientState clientState, GameGui gameGui)
{ {
@@ -45,10 +47,13 @@ namespace MareSynchronos
Configuration = this.PluginInterface.GetPluginConfig() as Configuration ?? new Configuration(); Configuration = this.PluginInterface.GetPluginConfig() as Configuration ?? new Configuration();
Configuration.Initialize(this.PluginInterface); Configuration.Initialize(this.PluginInterface);
windowSystem = new WindowSystem("MareSynchronos");
apiController = new ApiController(Configuration); apiController = new ApiController(Configuration);
ipcManager = new IpcManager(PluginInterface);
// you might normally want to embed resources and load them from the manifest stream // you might normally want to embed resources and load them from the manifest stream
this.PluginUi = new PluginUI(this.Configuration); this.PluginUi = new PluginUI(this.Configuration, windowSystem, apiController, ipcManager);
new FileCacheContext().Dispose(); // make sure db is initialized I guess new FileCacheContext().Dispose(); // make sure db is initialized I guess
@@ -59,9 +64,6 @@ namespace MareSynchronos
{ {
ClientState_Login(null, null!); ClientState_Login(null, null!);
} }
this.PluginInterface.UiBuilder.Draw += DrawUI;
this.PluginInterface.UiBuilder.OpenConfigUi += DrawConfigUI;
} }
public string Name => "Mare Synchronos"; public string Name => "Mare Synchronos";
@@ -77,14 +79,28 @@ namespace MareSynchronos
clientState.Logout -= ClientState_Logout; clientState.Logout -= ClientState_Logout;
ipcManager?.Dispose(); ipcManager?.Dispose();
characterManager?.Dispose(); characterManager?.Dispose();
apiController?.Dispose();
} }
private void ClientState_Login(object? sender, EventArgs e) private void ClientState_Login(object? sender, EventArgs e)
{ {
PluginLog.Debug("Client login"); PluginLog.Debug("Client login");
ipcManager = new IpcManager(PluginInterface);
ipcManager.IpcManagerInitialized += IpcManager_IpcManagerInitialized; Task.Run(async () =>
ipcManager.Initialize(); {
while (clientState.LocalPlayer == null)
{
await Task.Delay(50);
}
characterManager = new CharacterManager(
new DrawHooks(PluginInterface, clientState, objectTable, new FileReplacementFactory(ipcManager, clientState), gameGui),
clientState, framework, apiController, objectTable, ipcManager);
ipcManager.PenumbraRedraw(clientState.LocalPlayer!.Name.ToString());
});
PluginInterface.UiBuilder.Draw += Draw;
PluginInterface.UiBuilder.OpenConfigUi += OpenConfigUI;
CommandManager.AddHandler(commandName, new CommandInfo(OnCommand) CommandManager.AddHandler(commandName, new CommandInfo(OnCommand)
{ {
@@ -96,8 +112,8 @@ namespace MareSynchronos
{ {
PluginLog.Debug("Client logout"); PluginLog.Debug("Client logout");
characterManager?.Dispose(); characterManager?.Dispose();
ipcManager?.Dispose(); PluginInterface.UiBuilder.Draw -= Draw;
ipcManager = null!; PluginInterface.UiBuilder.OpenConfigUi -= OpenConfigUI;
CommandManager.RemoveHandler(commandName); CommandManager.RemoveHandler(commandName);
} }
@@ -139,32 +155,14 @@ namespace MareSynchronos
} }
} }
private void DrawConfigUI() private void Draw()
{ {
this.PluginUi.SettingsVisible = true; windowSystem.Draw();
} }
private void DrawUI() private void OpenConfigUI()
{ {
this.PluginUi.Draw(); this.PluginUi.Toggle();
}
private void IpcManager_IpcManagerInitialized(object? sender, EventArgs e)
{
PluginLog.Debug("IPC Manager initialized event");
ipcManager!.IpcManagerInitialized -= IpcManager_IpcManagerInitialized;
Task.Run(async () =>
{
while (clientState.LocalPlayer == null)
{
await Task.Delay(500);
}
characterManager = new CharacterManager(
new DrawHooks(PluginInterface, clientState, objectTable, new FileReplacementFactory(ipcManager, clientState), gameGui),
clientState, framework, apiController, objectTable, ipcManager);
ipcManager.PenumbraRedraw(clientState.LocalPlayer!.Name.ToString());
});
} }
private void OnCommand(string command, string args) private void OnCommand(string command, string args)

View File

@@ -1,4 +1,10 @@
using ImGuiNET; using Dalamud.Interface;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Windowing;
using Dalamud.Logging;
using ImGuiNET;
using MareSynchronos.Managers;
using MareSynchronos.WebAPI;
using System; using System;
using System.Numerics; using System.Numerics;
@@ -6,88 +12,182 @@ namespace MareSynchronos
{ {
// It is good to have this be disposable in general, in case you ever need it // It is good to have this be disposable in general, in case you ever need it
// to do any cleanup // to do any cleanup
class PluginUI : IDisposable class PluginUI : Window, IDisposable
{ {
private Configuration configuration; private Configuration configuration;
private readonly WindowSystem windowSystem;
// this extra bool exists for ImGui, since you can't ref a property private readonly ApiController apiController;
private bool visible = false; private readonly IpcManager ipcManager;
public bool Visible private string? uid;
{ private const string mainServer = "Lunae Crescere Incipientis (Central Server EU)";
get { return this.visible; }
set { this.visible = value; }
}
private bool settingsVisible = false;
public bool SettingsVisible
{
get { return this.settingsVisible; }
set { this.settingsVisible = value; }
}
// passing in the image here just for simplicity // passing in the image here just for simplicity
public PluginUI(Configuration configuration) public PluginUI(Configuration configuration, WindowSystem windowSystem, ApiController apiController, IpcManager ipcManager) : base("Mare Synchronos Settings", ImGuiWindowFlags.None)
{ {
SizeConstraints = new WindowSizeConstraints()
{
MinimumSize = new(700, 400),
MaximumSize = new(700, 2000)
};
this.configuration = configuration; this.configuration = configuration;
this.windowSystem = windowSystem;
this.apiController = apiController;
this.ipcManager = ipcManager;
windowSystem.AddWindow(this);
} }
public void Dispose() public void Dispose()
{ {
windowSystem.RemoveWindow(this);
} }
public void Draw() public override void Draw()
{ {
// This is our only draw handler attached to UIBuilder, so it needs to be if (!IsOpen)
// able to draw any windows we might have open.
// Each method checks its own visibility/state to ensure it only draws when
// it actually makes sense.
// There are other ways to do this, but it is generally best to keep the number of
// draw delegates as low as possible.
DrawMainWindow();
DrawSettingsWindow();
}
public void DrawMainWindow()
{
if (!Visible)
{ {
return; return;
} }
ImGui.SetNextWindowSize(new Vector2(375, 330), ImGuiCond.FirstUseEver); if (string.IsNullOrEmpty(apiController.SecretKey))
ImGui.SetNextWindowSizeConstraints(new Vector2(375, 330), new Vector2(float.MaxValue, float.MaxValue));
if (ImGui.Begin("My Amazing Window", ref this.visible, ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse))
{ {
if (ImGui.Button("Show Settings")) DrawIntroContent();
}
else
{ {
SettingsVisible = true; if (!OtherPluginStateOk()) return;
DrawSettingsContent();
}
} }
ImGui.Spacing(); private void DrawSettingsContent()
{
PrintServerState();
ImGui.Separator();
ImGui.Text("Your UID");
ImGui.SameLine();
ImGui.TextColored(ImGuiColors.ParsedGreen, apiController.UID);
ImGui.SameLine();
if (ImGui.Button("Copy UID"))
{
ImGui.SetClipboardText(apiController.UID);
} }
ImGui.End(); ImGui.Text("Share this UID to other Mare users so they can add you to their whitelist.");
} }
public void DrawSettingsWindow() private int serverSelectionIndex = 0;
private async void DrawIntroContent()
{ {
if (!SettingsVisible) ImGui.SetWindowFontScale(1.3f);
ImGui.Text("Welcome to Mare Synchronos!");
ImGui.SetWindowFontScale(1.0f);
ImGui.Separator();
ImGui.TextWrapped("Mare Synchronos is a plugin that will replicate your full current character state including all Penumbra mods to other whitelisted Mare Synchronos users. " +
"Note that you will have to have Penumbra as well as Glamourer installed to use this plugin.");
if (!OtherPluginStateOk()) return;
ImGui.SetWindowFontScale(1.5f);
string readThis = "READ THIS CAREFULLY BEFORE REGISTERING";
var textSize = ImGui.CalcTextSize(readThis);
ImGui.SetCursorPosX(ImGui.GetWindowSize().X / 2 - textSize.X / 2);
ImGui.TextColored(ImGuiColors.DalamudRed, readThis);
ImGui.SetWindowFontScale(1.0f);
ImGui.TextWrapped("All of the mod files currently active on your character as well as your current character state will be uploaded to the service you registered yourself at automatically. " +
"The plugin will exclusively upload the necessary mod files and not the whole mod.");
ImGui.TextWrapped("If you are on a data capped internet connection, higher fees due to data usage depending on the amount of downloaded and uploaded mod files might occur. " +
"Mod files will be compressed on up- and download to save on bandwidth usage. Due to varying up- and download speeds, changes in characters might not be visible immediately. " +
"Files present on the service that already represent your active mod files will not be uploaded again. To register at a service you will need to hold ctrl.");
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudRed);
ImGui.TextWrapped("The mod files you are uploading are confidential and will not be distributed to parties other than the ones who are requesting the exact same mod files. " +
"Please think about who you are going to whitelist since it is unavoidable that they will receive and locally cache the necessary mod files that you have currently in use. " +
"Locally cached mod files will have arbitrary file names to discourage attempts at replicating the original mod in question.");
ImGui.PopStyleColor();
ImGui.TextWrapped("Mod files that are saved on the service will remain on the service as long as there are requests for the files from clients. After a period of not being used, the mod files will be automatically deleted. " +
"You will also be able to wipe all the files you have personally uploaded on request.");
ImGui.TextColored(ImGuiColors.DalamudRed, "This service is provided as-is.");
ImGui.Separator();
string[] comboEntries = new[] { mainServer, "Custom Service" };
if (ImGui.BeginCombo("Service", comboEntries[serverSelectionIndex]))
{ {
return; for (int n = 0; n < comboEntries.Length; n++)
{
bool isSelected = serverSelectionIndex == n;
if (ImGui.Selectable(comboEntries[n], isSelected))
{
serverSelectionIndex = n;
} }
ImGui.SetNextWindowSize(new Vector2(500, 75), ImGuiCond.Always); if (isSelected)
if (ImGui.Begin("QUALITY UI DEVELOPMENT", ref this.settingsVisible,
ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse))
{ {
// can't ref a property, so use a local copy ImGui.SetItemDefaultFocus();
string penumbraFolder = configuration.CacheFolder; }
if(ImGui.InputText("Penumbra mod folder", ref penumbraFolder, 255)) {
this.configuration.CacheFolder = penumbraFolder; bool useCustomService = (serverSelectionIndex != 0);
this.configuration.Save();
if (apiController.UseCustomService != useCustomService)
{
PluginLog.Debug("Configuration " + apiController.UseCustomService + " changing to " + useCustomService);
apiController.UseCustomService = useCustomService;
configuration.Save();
} }
} }
ImGui.End();
ImGui.EndCombo();
}
if (apiController.UseCustomService)
{
string serviceAddress = configuration.ApiUri;
ImGui.InputText("Service address", ref serviceAddress, 255);
configuration.ApiUri = serviceAddress;
configuration.Save();
}
PrintServerState();
if (apiController.IsConnected)
{
if (ImGui.Button("Register"))
{
if (ImGui.GetIO().KeyCtrl)
{
await apiController.Register();
}
}
}
}
private bool OtherPluginStateOk()
{
var penumbraExists = ipcManager.CheckPenumbraAPI();
var glamourerExists = ipcManager.CheckGlamourerAPI();
var penumbraColor = penumbraExists ? ImGuiColors.ParsedGreen : ImGuiColors.DalamudRed;
var glamourerColor = glamourerExists ? ImGuiColors.ParsedGreen : ImGuiColors.DalamudRed;
ImGui.Text("Penumbra:");
ImGui.SameLine();
ImGui.TextColored(penumbraColor, penumbraExists ? "Available" : "Unavailable");
ImGui.Text("Glamourer:");
ImGui.SameLine();
ImGui.TextColored(glamourerColor, glamourerExists ? "Available" : "Unavailable");
if (!penumbraExists || !glamourerExists)
{
ImGui.TextColored(ImGuiColors.DalamudRed, "You need to install both Penumbra and Glamourer and keep them up to date to use Mare Synchronos.");
return false;
}
return true;
}
private void PrintServerState()
{
ImGui.Text("Service status of " + (string.IsNullOrEmpty(configuration.ApiUri) ? mainServer : configuration.ApiUri));
ImGui.SameLine();
var color = apiController.IsConnected ? ImGuiColors.ParsedGreen : ImGuiColors.DalamudRed;
ImGui.TextColored(color, apiController.IsConnected ? "Available" : "Unavailable");
} }
} }
} }

View File

@@ -5,32 +5,74 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace MareSynchronos.WebAPI namespace MareSynchronos.WebAPI
{ {
public class ApiController public class ApiController : IDisposable
{ {
private readonly Configuration pluginConfiguration; private readonly Configuration pluginConfiguration;
private const string mainService = "https://localhost:6591";
private string SecretKey => pluginConfiguration.ClientSecret; public string UID { get; private set; } = string.Empty;
public string SecretKey => pluginConfiguration.ClientSecret.ContainsKey(ApiUri) ? pluginConfiguration.ClientSecret[ApiUri] : string.Empty;
private string CacheFolder => pluginConfiguration.CacheFolder; private string CacheFolder => pluginConfiguration.CacheFolder;
private string ApiUri => pluginConfiguration.ApiUri; public bool UseCustomService
{
get => pluginConfiguration.UseCustomService;
set
{
pluginConfiguration.UseCustomService = value;
_ = Heartbeat();
pluginConfiguration.Save();
}
}
private string ApiUri => UseCustomService ? pluginConfiguration.ApiUri : mainService;
public bool IsConnected { get; set; }
Task heartbeatTask;
CancellationTokenSource cts;
public ApiController(Configuration pluginConfiguration) public ApiController(Configuration pluginConfiguration)
{ {
this.pluginConfiguration = pluginConfiguration; this.pluginConfiguration = pluginConfiguration;
cts = new CancellationTokenSource();
heartbeatTask = Task.Run(async () =>
{
PluginLog.Debug("Starting heartbeat to " + ApiUri);
while (true && !cts.IsCancellationRequested)
{
await Heartbeat();
await Task.Delay(TimeSpan.FromSeconds(15), cts.Token);
}
PluginLog.Debug("Stopping heartbeat");
}, cts.Token);
} }
public async Task Heartbeat() public async Task Heartbeat()
{
try
{ {
PluginLog.Debug("Sending heartbeat to " + ApiUri); PluginLog.Debug("Sending heartbeat to " + ApiUri);
if (ApiUri != mainService) throw new Exception();
IsConnected = true;
}
catch
{
IsConnected = false;
}
} }
public async Task<(string, string)> Register() public async Task Register()
{ {
PluginLog.Debug("Registering at service " + ApiUri); PluginLog.Debug("Registering at service " + ApiUri);
return (string.Empty, string.Empty); var response = ("RandomSecretKey", "RandomUID");
pluginConfiguration.ClientSecret[ApiUri] = response.Item1;
UID = response.Item2;
PluginLog.Debug(pluginConfiguration.ClientSecret[ApiUri]);
// pluginConfiguration.Save();
} }
public async Task UploadFile(string filePath) public async Task UploadFile(string filePath)
@@ -73,5 +115,10 @@ namespace MareSynchronos.WebAPI
List<string> whitelist = new(); List<string> whitelist = new();
return whitelist; return whitelist;
} }
public void Dispose()
{
cts?.Cancel();
}
} }
} }