init: initial commit for the project

This commit is contained in:
2025-01-23 08:54:08 +07:00
commit 0ab177abc7
26 changed files with 493 additions and 0 deletions

25
.dockerignore Normal file
View File

@@ -0,0 +1,25 @@
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/.idea
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/azds.yaml
**/bin
**/charts
**/docker-compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md

5
.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
bin/
obj/
/packages/
riderModule.iml
/_ReSharper.Caches/

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
</project>

21
CaddyManager.sln Normal file
View File

@@ -0,0 +1,21 @@

Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CaddyManager", "CaddyManager\CaddyManager.csproj", "{48F15175-A1B9-457D-9CA2-04C241F3435C}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{EC202984-FC85-4101-B801-1E8AA4E9C4DD}"
ProjectSection(SolutionItems) = preProject
compose.yaml = compose.yaml
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{48F15175-A1B9-457D-9CA2-04C241F3435C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{48F15175-A1B9-457D-9CA2-04C241F3435C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{48F15175-A1B9-457D-9CA2-04C241F3435C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{48F15175-A1B9-457D-9CA2-04C241F3435C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
</PropertyGroup>
<ItemGroup>
<Content Include="..\.dockerignore">
<Link>.dockerignore</Link>
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="MudBlazor" Version="8.0.0" />
<PackageReference Include="NetCore.AutoRegisterDi" Version="2.2.1" />
</ItemGroup>
<ItemGroup>
<Folder Include="Models\" />
<Folder Include="Repositories\" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,23 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<base href="/"/>
<link rel="stylesheet" href="@Assets["app.css"]"/>
<link rel="stylesheet" href="@Assets["CaddyManager.styles.css"]"/>
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" rel="stylesheet" />
<link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" />
<ImportMap/>
<link rel="icon" type="image/png" href="favicon.png"/>
<HeadOutlet @rendermode="InteractiveServer"/>
</head>
<body>
<Routes @rendermode="InteractiveServer"/>
<script src="_framework/blazor.web.js"></script>
<script src="_content/MudBlazor/MudBlazor.min.js"></script>
</body>
</html>

View File

@@ -0,0 +1,43 @@
@inherits LayoutComponentBase
@* Required *@
<MudThemeProvider />
<MudPopoverProvider />
@* Needed for dialogs *@
<MudDialogProvider />
@* Needed for snackbars *@
<MudSnackbarProvider />
<MudLayout>
<MudAppBar Elevation="1" Dense="true">
<MudIconButton Icon="@Icons.Material.Filled.Menu" Color="Color.Inherit" Edge="Edge.Start" OnClick="@ToggleDrawer" />
<MudSpacer />
<MudIconButton Icon="@Icons.Custom.Brands.GitHub" Color="Color.Inherit" Href="https://github.com/MudBlazor/MudBlazor" Target="_blank" />
</MudAppBar>
<MudDrawer @bind-Open="@_open" ClipMode="DrawerClipMode.Docked" Elevation="1" Variant="@DrawerVariant.Responsive">
<MudDrawerHeader>
<MudText Typo="Typo.h6">Caddy Manager</MudText>
</MudDrawerHeader>
<MudNavMenu>
<MudNavLink Match="NavLinkMatch.All" Href="/">Reverse Proxies</MudNavLink>
<MudNavLink Match="NavLinkMatch.All" Href="/caddyfile">Global Caddyfile</MudNavLink>
<MudNavLink Match="NavLinkMatch.All" Href="/settings">Settings</MudNavLink>
</MudNavMenu>
</MudDrawer>
<MudMainContent Class="pt-16 px-16">
<MudContainer Class="mt-6">
@Body
</MudContainer>
</MudMainContent>
</MudLayout>
@code{
private bool _open = false;
private void ToggleDrawer()
{
_open = !_open;
}
}

View File

@@ -0,0 +1,66 @@
@page "/caddyfile"
<PageTitle>Weather</PageTitle>
<h1>Weather</h1>
<p>This component demonstrates showing data.</p>
@if (forecasts == null)
{
<p>
<em>Loading...</em>
</p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Date</th>
<th aria-label="Temperature in Celsius">Temp. (C)</th>
<th aria-label="Temperature in Farenheit">Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in forecasts)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
}
@code {
private WeatherForecast[]? forecasts;
protected override async Task OnInitializedAsync()
{
// Simulate asynchronous loading to demonstrate a loading indicator
await Task.Delay(500);
var startDate = DateOnly.FromDateTime(DateTime.Now);
var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" };
forecasts = Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = startDate.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = summaries[Random.Shared.Next(summaries.Length)]
}).ToArray();
}
private class WeatherForecast
{
public DateOnly Date { get; set; }
public int TemperatureC { get; set; }
public string? Summary { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}
}

View File

@@ -0,0 +1,36 @@
@page "/Error"
@using System.Diagnostics
<PageTitle>Error</PageTitle>
<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>
@if (ShowRequestId)
{
<p>
<strong>Request ID:</strong> <code>@RequestId</code>
</p>
}
<h3>Development Mode</h3>
<p>
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
</p>
<p>
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
It can result in displaying sensitive information from exceptions to end users.
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
and restarting the app.
</p>
@code{
[CascadingParameter] private HttpContext? HttpContext { get; set; }
private string? RequestId { get; set; }
private bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
protected override void OnInitialized() =>
RequestId = Activity.Current?.Id ?? HttpContext?.TraceIdentifier;
}

View File

@@ -0,0 +1,24 @@
@page "/"
@using CaddyManager.Contracts.Caddy
@inject ICaddyService CaddyService
<PageTitle>Home</PageTitle>
<MudList T="string">
@foreach(var caddyConfig in _availableCaddyConfigurations)
{
<MudListItem Text="@caddyConfig" Icon="@Icons.Material.Filled.InsertDriveFile"/>
<MudDivider/>
}
</MudList>
@code
{
List<string> _availableCaddyConfigurations = [];
protected override Task OnInitializedAsync()
{
_availableCaddyConfigurations = CaddyService.GetExistingCaddyConfigurations();
return base.OnInitializedAsync();
}
}

View File

@@ -0,0 +1,21 @@
@page "/settings"
@using CaddyManager.Contracts.Caddy
@inject ICaddyService CaddyService
<PageTitle>Counter</PageTitle>
<h1>Counter</h1>
<p role="status">Current count: @currentCount</p>
<MudButton Variant="Variant.Filled" Color="Color.Primary" @onclick="IncrementCount">Click me</MudButton>
@code {
private int currentCount = 0;
private void IncrementCount()
{
Console.WriteLine(string.Join('\n', CaddyService.GetExistingCaddyConfigurations()));
}
}

View File

@@ -0,0 +1,6 @@
<Router AppAssembly="typeof(Program).Assembly">
<Found Context="routeData">
<RouteView RouteData="routeData" DefaultLayout="typeof(Layout.MainLayout)"/>
<FocusOnNavigate RouteData="routeData" Selector="h1"/>
</Found>
</Router>

View File

@@ -0,0 +1,11 @@
@using System.Net.Http
@using System.Net.Http.Json
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using static Microsoft.AspNetCore.Components.Web.RenderMode
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.JSInterop
@using CaddyManager
@using CaddyManager.Components
@using MudBlazor

View File

@@ -0,0 +1,11 @@
namespace CaddyManager.Configurations.Caddy;
/// <summary>
/// Wraps the configurations for Caddy service
/// </summary>
public class CaddyServiceConfigurations
{
public const string Caddy = "Caddy";
public string ConfigDir { get; set; } = "/config";
}

View File

@@ -0,0 +1,13 @@
namespace CaddyManager.Contracts.Caddy;
/// <summary>
/// Contracts for Caddy Service to help monitor the available Caddy configurations
/// </summary>
public interface ICaddyService
{
/// <summary>
/// Returns the existing Caddy configurations within the configured directory
/// </summary>
/// <returns></returns>
List<string> GetExistingCaddyConfigurations();
}

View File

@@ -0,0 +1,14 @@
using CaddyManager.Configurations.Caddy;
namespace CaddyManager.Contracts.Configurations;
/// <summary>
/// Contract for the services providing the configurations for the application
/// </summary>
public interface IConfigurationsService
{
/// <summary>
/// Configurations for Caddy service
/// </summary>
CaddyServiceConfigurations CaddyServiceConfigurations { get; }
}

23
CaddyManager/Dockerfile Normal file
View File

@@ -0,0 +1,23 @@
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
USER $APP_UID
WORKDIR /app
EXPOSE 8080
EXPOSE 8081
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["CaddyManager/CaddyManager.csproj", "CaddyManager/"]
RUN dotnet restore "CaddyManager/CaddyManager.csproj"
COPY . .
WORKDIR "/src/CaddyManager"
RUN dotnet build "CaddyManager.csproj" -c $BUILD_CONFIGURATION -o /app/build
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "CaddyManager.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "CaddyManager.dll"]

37
CaddyManager/Program.cs Normal file
View File

@@ -0,0 +1,37 @@
using CaddyManager.Components;
using MudBlazor.Services;
using NetCore.AutoRegisterDi;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services
.AddMudServices()
.AddRazorComponents()
.AddInteractiveServerComponents();
// 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"))
.AsPublicImplementedInterfaces();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error", createScopeForErrors: true);
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseAntiforgery();
app.MapStaticAssets();
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode();
app.Run();

View File

@@ -0,0 +1,23 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
"applicationUrl": "http://localhost:8080",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
"applicationUrl": "https://localhost:8081;http://localhost:8080",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@@ -0,0 +1,17 @@
using CaddyManager.Configurations.Caddy;
using CaddyManager.Contracts.Caddy;
using CaddyManager.Contracts.Configurations;
namespace CaddyManager.Services;
/// <inheritdoc />
public class CaddyService(IConfigurationsService configurationsService) : ICaddyService
{
private CaddyServiceConfigurations _configurations => configurationsService.CaddyServiceConfigurations;
/// <inheritdoc />
public List<string> GetExistingCaddyConfigurations()
{
return Directory.GetFiles(_configurations.ConfigDir).ToList();
}
}

View File

@@ -0,0 +1,15 @@
using CaddyManager.Configurations.Caddy;
using CaddyManager.Contracts.Configurations;
using NetCore.AutoRegisterDi;
namespace CaddyManager.Services.Configurations;
/// <inheritdoc />
[RegisterAsSingleton]
public class ConfigurationsService(IConfiguration configuration) : IConfigurationsService
{
/// <inheritdoc />
public CaddyServiceConfigurations CaddyServiceConfigurations =>
configuration.GetSection(CaddyServiceConfigurations.Caddy).Get<CaddyServiceConfigurations>() ??
new CaddyServiceConfigurations();
}

View File

@@ -0,0 +1,11 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"Caddy": {
"ConfigDir": "/Users/ebolo/Code/caddy/config"
}
}

View File

@@ -0,0 +1,12 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"Caddy": {
"ConfigDir": "/root/compose/caddy/config"
}
}

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

6
compose.yaml Normal file
View File

@@ -0,0 +1,6 @@
services:
caddymanager:
image: caddymanager
build:
context: .
dockerfile: CaddyManager/Dockerfile