diff --git a/Govor.API/Hubs/ChatsHub.cs b/Govor.API/Hubs/ChatsHub.cs index 737db0f..aad3501 100644 --- a/Govor.API/Hubs/ChatsHub.cs +++ b/Govor.API/Hubs/ChatsHub.cs @@ -159,7 +159,7 @@ public class ChatsHub : Hub private Guid GetUserId(bool suppressException = false) { - var userIdClaim = Context.User?.FindFirst("userID")?.Value; + var userIdClaim = Context.User?.FindFirst("userId")?.Value; if (string.IsNullOrEmpty(userIdClaim) || !Guid.TryParse(userIdClaim, out var userId)) { if (!suppressException) diff --git a/Govor.Console/Program.cs b/Govor.Console/Program.cs index 2f77dc7..e804006 100644 --- a/Govor.Console/Program.cs +++ b/Govor.Console/Program.cs @@ -4,6 +4,9 @@ using System.Net.Http.Headers; using System.Net.Http.Json; using System.Text.Json; using Govor.Contracts.Requests; +using Govor.Contracts.Requests.SignalR; +using Govor.Contracts.Responses.SignalR; +using Govor.Core.Models; /*==================================== @@ -24,9 +27,11 @@ namespace Govor.ConsoleClient { static string? AuthToken = null; static HttpClientService HttpService = new("https://govor-team-govor-88b3.twc1.net"); // поменяй URL на свой - private static FriendsClient friendsClient; + private static FriendsClient? friendsClient; + static HubConnection? _hubConnection; static Dictionary> ChatHistory = new(); - static string CurrentChatUser = null; + static string? CurrentChatUser = null; + static Guid CurrentChatUserId = Guid.Empty; static async Task Main() { @@ -71,6 +76,7 @@ namespace Govor.ConsoleClient sharedClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AuthToken); friendsClient = new FriendsClient(sharedClient); + await InitializeHubConnection(); Console.WriteLine("[Успех] Вход выполнен. Токен сохранен."); } catch (Exception ex) @@ -96,6 +102,7 @@ namespace Govor.ConsoleClient sharedClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AuthToken); friendsClient = new FriendsClient(sharedClient); + await InitializeHubConnection(); Console.WriteLine("[Успех] Регистрация завершена. Токен сохранен."); } catch (Exception ex) @@ -104,6 +111,11 @@ namespace Govor.ConsoleClient } break; case "/search": + if (friendsClient == null) + { + Console.WriteLine("[Ошибка] Сначала войдите в систему."); + break; + } Console.Write("Введите имя друга: "); var q = Console.ReadLine(); var foundUsers = await friendsClient.SearchAsync(q); @@ -115,17 +127,32 @@ namespace Govor.ConsoleClient case "/exit": Console.WriteLine("[Система] Выход..."); + if (_hubConnection != null) + { + await _hubConnection.StopAsync(); + await _hubConnection.DisposeAsync(); + } Environment.Exit(0); break; case "/friends": + if (friendsClient == null) + { + Console.WriteLine("[Ошибка] Сначала войдите в систему."); + break; + } var friends = await friendsClient.GetFriendsAsync(); foreach (var f in friends) { - Console.WriteLine($"{f.Username} | был онлайн: {f.WasOnline}"); + Console.WriteLine($"{f.Username} | был онлайн: {f.WasOnline} [{f.Id}]"); } break; case "/friend": + if (friendsClient == null) + { + Console.WriteLine("[Ошибка] Сначала войдите в систему."); + break; + } Console.Write("Введите ID пользователя, которому хотите отправить запрос: "); var targetId = Guid.Parse(Console.ReadLine()); await friendsClient.SendFriendRequestAsync(targetId); @@ -133,12 +160,22 @@ namespace Govor.ConsoleClient break; case "/accept": + if (friendsClient == null) + { + Console.WriteLine("[Ошибка] Сначала войдите в систему."); + break; + } Console.Write("Введите ID пользователя, чью заявку принимаете: "); var acceptId = Guid.Parse(Console.ReadLine()); await friendsClient.AcceptFriendRequestAsync(acceptId); Console.WriteLine("Принято"); break; case "/incoming": + if (friendsClient == null) + { + Console.WriteLine("[Ошибка] Сначала войдите в систему."); + break; + } var requests = await friendsClient.GetIncomingRequestsAsync(); foreach (var r in requests) { @@ -148,16 +185,25 @@ namespace Govor.ConsoleClient case "/chat": if (string.IsNullOrEmpty(argument)) { - Console.WriteLine("[Ошибка] Укажите имя друга"); + Console.WriteLine("[Ошибка] Укажите имя друга и ID через пробел (например /chat Egor GUID)"); break; } - CurrentChatUser = argument; - ShowChat(argument); + var chatArgs = argument.Split(' ', 2); + if (chatArgs.Length < 2 || !Guid.TryParse(chatArgs[1], out var chatUserId)) + { + Console.WriteLine("[Ошибка] Неверный формат. Укажите имя друга и ID (например /chat Egor GUID)"); + break; + } + + CurrentChatUser = chatArgs[0]; + CurrentChatUserId = chatUserId; + ShowChat(CurrentChatUser); break; case "/back": CurrentChatUser = null; + CurrentChatUserId = Guid.Empty; break; default: @@ -166,21 +212,90 @@ namespace Govor.ConsoleClient } } + static async Task InitializeHubConnection() + { + if (string.IsNullOrEmpty(AuthToken)) + { + Console.WriteLine("[Ошибка] Токен аутентификации отсутствует. Пожалуйста, войдите в систему."); + return; + } + + _hubConnection = new HubConnectionBuilder() + .WithUrl("https://govor-team-govor-88b3.twc1.net/api/chats", options => + { + options.AccessTokenProvider = () => Task.FromResult(AuthToken); + }) + .Build(); + + _hubConnection.On("ReceiveMessage", (message) => + { + var senderName = message.SenderId == GetMyUserId() ? "Ты" : CurrentChatUser ?? "Неизвестно"; // Simplified for now + var displayMessage = $"[{message.SentAt:HH:mm}] {senderName} >> {message.EncryptedContent}"; + + string chatKey = message.SenderId == GetMyUserId() ? message.RecipientId.ToString() : message.SenderId.ToString(); + + if (CurrentChatUser != null && (message.SenderId == CurrentChatUserId || message.RecipientId == CurrentChatUserId)) + { + if (!ChatHistory.ContainsKey(CurrentChatUser)) + { + ChatHistory[CurrentChatUser] = new List(); + } + ChatHistory[CurrentChatUser].Add(displayMessage); + Console.SetCursorPosition(0, Console.CursorTop); // Move cursor to beginning of line + Console.Write(new string(' ', Console.WindowWidth -1)); // Clear current line + Console.SetCursorPosition(0, Console.CursorTop); + Console.WriteLine($" * {displayMessage}"); // Display new message + Console.Write(">> "); // Re-display prompt + } + else + { + // Handle notification for messages not in the current chat - TBD + Console.WriteLine($"\n[Новое сообщение от {message.SenderId}]: {message.EncryptedContent}"); + Console.Write(CurrentChatUser == null ? "/> " : ">> "); + } + }); + + _hubConnection.On("MessageSent", (message) => + { + // Optional: Handle confirmation that message was sent successfully by the server + // This could be useful for updating UI to show message status (e.g., "sent", "delivered") + // For console, just logging or ignoring might be fine. + // Console.WriteLine($"[Система] Сообщение {message.MessageId} доставлено на сервер."); + }); + + try + { + await _hubConnection.StartAsync(); + Console.WriteLine("[SignalR] Соединение установлено."); + } + catch (Exception ex) + { + Console.WriteLine($"[SignalR Ошибка] {ex.Message}"); + } + } + + static Guid GetMyUserId() + { + if (AuthToken == null) return Guid.Empty; + var handler = new JwtSecurityTokenHandler(); + var jwtToken = handler.ReadJwtToken(AuthToken); + var userIdClaim = jwtToken.Claims.FirstOrDefault(claim => claim.Type == "userId"); + return userIdClaim != null && Guid.TryParse(userIdClaim.Value, out var userId) ? userId : Guid.Empty; + } + + static void ShowChat(string user) { Console.Clear(); Console.WriteLine($"/*===================================="); - Console.WriteLine($" * Личные сообщения | {user}"); + Console.WriteLine($" * Личные сообщения | {user} ({CurrentChatUserId})"); Console.WriteLine($" *===================================="); if (!ChatHistory.ContainsKey(user)) { - ChatHistory[user] = new List - { - $"[15:59] Вы добавили ({user}) в друзья", - $"[16:30] {user} >> Привет!", - $"[16:31] Ты >> Че как?" - }; + ChatHistory[user] = new List(); + // Example initial messages - consider fetching history if implementing that + // ChatHistory[user].Add($"[Система] Начало чата с {user}"); } foreach (var msg in ChatHistory[user]) @@ -189,12 +304,43 @@ namespace Govor.ConsoleClient Console.WriteLine(" *------------------------------------"); } - static void SendMessage(string message) + static async void SendMessage(string messageContent) { - if (string.IsNullOrWhiteSpace(message)) return; + if (string.IsNullOrWhiteSpace(messageContent) || _hubConnection == null || CurrentChatUserId == Guid.Empty) return; - ChatHistory[CurrentChatUser].Add($"Ты >> {message}"); - Console.WriteLine($">> {message}"); + var myUserId = GetMyUserId(); + if (myUserId == Guid.Empty) + { + Console.WriteLine("[Ошибка] Не удалось определить ID пользователя. Попробуйте войти снова."); + return; + } + + var messageRequest = new MessageRequest + { + RecipientId = CurrentChatUserId, + EncryptedContent = messageContent, // Assuming content is not actually encrypted for console client simplicity for now + RecipientType = RecipientType.User, + // MediaAttachments and ReplyToMessageId can be added if needed + }; + + try + { + await _hubConnection.InvokeAsync("Send", messageRequest); + + // Add to local history immediately for responsiveness. + // Server will send "ReceiveMessage" to self as well if needed, or "MessageSent" for confirmation. + var displayMessage = $"[{DateTime.Now:HH:mm}] Ты >> {messageContent}"; + if (!ChatHistory.ContainsKey(CurrentChatUser!)) + { + ChatHistory[CurrentChatUser!] = new List(); + } + ChatHistory[CurrentChatUser!].Add(displayMessage); + // Console.WriteLine($"Ты >> {messageContent}"); // Already handled by input echo + ReceiveMessage from self + } + catch (Exception ex) + { + Console.WriteLine($"[Ошибка отправки] {ex.Message}"); + } } static void LoginWindow()