diff --git a/Penumbra/Api/HttpApi.cs b/Penumbra/Api/HttpApi.cs new file mode 100644 index 00000000..ee87d026 --- /dev/null +++ b/Penumbra/Api/HttpApi.cs @@ -0,0 +1,128 @@ +using System; +using System.Threading.Tasks; +using EmbedIO; +using EmbedIO.Routing; +using EmbedIO.WebApi; +using Penumbra.Api.Enums; + +namespace Penumbra.Api; + +public class HttpApi : IDisposable +{ + private partial class Controller : WebApiController + { + // @formatter:off + [Route( HttpVerbs.Get, "/mods" )] public partial object? GetMods(); + [Route( HttpVerbs.Post, "/redraw" )] public partial Task Redraw(); + [Route( HttpVerbs.Post, "/redrawAll" )] public partial void RedrawAll(); + [Route( HttpVerbs.Post, "/reloadmod" )] public partial Task ReloadMod(); + // @formatter:on + } + + public const string Prefix = "http://localhost:42069/"; + + private readonly IPenumbraApi _api; + private WebServer? _server; + + public HttpApi( IPenumbraApi api ) + { + _api = api; + if( Penumbra.Config.EnableHttpApi ) + { + CreateWebServer(); + } + } + + public bool Enabled + => _server != null; + + public void CreateWebServer() + { + ShutdownWebServer(); + + _server = new WebServer( o => o + .WithUrlPrefix( Prefix ) + .WithMode( HttpListenerMode.EmbedIO ) ) + .WithCors( Prefix ) + .WithWebApi( "/api", m => m.WithController( () => new Controller( _api ) ) ); + + _server.StateChanged += ( _, e ) => Penumbra.Log.Information( $"WebServer New State - {e.NewState}" ); + _server.RunAsync(); + } + + public void ShutdownWebServer() + { + _server?.Dispose(); + _server = null; + } + + public void Dispose() + => ShutdownWebServer(); + + private partial class Controller + { + private readonly IPenumbraApi _api; + + public Controller( IPenumbraApi api ) + => _api = api; + + public partial object? GetMods() + { + Penumbra.Log.Debug( $"[HTTP] {nameof( GetMods )} triggered." ); + return _api.GetModList(); + } + + public async partial Task Redraw() + { + var data = await HttpContext.GetRequestDataAsync< RedrawData >(); + Penumbra.Log.Debug( $"[HTTP] {nameof( Redraw )} triggered with {data}." ); + if( data.ObjectTableIndex >= 0 ) + { + _api.RedrawObject( data.ObjectTableIndex, data.Type ); + } + else if( data.Name.Length > 0 ) + { + _api.RedrawObject( data.Name, data.Type ); + } + else + { + _api.RedrawAll( data.Type ); + } + } + + public partial void RedrawAll() + { + Penumbra.Log.Debug( $"[HTTP] {nameof( RedrawAll )} triggered." ); + _api.RedrawAll( RedrawType.Redraw ); + } + + public async partial Task ReloadMod() + { + var data = await HttpContext.GetRequestDataAsync< ModReloadData >(); + Penumbra.Log.Debug( $"[HTTP] {nameof( ReloadMod )} triggered with {data}." ); + // Add the mod if it is not already loaded and if the directory name is given. + // AddMod returns Success if the mod is already loaded. + if( data.Path.Length != 0 ) + { + _api.AddMod( data.Path ); + } + + // Reload the mod by path or name, which will also remove no-longer existing mods. + _api.ReloadMod( data.Path, data.Name ); + } + + private record ModReloadData( string Path, string Name ) + { + public ModReloadData() + : this( string.Empty, string.Empty ) + { } + } + + private record RedrawData( string Name, RedrawType Type, int ObjectTableIndex ) + { + public RedrawData() + : this( string.Empty, RedrawType.Redraw, -1 ) + { } + } + } +} \ No newline at end of file diff --git a/Penumbra/Api/ModsController.cs b/Penumbra/Api/ModsController.cs deleted file mode 100644 index 3432fb86..00000000 --- a/Penumbra/Api/ModsController.cs +++ /dev/null @@ -1,41 +0,0 @@ -using EmbedIO; -using EmbedIO.Routing; -using EmbedIO.WebApi; -using System.Linq; - -namespace Penumbra.Api; - -public class ModsController : WebApiController -{ - private readonly Penumbra _penumbra; - - public ModsController( Penumbra penumbra ) - => _penumbra = penumbra; - - [Route( HttpVerbs.Get, "/mods" )] - public object? GetMods() - { - return Penumbra.ModManager.Zip( Penumbra.CollectionManager.Current.ActualSettings ).Select( x => new - { - x.Second?.Enabled, - x.Second?.Priority, - FolderName = x.First.ModPath.Name, - x.First.Name, - BasePath = x.First.ModPath.FullName, - Files = x.First.AllFiles, - } ); - } - - [Route( HttpVerbs.Post, "/mods" )] - public object CreateMod() - => new { }; - - [Route( HttpVerbs.Get, "/files" )] - public object GetFiles() - { - return Penumbra.CollectionManager.Current.ResolvedFiles.ToDictionary( - o => o.Key.ToString(), - o => o.Value.Path.FullName - ); - } -} \ No newline at end of file diff --git a/Penumbra/Api/RedrawController.cs b/Penumbra/Api/RedrawController.cs deleted file mode 100644 index ad37c587..00000000 --- a/Penumbra/Api/RedrawController.cs +++ /dev/null @@ -1,46 +0,0 @@ -using EmbedIO; -using EmbedIO.Routing; -using EmbedIO.WebApi; -using System.Threading.Tasks; -using Penumbra.Api.Enums; - -namespace Penumbra.Api; - -public class RedrawController : WebApiController -{ - private readonly Penumbra _penumbra; - - public RedrawController( Penumbra penumbra ) - => _penumbra = penumbra; - - [Route( HttpVerbs.Post, "/redraw" )] - public async Task Redraw() - { - var data = await HttpContext.GetRequestDataAsync< RedrawData >(); - if( data.ObjectTableIndex >= 0 ) - { - _penumbra.Api.RedrawObject( data.ObjectTableIndex, data.Type ); - } - else if( data.Name.Length > 0 ) - { - _penumbra.Api.RedrawObject( data.Name, data.Type ); - } - else - { - _penumbra.Api.RedrawAll( data.Type ); - } - } - - [Route( HttpVerbs.Post, "/redrawAll" )] - public void RedrawAll() - { - _penumbra.Api.RedrawAll( RedrawType.Redraw ); - } - - public class RedrawData - { - public string Name { get; set; } = string.Empty; - public RedrawType Type { get; set; } = RedrawType.Redraw; - public int ObjectTableIndex { get; set; } = -1; - } -} \ No newline at end of file diff --git a/Penumbra/Api/ReloadController.cs b/Penumbra/Api/ReloadController.cs deleted file mode 100644 index 0f8fe19e..00000000 --- a/Penumbra/Api/ReloadController.cs +++ /dev/null @@ -1,34 +0,0 @@ -using EmbedIO.Routing; -using EmbedIO; -using EmbedIO.WebApi; -using Penumbra.Api.Enums; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.IO; - -namespace Penumbra.Api { - public class ReloadController : WebApiController { - private readonly Penumbra _penumbra; - public ReloadController( Penumbra penumbra ) - => _penumbra = penumbra; - - [Route( HttpVerbs.Post, "/reload" )] - public async Task Reload() { - var data = await HttpContext.GetRequestDataAsync(); - if( !string.IsNullOrEmpty( data.ModPath ) && !string.IsNullOrEmpty( data.ModName ) ) { - if(Directory.Exists( data.ModPath ) ) { - _penumbra.Api.AddMod( data.ModPath ); - } - _penumbra.Api.ReloadMod( data.ModPath, data.ModName ); - } - } - - public class ReloadData { - public string ModPath { get; set; } = string.Empty; - public string ModName { get; set; } = string.Empty; - } - } -} diff --git a/Penumbra/Penumbra.cs b/Penumbra/Penumbra.cs index ad7c323e..6a3c2ae4 100644 --- a/Penumbra/Penumbra.cs +++ b/Penumbra/Penumbra.cs @@ -6,8 +6,6 @@ using System.Reflection; using System.Text; using Dalamud.Interface.Windowing; using Dalamud.Plugin; -using EmbedIO; -using EmbedIO.WebApi; using ImGuiNET; using Lumina.Excel.GeneratedSheets; using OtterGui; @@ -81,6 +79,7 @@ public class Penumbra : IDalamudPlugin public readonly ObjectReloader ObjectReloader; public readonly ModFileSystem ModFileSystem; public readonly PenumbraApi Api; + public readonly HttpApi HttpApi; public readonly PenumbraIpcProviders IpcProviders; private readonly ConfigWindow _configWindow; private readonly LaunchButton _launchButton; @@ -89,14 +88,6 @@ public class Penumbra : IDalamudPlugin private readonly CommandHandler _commandHandler; private readonly ResourceWatcher _resourceWatcher; - internal WebServer? WebServer; - - private static void Timed( StartTimeType type, Action action ) - { - using var t = StartTimer.Measure( type ); - action(); - } - public Penumbra( DalamudPluginInterface pluginInterface ) { using var time = StartTimer.Measure( StartTimeType.Total ); @@ -158,21 +149,22 @@ public class Penumbra : IDalamudPlugin PathResolver.Enable(); } - if( Config.EnableHttpApi ) - { - CreateWebServer(); - } - if( Config.DebugMode ) { ResourceLoader.EnableDebug(); _configWindow.IsOpen = true; } - using( var tAPI = StartTimer.Measure( StartTimeType.Api ) ) + using( var tApi = StartTimer.Measure( StartTimeType.Api ) ) { Api = new PenumbraApi( this ); IpcProviders = new PenumbraIpcProviders( Dalamud.PluginInterface, Api ); + HttpApi = new HttpApi( Api ); + if( Config.EnableHttpApi ) + { + HttpApi.CreateWebServer(); + } + SubscribeItemLinks(); } @@ -290,38 +282,12 @@ public class Penumbra : IDalamudPlugin }; } - public void CreateWebServer() - { - const string prefix = "http://localhost:42069/"; - - ShutdownWebServer(); - - WebServer = new WebServer( o => o - .WithUrlPrefix( prefix ) - .WithMode( HttpListenerMode.EmbedIO ) ) - .WithCors( prefix ) - .WithWebApi( "/api", m => m - .WithController( () => new ModsController( this ) ) - .WithController( () => new RedrawController( this ) ) - .WithController( () => new ReloadController( this ) ) ); - - WebServer.StateChanged += ( _, e ) => Log.Information( $"WebServer New State - {e.NewState}" ); - - WebServer.RunAsync(); - } - - public void ShutdownWebServer() - { - WebServer?.Dispose(); - WebServer = null; - } - private short ResolveCutscene( ushort index ) => ( short )PathResolver.CutsceneActor( index ); public void Dispose() { - ShutdownWebServer(); + HttpApi?.Dispose(); IpcProviders?.Dispose(); Api?.Dispose(); _commandHandler?.Dispose(); diff --git a/Penumbra/UI/ConfigWindow.DebugTab.cs b/Penumbra/UI/ConfigWindow.DebugTab.cs index bc8499e1..39df2f3e 100644 --- a/Penumbra/UI/ConfigWindow.DebugTab.cs +++ b/Penumbra/UI/ConfigWindow.DebugTab.cs @@ -109,7 +109,7 @@ public partial class ConfigWindow PrintValue( "Mod Manager BasePath Exists", Directory.Exists( manager.BasePath.FullName ).ToString() ); PrintValue( "Mod Manager Valid", manager.Valid.ToString() ); PrintValue( "Path Resolver Enabled", _window._penumbra.PathResolver.Enabled.ToString() ); - PrintValue( "Web Server Enabled", ( _window._penumbra.WebServer != null ).ToString() ); + PrintValue( "Web Server Enabled", _window._penumbra.HttpApi.Enabled.ToString() ); } private static void DrawPerformanceTab() diff --git a/Penumbra/UI/ConfigWindow.SettingsTab.Advanced.cs b/Penumbra/UI/ConfigWindow.SettingsTab.Advanced.cs index 810140a5..f05c52cb 100644 --- a/Penumbra/UI/ConfigWindow.SettingsTab.Advanced.cs +++ b/Penumbra/UI/ConfigWindow.SettingsTab.Advanced.cs @@ -1,11 +1,8 @@ using System.Numerics; -using Dalamud.Interface; using ImGuiNET; using OtterGui; using OtterGui.Raii; using Penumbra.Interop; -using Penumbra.String.Classes; -using Penumbra.UI.Classes; namespace Penumbra.UI; @@ -46,11 +43,11 @@ public partial class ConfigWindow { if( http ) { - _window._penumbra.CreateWebServer(); + _window._penumbra.HttpApi.CreateWebServer(); } else { - _window._penumbra.ShutdownWebServer(); + _window._penumbra.HttpApi.ShutdownWebServer(); } Penumbra.Config.EnableHttpApi = http;