This commit is contained in:
Artemy
2025-06-27 21:50:23 +07:00
parent 05298c004c
commit 26dc4ccc1f
6 changed files with 302 additions and 155 deletions
+5 -5
View File
@@ -21,7 +21,7 @@ public class FriendsController : Controller
_friendsService = friendsService; _friendsService = friendsService;
} }
[HttpGet("search")] [HttpGet("search")] //api/friends/search
public async Task<IActionResult> Search(string query) public async Task<IActionResult> Search(string query)
{ {
try try
@@ -37,7 +37,7 @@ public class FriendsController : Controller
} }
} }
[HttpPost("request")] [HttpPost("request")] //api/friends/request
public async Task<IActionResult> SendRequest(Guid targetUserId) public async Task<IActionResult> SendRequest(Guid targetUserId)
{ {
try try
@@ -62,7 +62,7 @@ public class FriendsController : Controller
} }
} }
[HttpGet("requests")] [HttpGet("requests")] //api/friends/requests
public async Task<IActionResult> GetIncomingRequests() public async Task<IActionResult> GetIncomingRequests()
{ {
try try
@@ -78,7 +78,7 @@ public class FriendsController : Controller
} }
} }
[HttpPost("accept")] [HttpPost("accept")] //api/friends/accept
public async Task<IActionResult> AcceptFriend(Guid requesterId) public async Task<IActionResult> AcceptFriend(Guid requesterId)
{ {
try try
@@ -98,7 +98,7 @@ public class FriendsController : Controller
} }
} }
[HttpGet] [HttpGet] //api/friends/
public async Task<IActionResult> GetFriends() public async Task<IActionResult> GetFriends()
{ {
try try
+1 -5
View File
@@ -58,11 +58,6 @@ public class ChatsHub : Hub
} }
var senderId = GetUserId(); var senderId = GetUserId();
if (senderId == Guid.Empty)
{
_logger.LogError("Could not retrieve sender userId");
throw new InvalidOperationException("User not authenticated");
}
// Проверка существования получателя // Проверка существования получателя
try try
@@ -100,6 +95,7 @@ public class ChatsHub : Hub
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 (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"); throw new UnauthorizedAccessException("userID claim is missing or invalid");
} }
return userId; return userId;
+5
View File
@@ -59,6 +59,11 @@ builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
builder.Services.AddAuthorization(); builder.Services.AddAuthorization();
builder.Services.AddControllers(); builder.Services.AddControllers();
builder.Services.AddControllers()
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.ReferenceHandler = System.Text.Json.Serialization.ReferenceHandler.Preserve;
});
// Init DI // Init DI
builder.Services.AddServices(); builder.Services.AddServices();
+54
View File
@@ -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>();
}
}
}
+65
View File
@@ -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; }
}
}
+172 -145
View File
@@ -1,187 +1,214 @@
using Microsoft.AspNetCore.SignalR.Client; using Microsoft.AspNetCore.SignalR.Client;
using System.IdentityModel.Tokens.Jwt; using System.IdentityModel.Tokens.Jwt;
using System.Net.Http.Headers;
using System.Net.Http.Json; using System.Net.Http.Json;
using System.Text.Json; using System.Text.Json;
using Govor.Contracts.Requests; 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(); class Program
private static HubConnection _hubConnection;
private static string _jwtToken;
private static Guid _userId;
private static Guid _toUserId;
static async Task Main(string[] args)
{ {
Console.WriteLine("Welcome to the Chat Client!"); static string? AuthToken = null;
Console.WriteLine("Enter your username:"); static HttpClientService HttpService = new("https://localhost:7155"); // поменяй URL на свой
string username = Console.ReadLine(); private static FriendsClient friendsClient;
Console.WriteLine("Enter your password:"); static Dictionary<string, List<string>> ChatHistory = new();
string password = Console.ReadLine(); static string CurrentChatUser = null;
// Аутентификация и получение JWT static async Task Main()
bool authenticated = await AuthenticateAsync(username, password);
if (!authenticated)
{ {
Console.WriteLine("Authentication failed. Exiting..."); LoginWindow();
return;
while (true)
{
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");
}
} }
Console.Clear(); static async void HandleCommand(string input)
// Извлечение 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.");
while (true)
{ {
string input = Console.ReadLine(); var args = input.Split(' ', 2);
if (input.ToLower() == "exit") var command = args[0].ToLower();
break; var argument = args.Length > 1 ? args[1] : null;
await ProcessCommandAsync(input); 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;
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;
}
CurrentChatUser = argument;
ShowChat(argument);
break;
case "/back":
CurrentChatUser = null;
break;
default:
Console.WriteLine("[Ошибка] Неизвестная команда");
break;
}
} }
// Отключение SignalR static void ShowChat(string user)
await _hubConnection.StopAsync();
}
private static async Task<bool> AuthenticateAsync(string username, string password)
{
try
{ {
RegistrationRequest loginData = new RegistrationRequest() Console.Clear();
{ Console.WriteLine($"/*====================================");
Name = username, Console.WriteLine($" * Личные сообщения | {user}");
Password = password Console.WriteLine($" *====================================");
};
var response = await _httpClient.PostAsJsonAsync( if (!ChatHistory.ContainsKey(user))
"https://localhost:7155/api/Auth/login",
loginData);
if (!response.IsSuccessStatusCode)
{ {
Console.WriteLine($"Login failed: {response.StatusCode}"); ChatHistory[user] = new List<string>
return false; {
$"[15:59] Вы добавили ({user}) в друзья",
$"[16:30] {user} >> Привет!",
$"[16:31] Ты >> Че как?"
};
} }
var json = await response.Content.ReadAsStringAsync(); foreach (var msg in ChatHistory[user])
var tokenResponse = JsonSerializer.Deserialize<LoginResponse>(json, new JsonSerializerOptions Console.WriteLine(" * " + msg);
{
PropertyNameCaseInsensitive = true
});
_jwtToken = tokenResponse.token; Console.WriteLine(" *------------------------------------");
return true;
}
catch (Exception ex)
{
Console.WriteLine($"Authentication error: {ex.Message}");
return false;
}
}
private static Guid ExtractUserIdFromJwt(string jwtToken)
{
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;
}
}
private static async Task SetupSignalRAsync()
{
_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)) static void SendMessage(string message)
{ {
Console.WriteLine("Invalid toUserId format. Must be a valid Guid."); if (string.IsNullOrWhiteSpace(message)) return;
return;
ChatHistory[CurrentChatUser].Add($"Ты >> {message}");
Console.WriteLine($">> {message}");
} }
string message = string.Join(" ", parts[2..]); static void LoginWindow()
if (string.IsNullOrWhiteSpace(message))
{ {
Console.WriteLine("Message cannot be empty."); Console.WriteLine($"/*====================================");
return; Console.WriteLine($" * Добро пожаловать в Govor!");
} Console.WriteLine($" *====================================");
Console.WriteLine(" * /reg - создать аккаунт ");
try Console.WriteLine(" * /login - войти");
{
await _hubConnection.InvokeAsync("Send", message, toUserId);
Console.WriteLine($"Message sent to {toUserId}");
}
catch (Exception ex)
{
Console.WriteLine($"Error sending message: {ex.Message}");
} }
} }
} }
public class LoginResponse public class LoginResponse
{ {
public string token { get; set; } public string token { get; set; }