diff --git a/CaddyManager/CaddyManager.csproj b/CaddyManager/CaddyManager.csproj index ef18c55..c0b4ef4 100644 --- a/CaddyManager/CaddyManager.csproj +++ b/CaddyManager/CaddyManager.csproj @@ -6,6 +6,7 @@ enable Linux 13 + ebolo/caddy-manager @@ -22,7 +23,14 @@ - + + + + + + + <_ContentIncludedByDefault Remove="Components\Pages\ReverseProxies\ReverseProxiesPage.razor" /> + <_ContentIncludedByDefault Remove="Components\Pages\ReverseProxies\ReverseProxyItem.razor" /> diff --git a/CaddyManager/Components/Layout/MainLayout.razor b/CaddyManager/Components/Layout/MainLayout.razor index 309b7ea..20c3b35 100644 --- a/CaddyManager/Components/Layout/MainLayout.razor +++ b/CaddyManager/Components/Layout/MainLayout.razor @@ -15,7 +15,7 @@ Caddy Manager - + diff --git a/CaddyManager/Components/Layout/NavigationDrawer.razor b/CaddyManager/Components/Layout/NavigationDrawer.razor index 2f9daf2..8f2a585 100644 --- a/CaddyManager/Components/Layout/NavigationDrawer.razor +++ b/CaddyManager/Components/Layout/NavigationDrawer.razor @@ -8,7 +8,5 @@ Global Caddyfile - Settings - \ No newline at end of file diff --git a/CaddyManager/Components/Pages/CaddyfileEditor/CaddyfileEditor.razor b/CaddyManager/Components/Pages/Caddy/CaddyfileEditor/CaddyfileEditor.razor similarity index 100% rename from CaddyManager/Components/Pages/CaddyfileEditor/CaddyfileEditor.razor rename to CaddyManager/Components/Pages/Caddy/CaddyfileEditor/CaddyfileEditor.razor diff --git a/CaddyManager/Components/Pages/CaddyfileEditor/CaddyfileEditor.razor.cs b/CaddyManager/Components/Pages/Caddy/CaddyfileEditor/CaddyfileEditor.razor.cs similarity index 97% rename from CaddyManager/Components/Pages/CaddyfileEditor/CaddyfileEditor.razor.cs rename to CaddyManager/Components/Pages/Caddy/CaddyfileEditor/CaddyfileEditor.razor.cs index 30fb3a5..8b465ad 100644 --- a/CaddyManager/Components/Pages/CaddyfileEditor/CaddyfileEditor.razor.cs +++ b/CaddyManager/Components/Pages/Caddy/CaddyfileEditor/CaddyfileEditor.razor.cs @@ -4,7 +4,7 @@ using CaddyManager.Models.Caddy; using Microsoft.AspNetCore.Components; using MudBlazor; -namespace CaddyManager.Components.Pages.CaddyfileEditor; +namespace CaddyManager.Components.Pages.Caddy.CaddyfileEditor; public partial class CaddyfileEditor : ComponentBase { diff --git a/CaddyManager/Components/Pages/CaddyfilePage.razor b/CaddyManager/Components/Pages/Caddy/CaddyfilePage.razor similarity index 100% rename from CaddyManager/Components/Pages/CaddyfilePage.razor rename to CaddyManager/Components/Pages/Caddy/CaddyfilePage.razor diff --git a/CaddyManager/Components/Pages/CaddyfilePage.razor.cs b/CaddyManager/Components/Pages/Caddy/CaddyfilePage.razor.cs similarity index 91% rename from CaddyManager/Components/Pages/CaddyfilePage.razor.cs rename to CaddyManager/Components/Pages/Caddy/CaddyfilePage.razor.cs index 56bb885..a7059cb 100644 --- a/CaddyManager/Components/Pages/CaddyfilePage.razor.cs +++ b/CaddyManager/Components/Pages/Caddy/CaddyfilePage.razor.cs @@ -3,7 +3,7 @@ using CaddyManager.Contracts.Caddy; using Microsoft.AspNetCore.Components; using MudBlazor; -namespace CaddyManager.Components.Pages; +namespace CaddyManager.Components.Pages.Caddy; public partial class CaddyfilePage : ComponentBase { @@ -28,6 +28,7 @@ public partial class CaddyfilePage : ComponentBase AutomaticLayout = true, Language = "plaintext", Value = _caddyConfigurationContent, + Theme = "vs-dark", }; } @@ -47,6 +48,6 @@ public partial class CaddyfilePage : ComponentBase private void Cancel() { - // CaddyService.GetCaddyGlobalConfigurationContent(); + _codeEditor.SetValue(_caddyConfigurationContent); } } \ No newline at end of file diff --git a/CaddyManager/Components/Pages/ReverseProxies/ReverseProxiesPage.razor b/CaddyManager/Components/Pages/Caddy/ReverseProxies/ReverseProxiesPage.razor similarity index 68% rename from CaddyManager/Components/Pages/ReverseProxies/ReverseProxiesPage.razor rename to CaddyManager/Components/Pages/Caddy/ReverseProxies/ReverseProxiesPage.razor index 398c0d6..49f8516 100644 --- a/CaddyManager/Components/Pages/ReverseProxies/ReverseProxiesPage.razor +++ b/CaddyManager/Components/Pages/Caddy/ReverseProxies/ReverseProxiesPage.razor @@ -3,7 +3,7 @@ Reverse proxy configurations - + New... @@ -11,6 +11,13 @@ Disabled="@(_selectedCaddyConfigurations.Count <= 0)" OnClick="Delete">Delete + Restart Caddy + + @if (_isProcessing) + { + + } diff --git a/CaddyManager/Components/Pages/ReverseProxies/ReverseProxiesPage.razor.cs b/CaddyManager/Components/Pages/Caddy/ReverseProxies/ReverseProxiesPage.razor.cs similarity index 69% rename from CaddyManager/Components/Pages/ReverseProxies/ReverseProxiesPage.razor.cs rename to CaddyManager/Components/Pages/Caddy/ReverseProxies/ReverseProxiesPage.razor.cs index e59f573..1ea7f0f 100644 --- a/CaddyManager/Components/Pages/ReverseProxies/ReverseProxiesPage.razor.cs +++ b/CaddyManager/Components/Pages/Caddy/ReverseProxies/ReverseProxiesPage.razor.cs @@ -1,17 +1,22 @@ using CaddyManager.Contracts.Caddy; +using CaddyManager.Contracts.Docker; using Microsoft.AspNetCore.Components; using MudBlazor; -namespace CaddyManager.Components.Pages.ReverseProxies; +namespace CaddyManager.Components.Pages.Caddy.ReverseProxies; public partial class ReverseProxiesPage : ComponentBase { + private bool _isProcessing; private List _availableCaddyConfigurations = []; private IReadOnlyCollection _selectedCaddyConfigurations = []; [Inject] private ICaddyService CaddyService { get; set; } = null!; + [Inject] + private IDockerService DockerService { get; set; } = null!; + [Inject] private IDialogService DialogService { get; set; } = null!; @@ -59,6 +64,9 @@ public partial class ReverseProxiesPage : ComponentBase StateHasChanged(); } + /// + /// Have the selected configurations be deleted + /// private void Delete() { var response = CaddyService.DeleteCaddyConfigurations(_selectedCaddyConfigurations.ToList()); @@ -75,4 +83,26 @@ public partial class ReverseProxiesPage : ComponentBase Snackbar.Add(response.Message, Severity.Error); } } + + /// + /// Restart the Caddy container + /// + /// + private async Task RestartCaddy() + { + try + { + _isProcessing = true; + StateHasChanged(); + Snackbar.Add("Restarting Caddy container", Severity.Info); + await DockerService.RestartCaddyContainerAsync(); + Snackbar.Add("Caddy container restarted successfully", Severity.Success); + _isProcessing = false; + StateHasChanged(); + } + catch + { + Snackbar.Add("Failed to restart the Caddy container", Severity.Error); + } + } } \ No newline at end of file diff --git a/CaddyManager/Components/Pages/ReverseProxies/ReverseProxyItem.razor b/CaddyManager/Components/Pages/Caddy/ReverseProxies/ReverseProxyItem.razor similarity index 100% rename from CaddyManager/Components/Pages/ReverseProxies/ReverseProxyItem.razor rename to CaddyManager/Components/Pages/Caddy/ReverseProxies/ReverseProxyItem.razor diff --git a/CaddyManager/Components/Pages/ReverseProxies/ReverseProxyItem.razor.cs b/CaddyManager/Components/Pages/Caddy/ReverseProxies/ReverseProxyItem.razor.cs similarity index 92% rename from CaddyManager/Components/Pages/ReverseProxies/ReverseProxyItem.razor.cs rename to CaddyManager/Components/Pages/Caddy/ReverseProxies/ReverseProxyItem.razor.cs index 3bfa86f..67ccd2c 100644 --- a/CaddyManager/Components/Pages/ReverseProxies/ReverseProxyItem.razor.cs +++ b/CaddyManager/Components/Pages/Caddy/ReverseProxies/ReverseProxyItem.razor.cs @@ -2,7 +2,7 @@ using CaddyManager.Contracts.Caddy; using Microsoft.AspNetCore.Components; using MudBlazor; -namespace CaddyManager.Components.Pages.ReverseProxies; +namespace CaddyManager.Components.Pages.Caddy.ReverseProxies; public partial class ReverseProxyItem : ComponentBase { diff --git a/CaddyManager/Components/Pages/Settings.razor b/CaddyManager/Components/Pages/Settings.razor deleted file mode 100644 index ec4cef2..0000000 --- a/CaddyManager/Components/Pages/Settings.razor +++ /dev/null @@ -1,21 +0,0 @@ -@page "/settings" -@using CaddyManager.Contracts.Caddy -@inject ICaddyService CaddyService - -Counter - -

Counter

- -

Current count: @currentCount

- -Click me - -@code { - private int currentCount = 0; - - private void IncrementCount() - { - Console.WriteLine(string.Join('\n', CaddyService.GetExistingCaddyConfigurations())); - } - -} \ No newline at end of file diff --git a/CaddyManager/Configurations/Docker/DockerServiceConfiguration.cs b/CaddyManager/Configurations/Docker/DockerServiceConfiguration.cs new file mode 100644 index 0000000..3a23cf7 --- /dev/null +++ b/CaddyManager/Configurations/Docker/DockerServiceConfiguration.cs @@ -0,0 +1,25 @@ +namespace CaddyManager.Configurations.Docker; + +/// +/// Configuration for the Docker service +/// +public class DockerServiceConfiguration +{ + public const string Docker = "Docker"; + + /// + /// Name of the Caddy container to be controlled (i.e restart) + /// + public string CaddyContainerName { get; set; } = "caddy"; + + /// + /// Uri to the Docker host + /// + public string DockerHost { get; set; } = "unix:///var/run/docker.sock"; + + /// + /// Returns the Docker host with environment check. If the environment variable DOCKER_HOST is set, it will return + /// that value, otherwise it will return the value of DockerHost + /// + public string DockerHostWithEnvCheck => Environment.GetEnvironmentVariable("DOCKER_HOST") ?? DockerHost; +} \ No newline at end of file diff --git a/CaddyManager/Contracts/Configurations/IConfigurationsService.cs b/CaddyManager/Contracts/Configurations/IConfigurationsService.cs index 9914434..144634e 100644 --- a/CaddyManager/Contracts/Configurations/IConfigurationsService.cs +++ b/CaddyManager/Contracts/Configurations/IConfigurationsService.cs @@ -1,4 +1,5 @@ using CaddyManager.Configurations.Caddy; +using CaddyManager.Configurations.Docker; namespace CaddyManager.Contracts.Configurations; @@ -11,4 +12,9 @@ public interface IConfigurationsService /// Configurations for Caddy service /// CaddyServiceConfigurations CaddyServiceConfigurations { get; } + + /// + /// Configurations for Docker service + /// + DockerServiceConfiguration DockerServiceConfiguration { get; } } \ No newline at end of file diff --git a/CaddyManager/Contracts/Docker/IDockerService.cs b/CaddyManager/Contracts/Docker/IDockerService.cs new file mode 100644 index 0000000..9669e6c --- /dev/null +++ b/CaddyManager/Contracts/Docker/IDockerService.cs @@ -0,0 +1,13 @@ +namespace CaddyManager.Contracts.Docker; + +/// +/// Contract for the service to interact with Docker +/// +public interface IDockerService +{ + /// + /// Method to help restart the Caddy container + /// + /// + Task RestartCaddyContainerAsync(); +} \ No newline at end of file diff --git a/CaddyManager/Program.cs b/CaddyManager/Program.cs index ae2f8ee..c6b89d6 100644 --- a/CaddyManager/Program.cs +++ b/CaddyManager/Program.cs @@ -12,7 +12,7 @@ builder.Services // Auto register all the Services, Repositories that we have had within the code base builder.Services.RegisterAssemblyPublicNonGenericClasses() - .Where(t => t.Name.EndsWith("Service") || t.Name.EndsWith("Repository")) + .Where(t => t.Name.EndsWith("Service")) .AsPublicImplementedInterfaces(); builder.Services.AddSignalR(e => { e.MaximumReceiveMessageSize = 102400000; }); diff --git a/CaddyManager/Services/CaddyService.cs b/CaddyManager/Services/Caddy/CaddyService.cs similarity index 99% rename from CaddyManager/Services/CaddyService.cs rename to CaddyManager/Services/Caddy/CaddyService.cs index 7d85d30..020938c 100644 --- a/CaddyManager/Services/CaddyService.cs +++ b/CaddyManager/Services/Caddy/CaddyService.cs @@ -3,7 +3,7 @@ using CaddyManager.Contracts.Caddy; using CaddyManager.Contracts.Configurations; using CaddyManager.Models.Caddy; -namespace CaddyManager.Services; +namespace CaddyManager.Services.Caddy; /// public class CaddyService(IConfigurationsService configurationsService) : ICaddyService diff --git a/CaddyManager/Services/Configurations/ConfigurationsService.cs b/CaddyManager/Services/Configurations/ConfigurationsService.cs index dc4c415..52daa78 100644 --- a/CaddyManager/Services/Configurations/ConfigurationsService.cs +++ b/CaddyManager/Services/Configurations/ConfigurationsService.cs @@ -1,4 +1,5 @@ using CaddyManager.Configurations.Caddy; +using CaddyManager.Configurations.Docker; using CaddyManager.Contracts.Configurations; using NetCore.AutoRegisterDi; @@ -12,4 +13,8 @@ public class ConfigurationsService(IConfiguration configuration) : IConfiguratio public CaddyServiceConfigurations CaddyServiceConfigurations => configuration.GetSection(CaddyServiceConfigurations.Caddy).Get() ?? new CaddyServiceConfigurations(); + + public DockerServiceConfiguration DockerServiceConfiguration => + configuration.GetSection(DockerServiceConfiguration.Docker).Get() ?? + new DockerServiceConfiguration(); } \ No newline at end of file diff --git a/CaddyManager/Services/Docker/DockerService.cs b/CaddyManager/Services/Docker/DockerService.cs new file mode 100644 index 0000000..328513b --- /dev/null +++ b/CaddyManager/Services/Docker/DockerService.cs @@ -0,0 +1,48 @@ +using CaddyManager.Configurations.Docker; +using CaddyManager.Contracts.Configurations; +using CaddyManager.Contracts.Docker; +using Docker.DotNet; +using Docker.DotNet.Models; + +namespace CaddyManager.Services.Docker; + +/// +public class DockerService(IConfigurationsService configurationsService) : IDockerService +{ + private DockerServiceConfiguration Configuration => configurationsService.DockerServiceConfiguration; + + /// + /// Method to get the container id of the Caddy container by the name configured + /// + /// + private async Task GetCaddyContainerId() + { + var client = new DockerClientConfiguration(new Uri(Configuration.DockerHostWithEnvCheck)).CreateClient(); + + if (client == null) return string.Empty; + + var containers = await client.Containers.ListContainersAsync(new ContainersListParameters + { + All = true + }); + + return containers.FirstOrDefault(container => container.Names.Contains($"/{Configuration.CaddyContainerName}")) + ?.ID ?? string.Empty; + + } + + /// + public async Task RestartCaddyContainerAsync() + { + var containerId = await GetCaddyContainerId(); + + if (string.IsNullOrEmpty(containerId)) return; + + var client = new DockerClientConfiguration(new Uri(Configuration.DockerHostWithEnvCheck)).CreateClient(); + + if (client != null) + { + await client.Containers.RestartContainerAsync(containerId, new ContainerRestartParameters()); + } + } +} \ No newline at end of file diff --git a/CaddyManager/appsettings.json b/CaddyManager/appsettings.json index 8de4892..1ad8666 100644 --- a/CaddyManager/appsettings.json +++ b/CaddyManager/appsettings.json @@ -8,5 +8,9 @@ "AllowedHosts": "*", "Caddy": { "ConfigDir": "/root/compose/caddy/config" + }, + "Docker": { + "CaddyContainerName": "caddy", + "DockerHost": "unix:///var/run/docker.sock" } } diff --git a/CaddyManager/wwwroot/app.css b/CaddyManager/wwwroot/app.css index 62eac32..295020b 100644 --- a/CaddyManager/wwwroot/app.css +++ b/CaddyManager/wwwroot/app.css @@ -11,4 +11,5 @@ .caddy-file-editor .monaco-editor { overflow: hidden; border-radius: inherit; + padding: 8px; } \ No newline at end of file