mirror of
https://github.com/RedWizardsLab/EchoHub.git
synced 2026-09-04 08:36:11 +02:00
docs: Update documentation for 145 files
Generated by AurionDocs
Job ID: c99fff50-67a3-4294-b4df-3e73f4f12de9
Source commit: 4dcb480
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
# Adding a new controller
|
||||
|
||||
> *Workflow template auto-derived from 7 existing exemplar(s).*
|
||||
|
||||
This template describes how to add a new HTTP controller to the server: reach for this pattern when you need a new API surface implemented as an [ApiController] class that exposes routes and actions. Use the reference controller below as the concrete shape to copy (attributes, base class, constructor injection, and action patterns), and consult the existing examples to match naming and placement.
|
||||
|
||||
## Reference implementation
|
||||
|
||||
```csharp
|
||||
[ApiController]
|
||||
[Route("api/files")]
|
||||
[Authorize]
|
||||
[EnableRateLimiting("general")]
|
||||
public class FilesController : ControllerBase
|
||||
{
|
||||
private readonly FileStorageService _fileStorage;
|
||||
|
||||
public FilesController(FileStorageService fileStorage)
|
||||
{
|
||||
_fileStorage = fileStorage;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serves an uploaded file. Anonymous by design: the unguessable GUID in the URL is the
|
||||
/// access token (Discord-CDN-style capability URL), so attachment links can be opened
|
||||
/// directly in a browser and shared to IRC clients. E2E-encrypted room blobs are
|
||||
/// ciphertext at rest, so anonymous access reveals nothing for those channels.
|
||||
/// </summary>
|
||||
[HttpGet("{fileId}")]
|
||||
[AllowAnonymous]
|
||||
public IActionResult GetFile(string fileId)
|
||||
{
|
||||
if (!Guid.TryParse(fileId, out _))
|
||||
return BadRequest(new ErrorResponse("Invalid file identifier."));
|
||||
|
||||
var filePath = _fileStorage.GetFilePath(fileId);
|
||||
|
||||
if (filePath is null)
|
||||
return NotFound(new ErrorResponse("File not found."));
|
||||
|
||||
var contentType = Path.GetExtension(filePath).ToLowerInvariant() switch
|
||||
{
|
||||
".jpg" or ".jpeg" => "image/jpeg",
|
||||
".png" => "image/png",
|
||||
".gif" => "image/gif",
|
||||
".webp" => "image/webp",
|
||||
".mp3" => "audio/mpeg",
|
||||
".wav" => "audio/wav",
|
||||
".ogg" => "audio/ogg",
|
||||
".flac" => "audio/flac",
|
||||
".aac" => "audio/aac",
|
||||
".m4a" => "audio/mp4",
|
||||
".wma" => "audio/x-ms-wma",
|
||||
".pdf" => "application/pdf",
|
||||
".txt" => "text/plain",
|
||||
_ => "application/octet-stream"
|
||||
};
|
||||
|
||||
// Images and audio render inline so a browser displays them instead of
|
||||
// downloading; everything else keeps the attachment disposition.
|
||||
if (contentType.StartsWith("image/") || contentType.StartsWith("audio/"))
|
||||
return PhysicalFile(filePath, contentType);
|
||||
|
||||
var fileName = Path.GetFileName(filePath);
|
||||
return PhysicalFile(filePath, contentType, fileName);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Where it lives
|
||||
|
||||
Controllers in this codebase are placed under src/EchoHub.Server/Controllers, and exemplar files use names such as AuthController.cs, ChannelsController.cs, FilesController.cs, InvitesController.cs, ModerationController.cs, ServerController.cs, and UsersController.cs with corresponding public classes named AuthController, ChannelsController, FilesController, InvitesController, ModerationController, ServerController, and UsersController. Use that same folder and naming pattern when adding a new controller file.
|
||||
|
||||
## Wiring
|
||||
|
||||
A specific registration site for controllers was not detected in the symbol graph provided. Inspect the existing controllers listed below to see how they are referenced in the project and to follow the same runtime usage patterns used by the application.
|
||||
|
||||
## Existing examples
|
||||
|
||||
- [`AuthController`](../../Code/src/EchoHub.Server/Controllers/AuthController.cs.md)
|
||||
- [`ChannelsController`](../../Code/src/EchoHub.Server/Controllers/ChannelsController.cs.md)
|
||||
- [`FilesController`](../../Code/src/EchoHub.Server/Controllers/FilesController.cs.md)
|
||||
- [`InvitesController`](../../Code/src/EchoHub.Server/Controllers/InvitesController.cs.md)
|
||||
- [`ModerationController`](../../Code/src/EchoHub.Server/Controllers/ModerationController.cs.md)
|
||||
- [`ServerController`](../../Code/src/EchoHub.Server/Controllers/ServerController.cs.md)
|
||||
- [`UsersController`](../../Code/src/EchoHub.Server/Controllers/UsersController.cs.md)
|
||||
|
||||
---
|
||||
*Synthesised by Aurion on 2026-07-23 05:55:15 UTC*
|
||||
@@ -0,0 +1,94 @@
|
||||
# Adding a new service
|
||||
|
||||
> *Workflow template auto-derived from 8 existing exemplar(s).*
|
||||
|
||||
Adding a new service
|
||||
|
||||
When you need to encapsulate a piece of server functionality—either a long-lived background job or an application service consumed by controllers and other services—you add a new service type in this codebase. Use the existing service types in src/EchoHub.Server/Services as your models: pick a clear name that ends with "Service", place the source alongside the other services, and wire it up where services are registered.
|
||||
|
||||
## Reference implementation
|
||||
|
||||
Real code from `src/EchoHub.Server/Services/MuteExpirationService.cs` that a new instance can be modelled on:
|
||||
|
||||
```csharp
|
||||
/// <summary>
|
||||
/// Background service that periodically unmutes users whose timed mute has expired.
|
||||
/// </summary>
|
||||
public sealed class MuteExpirationService : BackgroundService
|
||||
{
|
||||
private static readonly TimeSpan CheckInterval = TimeSpan.FromSeconds(15);
|
||||
|
||||
private readonly IServiceScopeFactory _scopeFactory;
|
||||
private readonly ILogger<MuteExpirationService> _logger;
|
||||
|
||||
public MuteExpirationService(IServiceScopeFactory scopeFactory, ILogger<MuteExpirationService> logger)
|
||||
{
|
||||
_scopeFactory = scopeFactory;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
await Task.Yield();
|
||||
|
||||
while (!stoppingToken.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
{
|
||||
await UnmuteExpiredUsersAsync(stoppingToken);
|
||||
}
|
||||
catch (Exception ex) when (ex is not OperationCanceledException)
|
||||
{
|
||||
_logger.LogWarning(ex, "Error checking mute expirations");
|
||||
}
|
||||
|
||||
await Task.Delay(CheckInterval, stoppingToken);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task UnmuteExpiredUsersAsync(CancellationToken ct)
|
||||
{
|
||||
using var scope = _scopeFactory.CreateScope();
|
||||
var db = scope.ServiceProvider.GetRequiredService<EchoHubDbContext>();
|
||||
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
var expired = await db.Users
|
||||
.Where(u => u.IsMuted && u.MutedUntil.HasValue && u.MutedUntil.Value <= now)
|
||||
.ToListAsync(ct);
|
||||
|
||||
if (expired.Count == 0)
|
||||
return;
|
||||
|
||||
foreach (var user in expired)
|
||||
{
|
||||
user.IsMuted = false;
|
||||
user.MutedUntil = null;
|
||||
_logger.LogInformation("Auto-unmuted user {Username} (timed mute expired)", user.Username);
|
||||
}
|
||||
|
||||
await db.SaveChangesAsync(ct);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Where it lives
|
||||
|
||||
Service source files are placed in src/EchoHub.Server/Services. Existing service types include names such as ChannelService, ChatService, FileCleanupService, FileStorageService, LinkEmbedService, MessageEncryptionService, MuteExpirationService, and ServerDirectoryService; each service file in that folder defines the corresponding type (for example, public class ChannelService : IChannelService and public sealed class FileCleanupService : BackgroundService). Follow the same placement and name your new type with a Service suffix so it sits alongside these exemplars.
|
||||
|
||||
## Wiring
|
||||
|
||||
Detected registration/composition site: src/EchoHub.Server/Program.cs. Inspect that file to see how services from src/EchoHub.Server/Services are registered and how hosted/background services are added to the application; new service types should be wired there consistent with the existing registrations.
|
||||
|
||||
## Existing examples
|
||||
|
||||
- [`ChannelService`](../../Code/src/EchoHub.Server/Services/ChannelService.cs.md)
|
||||
- [`ChatService`](../../Code/src/EchoHub.Server/Services/ChatService.cs.md)
|
||||
- [`FileCleanupService`](../../Code/src/EchoHub.Server/Services/FileCleanupService.cs.md)
|
||||
- [`FileStorageService`](../../Code/src/EchoHub.Server/Services/FileStorageService.cs.md)
|
||||
- [`LinkEmbedService`](../../Code/src/EchoHub.Server/Services/LinkEmbedService.cs.md)
|
||||
- [`MessageEncryptionService`](../../Code/src/EchoHub.Server/Services/MessageEncryptionService.cs.md)
|
||||
- [`MuteExpirationService`](../../Code/src/EchoHub.Server/Services/MuteExpirationService.cs.md)
|
||||
- [`ServerDirectoryService`](../../Code/src/EchoHub.Server/Services/ServerDirectoryService.cs.md)
|
||||
|
||||
---
|
||||
*Synthesised by Aurion on 2026-07-23 05:55:34 UTC*
|
||||
Reference in New Issue
Block a user