/
egopen
/
Lab1
Обзор
Документация
Войти
/
egopen
/
Lab1
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
Lab4/library/BackWorkers/BooksWorker.cs
375 строк
17 KB
Egopen
lab 4
01 ноя 2025, 18:03
01 ноя 2025, 18:03
78d017c
Код
Авторство
О чём код?
using library.DB.Models; using library.QueueMessages; using library.Services; using RabbitMQ.Client; using RabbitMQ.Client.Events; using System.Security.Claims; using System.Text; using System.Text.Json; namespace library.BackWorkers { public class BooksWorker : IHostedService { private readonly TokenService _tokenService; readonly IConnection _conn; IServiceProvider _serviceProvider; IChannel _channel; delegate Task<byte[]> Handler(byte[] body, IReadOnlyBasicProperties props); Dictionary<string, Handler> _handlers; private readonly ILogger<BooksWorker> _log; public BooksWorker(IConnection connection, IServiceProvider serviceProvider, TokenService tokenService, ILogger<BooksWorker> log) { _conn = connection; _serviceProvider = serviceProvider; _tokenService = tokenService; _log = log; _handlers = new Dictionary<string, Handler> { ["get_book.request"] = ProcessGetBook, ["get_books.request"] = ProcessGetBooks, ["add_book.request"] = ProcessAddBook, ["delete_book.request"] = ProcessDeleteBook, ["get_author.request"] = ProcessGetAuthor, ["add_author.request"] = ProcessAddAuthor, ["delete_author.request"] = ProcessDeleteAuthor, ["update_book.request"] = ProcessUpdateBook }; _log = log; } public async Task StartAsync(CancellationToken token) { _channel = await _conn.CreateChannelAsync(); await _channel.ExchangeDeclareAsync("Books", ExchangeType.Direct); foreach (var queue in _handlers.Keys) { await _channel.QueueDeclareAsync(queue, durable: true, exclusive: false, autoDelete: false); await _channel.QueueBindAsync($"books.{queue.Replace(".request", "")}", "Books", queue); } await ExecuteAsync(token); } public async Task ExecuteAsync(CancellationToken token) { try { var consumer = new AsyncEventingBasicConsumer(_channel); consumer.ReceivedAsync += async (ch, ea) => { var body = ea.Body.ToArray(); var res = await _handlers[ea.RoutingKey](body, ea.BasicProperties); await _channel.BasicAckAsync(ea.DeliveryTag, false); var props = new BasicProperties(); props.ContentType = "application/json"; props.DeliveryMode = DeliveryModes.Persistent; await _channel.BasicPublishAsync("Books", ea.RoutingKey.Replace(".request", ".response"), true, props, res); }; foreach (var queue in _handlers.Keys) { await _channel.BasicConsumeAsync($"books.{queue.Replace(".request", "")}", autoAck: false, consumer); } } catch (Exception ex) { _log.LogError(ex.ToString()); } } public async Task StopAsync(CancellationToken token) { await _channel.CloseAsync(); await _channel.DisposeAsync(); } private async Task<byte[]> ProcessGetBook(byte[] body, IReadOnlyBasicProperties props) { using var scope = _serviceProvider.CreateScope(); var bookService = scope.ServiceProvider.GetRequiredService<BookManagingService>(); var jsonString = Encoding.UTF8.GetString(body); var req = JsonSerializer.Deserialize<BaseMessage>(jsonString); if (req?.Data == null) return ErrorResponse("Invalid request"); var payload = JsonSerializer.Deserialize<GetBookPayload>(req.Data.ToString()); if (payload?.BookId == null) return ErrorResponse("Invalid payload"); var book = await bookService.GetBook(payload.BookId.Value); if (req.Version == "v2") { var response = new { book.Id, book.Title, book.CreationDate, book.AuthorId, Links = new { Self = $"/api/v2/books/{book.Id}", Author = $"/api/v2/books/authors/{book.AuthorId}" } }; return Encoding.UTF8.GetBytes(JsonSerializer.Serialize(response)); } else { return Encoding.UTF8.GetBytes(JsonSerializer.Serialize(book)); } } private async Task<byte[]> ProcessGetBooks(byte[] body, IReadOnlyBasicProperties props) { using var scope = _serviceProvider.CreateScope(); var bookService = scope.ServiceProvider.GetRequiredService<BookManagingService>(); var jsonString = Encoding.UTF8.GetString(body); var req = JsonSerializer.Deserialize<BaseMessage>(jsonString); if (req?.Data == null) return ErrorResponse("Invalid request"); var payload = JsonSerializer.Deserialize<GetBooksPayload>(req.Data.ToString()); if (payload?.Page < 1) return ErrorResponse("Invalid page"); List<Book> books; if (payload.AuthorId.HasValue) { books = await bookService.GetBooksByAuthor(payload.AuthorId.Value, payload.Page); } else { books = await bookService.GetBooks(payload.Page, payload.PageSize, payload.WithAuthor); } if (req.Version == "v2") { var response = new { Data = books, Pagination = new { CurrentPage = payload.Page, PageSize = payload.PageSize, }, Links = new { Self = $"/api/v2/books?page={payload.Page}&pageSize={payload.PageSize}&authorId={payload.AuthorId}" } }; return Encoding.UTF8.GetBytes(JsonSerializer.Serialize(response)); } else { var response = new { page = payload.Page, books = books }; return Encoding.UTF8.GetBytes(JsonSerializer.Serialize(response)); } } private async Task<byte[]> ProcessAddBook(byte[] body, IReadOnlyBasicProperties props) { using var scope = _serviceProvider.CreateScope(); var bookService = scope.ServiceProvider.GetRequiredService<BookManagingService>(); var jsonString = Encoding.UTF8.GetString(body); var req = JsonSerializer.Deserialize<BaseMessage>(jsonString); if (req?.Data == null) return ErrorResponse("Invalid request"); if (req.AuthKey == null) return ErrorResponse("Auth required"); var claims = _tokenService.GetClaimsFromExpiredToken(req.AuthKey); var role = claims.FirstOrDefault(c => c.Type == "role"); if (role?.Value != "Admin" && role?.Value != "Moderator") return ErrorResponse("Not authorized"); Book book; if (req.Version == "v2") { var payload = JsonSerializer.Deserialize<AddBookPayloadV2>(req.Data.ToString()); if (payload?.AuthorId == null || payload?.Title == null) return ErrorResponse("Invalid payload"); book = await bookService.AddBook(payload.AuthorId.Value, payload.Title, payload.CreationDate); var response = new { book.Id, book.Title, book.CreationDate, book.AuthorId, Message = "Book created successfully", Links = new { Self = $"/api/v2/books/{book.Id}", Collection = "/api/v2/books" } }; return Encoding.UTF8.GetBytes(JsonSerializer.Serialize(response)); } else { var payload = JsonSerializer.Deserialize<AddBookPayload>(req.Data.ToString()); if (payload?.AuthorId == null || payload?.Title == null) return ErrorResponse("Invalid payload"); book = await bookService.AddBook(payload.AuthorId.Value, payload.Title, payload.CreationDate); return Encoding.UTF8.GetBytes(JsonSerializer.Serialize(book)); } } private async Task<byte[]> ProcessDeleteBook(byte[] body, IReadOnlyBasicProperties props) { using var scope = _serviceProvider.CreateScope(); var bookService = scope.ServiceProvider.GetRequiredService<BookManagingService>(); var jsonString = Encoding.UTF8.GetString(body); var req = JsonSerializer.Deserialize<BaseMessage>(jsonString); if (req?.Data == null) return ErrorResponse("Invalid request"); if (req.AuthKey == null) return ErrorResponse("Auth required"); var claims = _tokenService.GetClaimsFromExpiredToken(req.AuthKey); var role = claims.FirstOrDefault(c => c.Type == "role"); if (role?.Value != "Admin" && role?.Value != "Moderator") return ErrorResponse("Not authorized"); var payload = JsonSerializer.Deserialize<DeleteBookPayload>(req.Data.ToString()); if (payload?.BookId == null) return ErrorResponse("Invalid payload"); await bookService.DeleteBook(payload.BookId.Value); if (req.Version == "v2") { var response = new { message = "Book deleted successfully", bookId = payload.BookId, deletedAt = DateTime.UtcNow }; return Encoding.UTF8.GetBytes(JsonSerializer.Serialize(response)); } else { var response = new { message = "Book deleted successfully" }; return Encoding.UTF8.GetBytes(JsonSerializer.Serialize(response)); } } private async Task<byte[]> ProcessGetAuthor(byte[] body, IReadOnlyBasicProperties props) { using var scope = _serviceProvider.CreateScope(); var bookService = scope.ServiceProvider.GetRequiredService<BookManagingService>(); var jsonString = Encoding.UTF8.GetString(body); var req = JsonSerializer.Deserialize<BaseMessage>(jsonString); if (req?.Data == null) return ErrorResponse("Invalid request"); var payload = JsonSerializer.Deserialize<GetAuthorPayload>(req.Data.ToString()); if (payload?.AuthorId == null) return ErrorResponse("Invalid payload"); var author = await bookService.GetAuthor(payload.AuthorId.Value); return Encoding.UTF8.GetBytes(JsonSerializer.Serialize(author)); } private async Task<byte[]> ProcessAddAuthor(byte[] body, IReadOnlyBasicProperties props) { using var scope = _serviceProvider.CreateScope(); var bookService = scope.ServiceProvider.GetRequiredService<BookManagingService>(); var jsonString = Encoding.UTF8.GetString(body); var req = JsonSerializer.Deserialize<BaseMessage>(jsonString); if (req?.Data == null) return ErrorResponse("Invalid request"); if (req.AuthKey == null) return ErrorResponse("Auth required"); var claims = _tokenService.GetClaimsFromExpiredToken(req.AuthKey); var role = claims.FirstOrDefault(c => c.Type == "role"); if (role?.Value != "Admin" && role?.Value != "Moderator") return ErrorResponse("Not authorized"); var payload = JsonSerializer.Deserialize<AddAuthorPayload>(req.Data.ToString()); if (payload?.Name == null) return ErrorResponse("Invalid payload"); var author = await bookService.AddAuthor(payload.Name, payload.BirthDate); return Encoding.UTF8.GetBytes(JsonSerializer.Serialize(author)); } private async Task<byte[]> ProcessDeleteAuthor(byte[] body, IReadOnlyBasicProperties props) { using var scope = _serviceProvider.CreateScope(); var bookService = scope.ServiceProvider.GetRequiredService<BookManagingService>(); var jsonString = Encoding.UTF8.GetString(body); var req = JsonSerializer.Deserialize<BaseMessage>(jsonString); if (req?.Data == null) return ErrorResponse("Invalid request"); if (req.AuthKey == null) return ErrorResponse("Auth required"); var claims = _tokenService.GetClaimsFromExpiredToken(req.AuthKey); var role = claims.FirstOrDefault(c => c.Type == "role"); if (role?.Value != "Admin") return ErrorResponse("Not authorized"); var payload = JsonSerializer.Deserialize<DeleteAuthorPayload>(req.Data.ToString()); if (payload?.AuthorId == null) return ErrorResponse("Invalid payload"); await bookService.DeleteAuthor(payload.AuthorId.Value); var response = new { message = "Author deleted successfully" }; return Encoding.UTF8.GetBytes(JsonSerializer.Serialize(response)); } private async Task<byte[]> ProcessUpdateBook(byte[] body, IReadOnlyBasicProperties props) { using var scope = _serviceProvider.CreateScope(); var bookService = scope.ServiceProvider.GetRequiredService<BookManagingService>(); var jsonString = Encoding.UTF8.GetString(body); var req = JsonSerializer.Deserialize<BaseMessage>(jsonString); if (req?.Data == null) return ErrorResponse("Invalid request"); if (req.AuthKey == null) return ErrorResponse("Auth required"); var claims = _tokenService.GetClaimsFromExpiredToken(req.AuthKey); var role = claims.FirstOrDefault(c => c.Type == "role"); if (role?.Value != "Admin" && role?.Value != "Moderator") return ErrorResponse("Not authorized"); var payload = JsonSerializer.Deserialize<UpdateBookPayload>(req.Data.ToString()); if (payload?.BookId == null) return ErrorResponse("Invalid payload"); var updateDto = new library.DTO.UpdateBookDTO { Id = payload.BookId.Value, Title = payload.Title, AuthorId = payload.AuthorId, CreationDate = payload.CreationDate }; var book = await bookService.UpdateBook(updateDto); if (req.Version == "v2") { var response = new { book.Id, book.Title, book.CreationDate, book.AuthorId, Message = "Book updated successfully" }; return Encoding.UTF8.GetBytes(JsonSerializer.Serialize(response)); } else { return Encoding.UTF8.GetBytes(JsonSerializer.Serialize(book)); } } private byte[] ErrorResponse(string message) { var error = new { error = message }; return Encoding.UTF8.GetBytes(JsonSerializer.Serialize(error)); } private class GetBookPayload { public Guid? BookId { get; set; } } private class GetBooksPayload { public int Page { get; set; } = 1; public int PageSize { get; set; } = 20; public bool WithAuthor { get; set; } public Guid? AuthorId { get; set; } } private class AddBookPayload { public Guid? AuthorId { get; set; } public string Title { get; set; } public DateTime CreationDate { get; set; } } private class AddBookPayloadV2 { public Guid? AuthorId { get; set; } public string Title { get; set; } public DateTime CreationDate { get; set; } } private class DeleteBookPayload { public Guid? BookId { get; set; } } private class GetAuthorPayload { public Guid? AuthorId { get; set; } } private class AddAuthorPayload { public string Name { get; set; } public DateTime BirthDate { get; set; } } private class DeleteAuthorPayload { public Guid? AuthorId { get; set; } } private class UpdateBookPayload { public Guid? BookId { get; set; } public string Title { get; set; } public Guid? AuthorId { get; set; } public DateTime? CreationDate { get; set; } } } }