mirror of
https://github.com/Govor-team/Govor.git
synced 2026-07-21 11:44:56 +00:00
client
This commit is contained in:
@@ -21,7 +21,7 @@ public class FriendsController : Controller
|
||||
_friendsService = friendsService;
|
||||
}
|
||||
|
||||
[HttpGet("search")]
|
||||
[HttpGet("search")] //api/friends/search
|
||||
public async Task<IActionResult> Search(string query)
|
||||
{
|
||||
try
|
||||
@@ -37,7 +37,7 @@ public class FriendsController : Controller
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost("request")]
|
||||
[HttpPost("request")] //api/friends/request
|
||||
public async Task<IActionResult> SendRequest(Guid targetUserId)
|
||||
{
|
||||
try
|
||||
@@ -62,7 +62,7 @@ public class FriendsController : Controller
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet("requests")]
|
||||
[HttpGet("requests")] //api/friends/requests
|
||||
public async Task<IActionResult> GetIncomingRequests()
|
||||
{
|
||||
try
|
||||
@@ -78,7 +78,7 @@ public class FriendsController : Controller
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost("accept")]
|
||||
[HttpPost("accept")] //api/friends/accept
|
||||
public async Task<IActionResult> AcceptFriend(Guid requesterId)
|
||||
{
|
||||
try
|
||||
@@ -98,7 +98,7 @@ public class FriendsController : Controller
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[HttpGet] //api/friends/
|
||||
public async Task<IActionResult> GetFriends()
|
||||
{
|
||||
try
|
||||
|
||||
@@ -58,11 +58,6 @@ public class ChatsHub : Hub
|
||||
}
|
||||
|
||||
var senderId = GetUserId();
|
||||
if (senderId == Guid.Empty)
|
||||
{
|
||||
_logger.LogError("Could not retrieve sender userId");
|
||||
throw new InvalidOperationException("User not authenticated");
|
||||
}
|
||||
|
||||
// Проверка существования получателя
|
||||
try
|
||||
@@ -100,6 +95,7 @@ public class ChatsHub : Hub
|
||||
var userIdClaim = Context.User?.FindFirst("userID")?.Value;
|
||||
if (string.IsNullOrEmpty(userIdClaim) || !Guid.TryParse(userIdClaim, out var userId))
|
||||
{
|
||||
_logger.LogError("Could not retrieve sender userId");
|
||||
throw new UnauthorizedAccessException("userID claim is missing or invalid");
|
||||
}
|
||||
return userId;
|
||||
|
||||
@@ -59,6 +59,11 @@ builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
||||
builder.Services.AddAuthorization();
|
||||
|
||||
builder.Services.AddControllers();
|
||||
builder.Services.AddControllers()
|
||||
.AddJsonOptions(options =>
|
||||
{
|
||||
options.JsonSerializerOptions.ReferenceHandler = System.Text.Json.Serialization.ReferenceHandler.Preserve;
|
||||
});
|
||||
|
||||
// Init DI
|
||||
builder.Services.AddServices();
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Json;
|
||||
using Govor.Contracts.DTOs;
|
||||
|
||||
namespace Govor.ConsoleClient
|
||||
{
|
||||
public class FriendsClient
|
||||
{
|
||||
private readonly HttpClient _client;
|
||||
|
||||
public FriendsClient(HttpClient client)
|
||||
{
|
||||
_client = client;
|
||||
}
|
||||
|
||||
public async Task<List<UserDto>> SearchAsync(string query)
|
||||
{
|
||||
var response = await _client.GetAsync($"/api/friends/search?query={query}");
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
return await response.Content.ReadFromJsonAsync<List<UserDto>>() ?? new List<UserDto>();
|
||||
}
|
||||
|
||||
public async Task SendFriendRequestAsync(Guid targetUserId)
|
||||
{
|
||||
var response = await _client.PostAsync($"api/friends/request?targetUserId={targetUserId}", null);
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
|
||||
public async Task<List<FriendshipDto>> GetIncomingRequestsAsync()
|
||||
{
|
||||
var response = await _client.GetAsync("/api/friends/requests");
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
return await response.Content.ReadFromJsonAsync<List<FriendshipDto>>() ?? new List<FriendshipDto>();
|
||||
}
|
||||
|
||||
public async Task AcceptFriendRequestAsync(Guid requesterId)
|
||||
{
|
||||
var content = JsonContent.Create(requesterId);
|
||||
var response = await _client.PostAsync("/api/friends/accept", content);
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
|
||||
public async Task<List<UserDto>> GetFriendsAsync()
|
||||
{
|
||||
var response = await _client.GetAsync("/api/friends");
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
return await response.Content.ReadFromJsonAsync<List<UserDto>>() ?? new List<UserDto>();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using Govor.Contracts.Requests;
|
||||
|
||||
namespace Govor.ConsoleClient
|
||||
{
|
||||
public class HttpClientService
|
||||
{
|
||||
private readonly HttpClient _client;
|
||||
|
||||
public HttpClientService(string baseUrl)
|
||||
{
|
||||
_client = new HttpClient
|
||||
{
|
||||
BaseAddress = new Uri(baseUrl)
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<string> RegisterAsync(string username, string password, string inviteCode)
|
||||
{
|
||||
var request = new RegistrationRequest
|
||||
{
|
||||
Name = username,
|
||||
Password = password,
|
||||
InviteLink = inviteCode
|
||||
};
|
||||
|
||||
var response = await _client.PostAsJsonAsync("/api/auth/register", request);
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
var result = await response.Content.ReadFromJsonAsync<TokenResponse>();
|
||||
return result?.Token;
|
||||
}
|
||||
|
||||
var error = await response.Content.ReadAsStringAsync();
|
||||
throw new Exception($"Registration failed: {error}");
|
||||
}
|
||||
|
||||
public async Task<string> LoginAsync(string username, string password)
|
||||
{
|
||||
var request = new LoginRequest
|
||||
{
|
||||
Name = username,
|
||||
Password = password
|
||||
};
|
||||
|
||||
var response = await _client.PostAsJsonAsync("/api/auth/login", request);
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
var result = await response.Content.ReadFromJsonAsync<TokenResponse>();
|
||||
return result?.Token;
|
||||
}
|
||||
|
||||
var error = await response.Content.ReadAsStringAsync();
|
||||
throw new Exception($"Login failed: {error}");
|
||||
}
|
||||
}
|
||||
|
||||
public class TokenResponse
|
||||
{
|
||||
public string Token { get; set; }
|
||||
}
|
||||
}
|
||||
+168
-141
@@ -1,187 +1,214 @@
|
||||
using Microsoft.AspNetCore.SignalR.Client;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
using Govor.Contracts.Requests;
|
||||
|
||||
|
||||
/*====================================
|
||||
*Горелые Петушки Чат
|
||||
*Личные сообщения| Егор
|
||||
*====================================
|
||||
* [15:59] Вы добавили (Егор) в друзья
|
||||
*
|
||||
* [16:30] Егор >> Привет!
|
||||
* [16:31] Ты >> Че как?
|
||||
*
|
||||
* [16:30] Егор >> Привет, Питухам!
|
||||
* [16:31] Anon >> Че как?
|
||||
* Я норм << [16:32]
|
||||
*------------------------------------
|
||||
* >> "Привет, Егор!"
|
||||
* >> "Пойдем завтра гулять?!"
|
||||
*/
|
||||
|
||||
class Program
|
||||
namespace Govor.ConsoleClient
|
||||
{
|
||||
private static HttpClient _httpClient = new HttpClient();
|
||||
private static HubConnection _hubConnection;
|
||||
private static string _jwtToken;
|
||||
private static Guid _userId;
|
||||
private static Guid _toUserId;
|
||||
|
||||
static async Task Main(string[] args)
|
||||
class Program
|
||||
{
|
||||
Console.WriteLine("Welcome to the Chat Client!");
|
||||
Console.WriteLine("Enter your username:");
|
||||
string username = Console.ReadLine();
|
||||
Console.WriteLine("Enter your password:");
|
||||
string password = Console.ReadLine();
|
||||
static string? AuthToken = null;
|
||||
static HttpClientService HttpService = new("https://localhost:7155"); // поменяй URL на свой
|
||||
private static FriendsClient friendsClient;
|
||||
static Dictionary<string, List<string>> ChatHistory = new();
|
||||
static string CurrentChatUser = null;
|
||||
|
||||
// Аутентификация и получение JWT
|
||||
bool authenticated = await AuthenticateAsync(username, password);
|
||||
if (!authenticated)
|
||||
static async Task Main()
|
||||
{
|
||||
Console.WriteLine("Authentication failed. Exiting...");
|
||||
return;
|
||||
}
|
||||
|
||||
Console.Clear();
|
||||
|
||||
// Извлечение UserId из JWT
|
||||
_userId = ExtractUserIdFromJwt(_jwtToken);
|
||||
Console.WriteLine($"Authenticated successfully! Your UserId: {_userId}");
|
||||
|
||||
// Настройка SignalR
|
||||
await SetupSignalRAsync();
|
||||
|
||||
// Обработка команд
|
||||
Console.WriteLine("Enter command /chat {username} to send a chat message");
|
||||
Console.WriteLine("Enter commands in format: /send {message}, in chat {username}");
|
||||
Console.WriteLine("Type 'exit' to quit.");
|
||||
LoginWindow();
|
||||
|
||||
while (true)
|
||||
{
|
||||
string input = Console.ReadLine();
|
||||
if (input.ToLower() == "exit")
|
||||
Console.Write(CurrentChatUser == null ? "/> " : ">> ");
|
||||
var input = Console.ReadLine();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(input)) continue;
|
||||
|
||||
if (input.StartsWith("/"))
|
||||
HandleCommand(input);
|
||||
else if (CurrentChatUser != null)
|
||||
SendMessage(input);
|
||||
else
|
||||
Console.WriteLine("[Система] Введите команду, например /friends");
|
||||
}
|
||||
}
|
||||
|
||||
static async void HandleCommand(string input)
|
||||
{
|
||||
var args = input.Split(' ', 2);
|
||||
var command = args[0].ToLower();
|
||||
var argument = args.Length > 1 ? args[1] : null;
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case "/login":
|
||||
Console.Write("username: ");
|
||||
var loginUsername = Console.ReadLine();
|
||||
|
||||
Console.Write("password: ");
|
||||
var loginPassword = Console.ReadLine();
|
||||
|
||||
try
|
||||
{
|
||||
AuthToken = await HttpService.LoginAsync(loginUsername, loginPassword);
|
||||
HttpClient sharedClient = new();
|
||||
sharedClient.BaseAddress = new Uri("https://localhost:7155");
|
||||
sharedClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AuthToken);
|
||||
|
||||
friendsClient = new FriendsClient(sharedClient);
|
||||
Console.WriteLine("[Успех] Вход выполнен. Токен сохранен.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"[Ошибка] {ex.Message}");
|
||||
}
|
||||
break;
|
||||
case "/reg":
|
||||
Console.Write("username: ");
|
||||
var regUsername = Console.ReadLine();
|
||||
|
||||
Console.Write("password: ");
|
||||
var regPassword = Console.ReadLine();
|
||||
|
||||
Console.Write("invitation: ");
|
||||
var inviteCode = Console.ReadLine();
|
||||
|
||||
try
|
||||
{
|
||||
AuthToken = await HttpService.RegisterAsync(regUsername, regPassword, inviteCode);
|
||||
HttpClient sharedClient = new();
|
||||
sharedClient.BaseAddress = new Uri("https://localhost:7155");
|
||||
sharedClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AuthToken);
|
||||
|
||||
friendsClient = new FriendsClient(sharedClient);
|
||||
Console.WriteLine("[Успех] Регистрация завершена. Токен сохранен.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"[Ошибка] {ex.Message}");
|
||||
}
|
||||
break;
|
||||
case "/search":
|
||||
Console.Write("Введите имя друга: ");
|
||||
var q = Console.ReadLine();
|
||||
var foundUsers = await friendsClient.SearchAsync(q);
|
||||
foreach (var user in foundUsers)
|
||||
{
|
||||
Console.WriteLine($"{user.Username} [{user.Id}]");
|
||||
}
|
||||
break;
|
||||
|
||||
await ProcessCommandAsync(input);
|
||||
case "/exit":
|
||||
Console.WriteLine("[Система] Выход...");
|
||||
Environment.Exit(0);
|
||||
break;
|
||||
|
||||
case "/friends":
|
||||
var friends = await friendsClient.GetFriendsAsync();
|
||||
foreach (var f in friends)
|
||||
{
|
||||
Console.WriteLine($"{f.Username} | был онлайн: {f.WasOnline}");
|
||||
}
|
||||
break;
|
||||
case "/friend":
|
||||
Console.Write("Введите ID пользователя, которому хотите отправить запрос: ");
|
||||
var targetId = Guid.Parse(Console.ReadLine());
|
||||
await friendsClient.SendFriendRequestAsync(targetId);
|
||||
Console.WriteLine("Запрос отправлен");
|
||||
break;
|
||||
|
||||
case "/accept":
|
||||
Console.Write("Введите ID пользователя, чью заявку принимаете: ");
|
||||
var acceptId = Guid.Parse(Console.ReadLine());
|
||||
await friendsClient.AcceptFriendRequestAsync(acceptId);
|
||||
Console.WriteLine("Принято");
|
||||
break;
|
||||
case "/incoming":
|
||||
var requests = await friendsClient.GetIncomingRequestsAsync();
|
||||
foreach (var r in requests)
|
||||
{
|
||||
Console.WriteLine($"Запрос от: {r.RequesterId} (добавьте через /accept {r.RequesterId})");
|
||||
}
|
||||
break;
|
||||
case "/chat":
|
||||
if (string.IsNullOrEmpty(argument))
|
||||
{
|
||||
Console.WriteLine("[Ошибка] Укажите имя друга");
|
||||
break;
|
||||
}
|
||||
|
||||
// Отключение SignalR
|
||||
await _hubConnection.StopAsync();
|
||||
CurrentChatUser = argument;
|
||||
ShowChat(argument);
|
||||
break;
|
||||
|
||||
case "/back":
|
||||
CurrentChatUser = null;
|
||||
break;
|
||||
|
||||
default:
|
||||
Console.WriteLine("[Ошибка] Неизвестная команда");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<bool> AuthenticateAsync(string username, string password)
|
||||
static void ShowChat(string user)
|
||||
{
|
||||
try
|
||||
Console.Clear();
|
||||
Console.WriteLine($"/*====================================");
|
||||
Console.WriteLine($" * Личные сообщения | {user}");
|
||||
Console.WriteLine($" *====================================");
|
||||
|
||||
if (!ChatHistory.ContainsKey(user))
|
||||
{
|
||||
RegistrationRequest loginData = new RegistrationRequest()
|
||||
ChatHistory[user] = new List<string>
|
||||
{
|
||||
Name = username,
|
||||
Password = password
|
||||
$"[15:59] Вы добавили ({user}) в друзья",
|
||||
$"[16:30] {user} >> Привет!",
|
||||
$"[16:31] Ты >> Че как?"
|
||||
};
|
||||
|
||||
var response = await _httpClient.PostAsJsonAsync(
|
||||
"https://localhost:7155/api/Auth/login",
|
||||
loginData);
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
Console.WriteLine($"Login failed: {response.StatusCode}");
|
||||
return false;
|
||||
}
|
||||
|
||||
var json = await response.Content.ReadAsStringAsync();
|
||||
var tokenResponse = JsonSerializer.Deserialize<LoginResponse>(json, new JsonSerializerOptions
|
||||
{
|
||||
PropertyNameCaseInsensitive = true
|
||||
});
|
||||
foreach (var msg in ChatHistory[user])
|
||||
Console.WriteLine(" * " + msg);
|
||||
|
||||
_jwtToken = tokenResponse.token;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Authentication error: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
Console.WriteLine(" *------------------------------------");
|
||||
}
|
||||
|
||||
private static Guid ExtractUserIdFromJwt(string jwtToken)
|
||||
static void SendMessage(string message)
|
||||
{
|
||||
try
|
||||
{
|
||||
var handler = new JwtSecurityTokenHandler();
|
||||
var token = handler.ReadJwtToken(jwtToken);
|
||||
var userIdClaim = token.Claims.FirstOrDefault(c => c.Type == "sub" || c.Type == "userID")?.Value;
|
||||
return Guid.TryParse(userIdClaim, out Guid userId) ? userId : Guid.Empty;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error extracting UserId: {ex.Message}");
|
||||
return Guid.Empty;
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(message)) return;
|
||||
|
||||
ChatHistory[CurrentChatUser].Add($"Ты >> {message}");
|
||||
Console.WriteLine($">> {message}");
|
||||
}
|
||||
|
||||
private static async Task SetupSignalRAsync()
|
||||
static void LoginWindow()
|
||||
{
|
||||
_hubConnection = new HubConnectionBuilder()
|
||||
.WithUrl("https://localhost:7155/api/chats", options =>
|
||||
{
|
||||
options.AccessTokenProvider = () => Task.FromResult(_jwtToken);
|
||||
})
|
||||
.WithAutomaticReconnect()
|
||||
.Build();
|
||||
|
||||
_hubConnection.On<string, Guid>("Receive", (message, senderId) =>
|
||||
{
|
||||
Console.WriteLine($"[{DateTime.Now}] From {senderId}: {message}");
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
await _hubConnection.StartAsync();
|
||||
Console.WriteLine("Connected to SignalR hub.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"SignalR connection error: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task ProcessCommandAsync(string input)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(input))
|
||||
return;
|
||||
|
||||
var parts = input.Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
||||
if (parts.Length < 3 || parts[0].ToLower() != "/send")
|
||||
{
|
||||
Console.WriteLine("Invalid command. Use: /send {toUserId} {message}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Guid.TryParse(parts[1], out Guid toUserId))
|
||||
{
|
||||
Console.WriteLine("Invalid toUserId format. Must be a valid Guid.");
|
||||
return;
|
||||
}
|
||||
|
||||
string message = string.Join(" ", parts[2..]);
|
||||
if (string.IsNullOrWhiteSpace(message))
|
||||
{
|
||||
Console.WriteLine("Message cannot be empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await _hubConnection.InvokeAsync("Send", message, toUserId);
|
||||
Console.WriteLine($"Message sent to {toUserId}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error sending message: {ex.Message}");
|
||||
Console.WriteLine($"/*====================================");
|
||||
Console.WriteLine($" * Добро пожаловать в Govor!");
|
||||
Console.WriteLine($" *====================================");
|
||||
Console.WriteLine(" * /reg - создать аккаунт ");
|
||||
Console.WriteLine(" * /login - войти");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class LoginResponse
|
||||
{
|
||||
public string token { get; set; }
|
||||
|
||||
Reference in New Issue
Block a user