using System.Collections.Concurrent;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
namespace ImageEffectApp.Web.Services
{
public class WebSocketMiddleware
{
private readonly RequestDelegate _next;
private static readonly ConcurrentDictionary _sockets = new();
public WebSocketMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
if (context.Request.Path == "/ws")
{
if (context.WebSockets.IsWebSocketRequest)
{
var webSocket = await context.WebSockets.AcceptWebSocketAsync();
var socketId = Guid.NewGuid();
_sockets.TryAdd(socketId, webSocket);
Console.WriteLine($"Yeni WebSocket bağlantısı: {socketId}");
await ReceiveMessages(webSocket);
_sockets.TryRemove(socketId, out _);
}
else
{
context.Response.StatusCode = 400;
}
}
else
{
await _next(context);
}
}
private async Task ReceiveMessages(WebSocket webSocket)
{
var buffer = new byte[1024 * 4];
while (webSocket.State == WebSocketState.Open)
{
var result = await webSocket.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None);
if (result.MessageType == WebSocketMessageType.Text)
{
string message = Encoding.UTF8.GetString(buffer, 0, result.Count);
Console.WriteLine($"WebSocket mesajı alındı: {message}");
await SendMessageToClients(message);
}
else if (result.MessageType == WebSocketMessageType.Close)
{
await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None);
}
}
}
public static async Task SendMessageToClients(string message)
{
var buffer = Encoding.UTF8.GetBytes(message);
var tasks = _sockets.Values
.Where(s => s.State == WebSocketState.Open)
.Select(s => s.SendAsync(new ArraySegment(buffer), WebSocketMessageType.Text, true, CancellationToken.None));
await Task.WhenAll(tasks);
}
}
}
using ImageEffectApp.Web.Models;
using ImageEffectApp.WorkerService.Models;
using Microsoft.Extensions.Options;
using RabbitMQ.Client;
using System.Net.Security;
using System.Text;
using System.Text.Json;
namespace ImageEffectApp.Web.Services
{
public class RabbitMQPublisher
{
private readonly string _hostName;
private readonly string _queueName;
public RabbitMQPublisher(IOptions options)
{
_hostName = options.Value.HostName;
_queueName= options.Value.QueueName;
}
public async Task PublishMessage(ImageProcessingRequest message)
{
try
{
var factory = new ConnectionFactory()
{
Uri = new Uri(_hostName),
Ssl = new SslOption
{
Enabled = true,
AcceptablePolicyErrors = SslPolicyErrors.RemoteCertificateChainErrors |
SslPolicyErrors.RemoteCertificateNameMismatch |
SslPolicyErrors.RemoteCertificateNotAvailable
}
};
await using var connection = await factory.CreateConnectionAsync();
await using var channel = await connection.CreateChannelAsync();
await channel.QueueDeclareAsync(_queueName, durable: true, exclusive: false, autoDelete: false, arguments: null);
var jsonMessage = JsonSerializer.Serialize(message);
var body = Encoding.UTF8.GetBytes(jsonMessage);
await channel.BasicPublishAsync(
exchange: "",
routingKey: _queueName,
mandatory: false,
basicProperties: new BasicProperties(),
body: body
);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
}
using Microsoft.AspNetCore.Mvc;
namespace ImageEffectApp.Web.Controllers
{
[ApiController]
[Route("api/delete")]
public class ClearController : ControllerBase
{
private readonly string _uploadsFolder = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "uploads");
private readonly string _processedFolder = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "processed");
[HttpDelete]
public IActionResult Clear()
{
try
{
if (Directory.Exists(_uploadsFolder))
{
var files = Directory.GetFiles(_uploadsFolder);
var deletedFiles = new List();
foreach (var file in files)
{
try
{
var creationTime = System.IO.File.GetCreationTime(file);
if (creationTime < DateTime.Now.AddMinutes(-5))
{
System.IO.File.Delete(file);
deletedFiles.Add(file);
}
}
catch (Exception ex)
{
Console.WriteLine($"Error deleting file {file}: {ex.Message}");
}
}
}
else
{
return NotFound("Uploads folder not found.");
}
if (Directory.Exists(_processedFolder))
{
var files = Directory.GetFiles(_processedFolder);
var deletedFiles = new List();
foreach (var file in files)
{
try
{
var creationTime = System.IO.File.GetCreationTime(file);
if (creationTime < DateTime.Now.AddMinutes(-5))
{
System.IO.File.Delete(file);
deletedFiles.Add(file);
}
}
catch (Exception ex)
{
Console.WriteLine($"Error deleting file {file}: {ex.Message}");
}
}
}
else
{
return NotFound("Processed folder not found.");
}
return Ok();
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
return StatusCode(500, "Internal server error.");
}
}
}
}
using ImageEffectApp.WorkerService.Models;
using Microsoft.Extensions.Options;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;
using System.Net.Http.Headers;
using System.Net.WebSockets;
using System.Text;
using System.Text.Json;
namespace ImageEffectApp.WorkerService.Processing
{
public class ImageProcessor : IImageProcessor
{
private readonly IHttpClientFactory _httpClientFactory;
private readonly string _uploadUrl;
private readonly string _webSocketUrl;
public ImageProcessor(IHttpClientFactory httpClientFactory, IOptions options)
{
_httpClientFactory = httpClientFactory;
_uploadUrl = options.Value.UploadUrl;
_webSocketUrl = options.Value.WebSocketUrl;
}
public async Task ProcessImageAsync(ImageProcessingRequest request, CancellationToken cancellationToken)
{
try
{
if (request is null)
{
throw new ArgumentNullException(nameof(request), "İstek nesnesi null olamaz!");
}
if (string.IsNullOrWhiteSpace(request.ImagePath) || string.IsNullOrWhiteSpace(request.OutputName))
{
throw new ArgumentException("Resim yolu veya çıktı adı boş olamaz!");
}
string localImagePath;
if (request.ImagePath.StartsWith("https", StringComparison.OrdinalIgnoreCase))
{
localImagePath = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.png");
using (var httpClient = _httpClientFactory.CreateClient())
using (var response = await httpClient.GetAsync(request.ImagePath, cancellationToken))
{
if (!response.IsSuccessStatusCode)
{
throw new HttpRequestException($"Resim indirme başarısız! HTTP {response.StatusCode}");
}
await using var fs = new FileStream(localImagePath, FileMode.Create, FileAccess.Write, FileShare.None);
await response.Content.CopyToAsync(fs);
}
}
else
{
localImagePath = request.ImagePath;
}
string fileName = string.IsNullOrWhiteSpace(request.OutputName) ? $"{Guid.NewGuid()}.png" : request.OutputName;
string tempOutputPath = Path.Combine(Path.GetTempPath(), fileName);
using (var image = await Image.LoadAsync(localImagePath, cancellationToken))
{
image.Mutate(x => x.Grayscale());
await image.SaveAsync(tempOutputPath, cancellationToken);
}
await UploadImageToServer(tempOutputPath, cancellationToken);
try
{
if (File.Exists(localImagePath)) File.Delete(localImagePath);
if (File.Exists(tempOutputPath)) File.Delete(tempOutputPath);
}
catch (Exception ex)
{
Console.WriteLine($"❌ Dosya silme hatası: {ex.Message}");
}
}
catch (Exception ex)
{
Console.WriteLine($"❌ Hata: {ex}");
throw;
}
}
public async Task UploadImageToServer(string filePath, CancellationToken cancellationToken)
{
try
{
if (!File.Exists(filePath))
{
Console.WriteLine($"Dosya bulunamadı: {filePath}");
return false;
}
using (var httpClient = _httpClientFactory.CreateClient())
using (var form = new MultipartFormDataContent())
using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
var fileContent = new StreamContent(fileStream);
fileContent.Headers.ContentType = new MediaTypeHeaderValue(GetMimeType(filePath));
form.Add(fileContent, "file", Path.GetFileName(filePath));
Console.WriteLine($"Resim yükleniyor: {filePath} -> {_uploadUrl}");
var response = await httpClient.PostAsync(_uploadUrl, form, cancellationToken);
await SendWebSocketNotification(Path.GetFileName(filePath));
return true;
}
}
catch (Exception ex)
{
Console.WriteLine($"Hata oluştu: {ex.Message}");
return false;
}
}
private async Task SendWebSocketNotification(string fileName)
{
try
{
using (var webSocket = new ClientWebSocket())
{
Uri serverUri = new Uri(_webSocketUrl);
await webSocket.ConnectAsync(serverUri, CancellationToken.None);
var notification = new
{
type = "image_processed",
imageId = fileName.Substring(0, fileName.LastIndexOf('.')),
outputPath = $"/processed/{fileName}",
timestamp = DateTime.UtcNow.ToString("o"),
success = true
};
string jsonMessage = JsonSerializer.Serialize(notification);
byte[] messageBytes = Encoding.UTF8.GetBytes(jsonMessage);
await webSocket.SendAsync(
new ArraySegment(messageBytes),
WebSocketMessageType.Text,
true,
CancellationToken.None
);
await webSocket.CloseAsync(
WebSocketCloseStatus.NormalClosure,
"Notification sent",
CancellationToken.None
);
Console.WriteLine($"WebSocket bildirimi gönderildi: Image ID {fileName}");
}
}
catch (Exception ex)
{
Console.WriteLine($"WebSocket bildirimi gönderilemedi: {ex.Message}");
}
}
private string GetMimeType(string filePath)
{
string extension = Path.GetExtension(filePath).ToLowerInvariant();
return extension switch
{
".jpg" or ".jpeg" => "image/jpeg",
".png" => "image/png",
".gif" => "image/gif",
".bmp" => "image/bmp",
".tiff" => "image/tiff",
_ => "application/octet-stream"
};
}
}
}