mirror of
https://github.com/SoPat712/allstarr.git
synced 2026-02-10 07:58:39 -05:00
Move admin endpoints to internal port 5275 for security
This commit is contained in:
@@ -2015,6 +2015,284 @@ public class AdminController : ControllerBase
|
||||
GC.Collect(2, GCCollectionMode.Optimized, blocking: false);
|
||||
}
|
||||
}
|
||||
|
||||
#region Spotify Admin Endpoints
|
||||
|
||||
/// <summary>
|
||||
/// Manual trigger endpoint to force fetch Spotify missing tracks.
|
||||
/// </summary>
|
||||
[HttpGet("spotify/sync")]
|
||||
public async Task<IActionResult> TriggerSpotifySync([FromServices] IEnumerable<IHostedService> hostedServices)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!_spotifyImportSettings.Enabled)
|
||||
{
|
||||
return BadRequest(new { error = "Spotify Import is not enabled" });
|
||||
}
|
||||
|
||||
_logger.LogInformation("Manual Spotify sync triggered via admin endpoint");
|
||||
|
||||
// Find the SpotifyMissingTracksFetcher service
|
||||
var fetcherService = hostedServices
|
||||
.OfType<allstarr.Services.Spotify.SpotifyMissingTracksFetcher>()
|
||||
.FirstOrDefault();
|
||||
|
||||
if (fetcherService == null)
|
||||
{
|
||||
return BadRequest(new { error = "SpotifyMissingTracksFetcher service not found" });
|
||||
}
|
||||
|
||||
// Trigger the sync in background
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
// Use reflection to call the private ExecuteOnceAsync method
|
||||
var method = fetcherService.GetType().GetMethod("ExecuteOnceAsync",
|
||||
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
|
||||
|
||||
if (method != null)
|
||||
{
|
||||
await (Task)method.Invoke(fetcherService, new object[] { CancellationToken.None })!;
|
||||
_logger.LogInformation("Manual Spotify sync completed successfully");
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogError("Could not find ExecuteOnceAsync method on SpotifyMissingTracksFetcher");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error during manual Spotify sync");
|
||||
}
|
||||
});
|
||||
|
||||
return Ok(new {
|
||||
message = "Spotify sync started in background",
|
||||
timestamp = DateTime.UtcNow
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error triggering Spotify sync");
|
||||
return StatusCode(500, new { error = "Internal server error" });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Manual trigger endpoint to force Spotify track matching.
|
||||
/// </summary>
|
||||
[HttpGet("spotify/match")]
|
||||
public async Task<IActionResult> TriggerSpotifyMatch([FromServices] IEnumerable<IHostedService> hostedServices)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!_spotifyApiSettings.Enabled)
|
||||
{
|
||||
return BadRequest(new { error = "Spotify API is not enabled" });
|
||||
}
|
||||
|
||||
_logger.LogInformation("Manual Spotify track matching triggered via admin endpoint");
|
||||
|
||||
// Find the SpotifyTrackMatchingService
|
||||
var matchingService = hostedServices
|
||||
.OfType<allstarr.Services.Spotify.SpotifyTrackMatchingService>()
|
||||
.FirstOrDefault();
|
||||
|
||||
if (matchingService == null)
|
||||
{
|
||||
return BadRequest(new { error = "SpotifyTrackMatchingService not found" });
|
||||
}
|
||||
|
||||
// Trigger matching in background
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
// Use reflection to call the private ExecuteOnceAsync method
|
||||
var method = matchingService.GetType().GetMethod("ExecuteOnceAsync",
|
||||
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
|
||||
|
||||
if (method != null)
|
||||
{
|
||||
await (Task)method.Invoke(matchingService, new object[] { CancellationToken.None })!;
|
||||
_logger.LogInformation("Manual Spotify track matching completed successfully");
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogError("Could not find ExecuteOnceAsync method on SpotifyTrackMatchingService");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error during manual Spotify track matching");
|
||||
}
|
||||
});
|
||||
|
||||
return Ok(new {
|
||||
message = "Spotify track matching started in background",
|
||||
timestamp = DateTime.UtcNow
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error triggering Spotify track matching");
|
||||
return StatusCode(500, new { error = "Internal server error" });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear Spotify playlist cache to force re-matching.
|
||||
/// </summary>
|
||||
[HttpPost("spotify/clear-cache")]
|
||||
public async Task<IActionResult> ClearSpotifyCache()
|
||||
{
|
||||
try
|
||||
{
|
||||
var clearedKeys = new List<string>();
|
||||
|
||||
// Clear Redis cache for all configured playlists
|
||||
foreach (var playlist in _spotifyImportSettings.Playlists)
|
||||
{
|
||||
var keys = new[]
|
||||
{
|
||||
$"spotify:playlist:{playlist.Name}",
|
||||
$"spotify:playlist:items:{playlist.Name}",
|
||||
$"spotify:matched:{playlist.Name}"
|
||||
};
|
||||
|
||||
foreach (var key in keys)
|
||||
{
|
||||
await _cache.DeleteAsync(key);
|
||||
clearedKeys.Add(key);
|
||||
}
|
||||
}
|
||||
|
||||
_logger.LogInformation("Cleared Spotify cache for {Count} keys via admin endpoint", clearedKeys.Count);
|
||||
|
||||
return Ok(new {
|
||||
message = "Spotify cache cleared successfully",
|
||||
clearedKeys = clearedKeys,
|
||||
timestamp = DateTime.UtcNow
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error clearing Spotify cache");
|
||||
return StatusCode(500, new { error = "Internal server error" });
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Debug Endpoints
|
||||
|
||||
/// <summary>
|
||||
/// Gets endpoint usage statistics from the log file.
|
||||
/// </summary>
|
||||
[HttpGet("debug/endpoint-usage")]
|
||||
public async Task<IActionResult> GetEndpointUsage(
|
||||
[FromQuery] int top = 100,
|
||||
[FromQuery] string? since = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var logFile = "/app/cache/endpoint-usage/endpoints.csv";
|
||||
|
||||
if (!System.IO.File.Exists(logFile))
|
||||
{
|
||||
return Ok(new {
|
||||
message = "No endpoint usage data available",
|
||||
endpoints = new object[0]
|
||||
});
|
||||
}
|
||||
|
||||
var lines = await System.IO.File.ReadAllLinesAsync(logFile);
|
||||
var usage = new Dictionary<string, int>();
|
||||
DateTime? sinceDate = null;
|
||||
|
||||
if (!string.IsNullOrEmpty(since) && DateTime.TryParse(since, out var parsedDate))
|
||||
{
|
||||
sinceDate = parsedDate;
|
||||
}
|
||||
|
||||
foreach (var line in lines.Skip(1)) // Skip header
|
||||
{
|
||||
var parts = line.Split(',');
|
||||
if (parts.Length >= 3)
|
||||
{
|
||||
var timestamp = parts[0];
|
||||
var endpoint = parts[1];
|
||||
|
||||
// Filter by date if specified
|
||||
if (sinceDate.HasValue && DateTime.TryParse(timestamp, out var logDate))
|
||||
{
|
||||
if (logDate < sinceDate.Value)
|
||||
continue;
|
||||
}
|
||||
|
||||
usage[endpoint] = usage.GetValueOrDefault(endpoint, 0) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
var topEndpoints = usage
|
||||
.OrderByDescending(kv => kv.Value)
|
||||
.Take(top)
|
||||
.Select(kv => new { endpoint = kv.Key, count = kv.Value })
|
||||
.ToArray();
|
||||
|
||||
return Ok(new {
|
||||
totalEndpoints = usage.Count,
|
||||
totalRequests = usage.Values.Sum(),
|
||||
since = since,
|
||||
top = top,
|
||||
endpoints = topEndpoints
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error getting endpoint usage");
|
||||
return StatusCode(500, new { error = "Internal server error" });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the endpoint usage log file.
|
||||
/// </summary>
|
||||
[HttpDelete("debug/endpoint-usage")]
|
||||
public IActionResult ClearEndpointUsage()
|
||||
{
|
||||
try
|
||||
{
|
||||
var logFile = "/app/cache/endpoint-usage/endpoints.csv";
|
||||
|
||||
if (System.IO.File.Exists(logFile))
|
||||
{
|
||||
System.IO.File.Delete(logFile);
|
||||
_logger.LogInformation("Cleared endpoint usage log via admin endpoint");
|
||||
|
||||
return Ok(new {
|
||||
message = "Endpoint usage log cleared successfully",
|
||||
timestamp = DateTime.UtcNow
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
return Ok(new {
|
||||
message = "No endpoint usage log file found",
|
||||
timestamp = DateTime.UtcNow
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error clearing endpoint usage log");
|
||||
return StatusCode(500, new { error = "Internal server error" });
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public class ConfigUpdateRequest
|
||||
|
||||
Reference in New Issue
Block a user