✨ Link scrapping for preview
This commit is contained in:
110
DysonNetwork.Sphere/Connection/WebReader/WebReaderController.cs
Normal file
110
DysonNetwork.Sphere/Connection/WebReader/WebReaderController.cs
Normal file
@ -0,0 +1,110 @@
|
||||
using DysonNetwork.Sphere.Permission;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.RateLimiting;
|
||||
|
||||
namespace DysonNetwork.Sphere.Connection.WebReader;
|
||||
|
||||
/// <summary>
|
||||
/// Controller for web scraping and link preview services
|
||||
/// </summary>
|
||||
[ApiController]
|
||||
[Route("/scrap")]
|
||||
[EnableRateLimiting("fixed")]
|
||||
public class WebReaderController(WebReaderService reader, ILogger<WebReaderController> logger)
|
||||
: ControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieves a preview for the provided URL
|
||||
/// </summary>
|
||||
/// <param name="url">URL-encoded link to generate preview for</param>
|
||||
/// <returns>Link preview data including title, description, and image</returns>
|
||||
[HttpGet("link")]
|
||||
public async Task<ActionResult<LinkEmbed>> ScrapLink([FromQuery] string url)
|
||||
{
|
||||
if (string.IsNullOrEmpty(url))
|
||||
{
|
||||
return BadRequest(new { error = "URL parameter is required" });
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Ensure URL is properly decoded
|
||||
var decodedUrl = UrlDecoder.Decode(url);
|
||||
|
||||
// Validate URL format
|
||||
if (!Uri.TryCreate(decodedUrl, UriKind.Absolute, out _))
|
||||
{
|
||||
return BadRequest(new { error = "Invalid URL format" });
|
||||
}
|
||||
|
||||
var linkEmbed = await reader.GetLinkPreviewAsync(decodedUrl);
|
||||
return Ok(linkEmbed);
|
||||
}
|
||||
catch (WebReaderException ex)
|
||||
{
|
||||
logger.LogWarning(ex, "Error scraping link: {Url}", url);
|
||||
return BadRequest(new { error = ex.Message });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Unexpected error scraping link: {Url}", url);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError,
|
||||
new { error = "An unexpected error occurred while processing the link" });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Force invalidates the cache for a specific URL
|
||||
/// </summary>
|
||||
[HttpDelete("link/cache")]
|
||||
[Authorize]
|
||||
[RequiredPermission("maintenance", "cache.scrap")]
|
||||
public async Task<IActionResult> InvalidateCache([FromQuery] string url)
|
||||
{
|
||||
if (string.IsNullOrEmpty(url))
|
||||
{
|
||||
return BadRequest(new { error = "URL parameter is required" });
|
||||
}
|
||||
|
||||
await reader.InvalidateCacheForUrlAsync(url);
|
||||
return Ok(new { message = "Cache invalidated for URL" });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Force invalidates all cached link previews
|
||||
/// </summary>
|
||||
[HttpDelete("cache/all")]
|
||||
[Authorize]
|
||||
[RequiredPermission("maintenance", "cache.scrap")]
|
||||
public async Task<IActionResult> InvalidateAllCache()
|
||||
{
|
||||
await reader.InvalidateAllCachedPreviewsAsync();
|
||||
return Ok(new { message = "All link preview caches invalidated" });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper class for URL decoding
|
||||
/// </summary>
|
||||
public static class UrlDecoder
|
||||
{
|
||||
public static string Decode(string url)
|
||||
{
|
||||
// First check if URL is already decoded
|
||||
if (!url.Contains('%') && !url.Contains('+'))
|
||||
{
|
||||
return url;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return System.Net.WebUtility.UrlDecode(url);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// If decoding fails, return the original string
|
||||
return url;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user