using QtCNETAPI.Dtos.Room; using QtCNETAPI.Dtos.User; using QtCNETAPI.Models; using RestSharp; using System.IdentityModel.Tokens.Jwt; using System.Resources; using System.Text.Json; namespace QtCNETAPI.Services.ApiService { public class ApiService : IApiService { private User? user; private RestClient _client; internal string? sessionToken; internal string apiUri; public string? SessionToken { get { return sessionToken; } set { sessionToken = value; } } public User? CurrentUser { get { return user; } } public ApiService(string apiUrl) { apiUri = apiUrl; _client = new RestClient(apiUri); } public async Task> PingServerAsync() { var serviceResponse = new ServiceResponse(); try { var request = new RestRequest("general/ping"); var response = await _client.GetAsync(request); if (response != null) { if (response != "Pong!") serviceResponse.Success = false; else serviceResponse.Success = true; } else serviceResponse.Success = false; } catch (HttpRequestException ex) { serviceResponse.Success = false; serviceResponse.Message = ex.Message; } return serviceResponse; } public async Task>> GetAllUsersAsync() { await RefreshSessionIfInvalid(); var serviceResponse = new ServiceResponse>(); if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made."); var request = new RestRequest("users/all") .AddHeader("Authorization", $"Bearer {SessionToken}"); var response = await _client.GetAsync>>(request); if (response != null || response!.Data != null) { serviceResponse.Success = true; serviceResponse.Data = response.Data; } else { serviceResponse.Success = false; serviceResponse.Message = "API didn't respond with users."; } return serviceResponse; } public async Task>> GetOnlineUsersAsync() { await RefreshSessionIfInvalid(); var serviceResponse = new ServiceResponse>(); if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made."); var request = new RestRequest("users/users-online") .AddHeader("Authorization", $"Bearer {SessionToken}"); var response = await _client.GetAsync>>(request); if (response != null || response!.Data != null) { serviceResponse.Success = true; serviceResponse.Data = response.Data; } else { serviceResponse.Success = false; serviceResponse.Message = "API didn't respond with online users."; } return serviceResponse; } public async Task> GetUserInformationAsync(string id) { await RefreshSessionIfInvalid(); var serviceResponse = new ServiceResponse(); if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made."); var request = new RestRequest($"users/user-info") .AddHeader("Authorization", $"Bearer {SessionToken}") .AddQueryParameter("id", id); var response = await _client.GetAsync>(request); if(response != null || response!.Data != null) { serviceResponse.Success = true; serviceResponse.Data = response.Data; } else { serviceResponse.Success = false; serviceResponse.Message = "API did not return user information."; } return serviceResponse; } public async Task> UpdateUserInformationAsync(UserUpdateInformationDto request) { await RefreshSessionIfInvalid(); var serviceResponse = new ServiceResponse(); var restRequest = new RestRequest("users/update") .AddJsonBody(request) .AddHeader("Authorization", $"Bearer {SessionToken}"); var response = await _client.PutAsync>(restRequest); if(response != null || response!.Data != null) { serviceResponse.Success = true; serviceResponse.Data = response.Data; // update currentuser model CurrentUser!.Username = response.Data!.Username; CurrentUser.Bio = response.Data.Bio; CurrentUser.DateOfBirth = response.Data.DateOfBirth; } else { serviceResponse.Success = false; serviceResponse.Message = "API never responded."; } return serviceResponse; } public async Task> UpdateUserProfilePic(string filePath) { var serviceResponse = new ServiceResponse(); try { var restRequest = new RestRequest($"users/upload-profile-pic") .AddQueryParameter("userId", CurrentUser!.Id) .AddHeader("Authorization", $"Bearer {SessionToken}") .AddFile("file", filePath); var response = await _client.PostAsync>(restRequest); if (response != null && response.Success != false) { serviceResponse.Success = true; serviceResponse.Data = response.Data; } else { serviceResponse.Success = false; serviceResponse.Data = "Upload Failed."; } } catch (JsonException) { serviceResponse.Success = false; serviceResponse.Message = "Profile Pictures Can Only Be Less Then 3 MB In Size."; } catch (HttpRequestException ex) { serviceResponse.Success = false; serviceResponse.Data = ex.Message; } return serviceResponse; } public async Task> GetUserProfilePic(string userId) { var serviceResponse = new ServiceResponse(); try { var restRequest = new RestRequest($"users/profile-pic/{userId}") .AddHeader("Authorization", $"Bearer {SessionToken}"); var response = await _client.GetAsync(restRequest); if (response != null) { serviceResponse.Success = true; serviceResponse.Data = response.RawBytes; } else { serviceResponse.Success = false; serviceResponse.Message = "No Profile Picture Received."; } return serviceResponse; } catch (HttpRequestException ex) { serviceResponse.Success = false; serviceResponse.Message = ex.Message; return serviceResponse; } } public async Task> LoginAsync(UserLoginDto userLoginDto) { var serviceResponse = new ServiceResponse(); try { if (string.IsNullOrWhiteSpace(userLoginDto.Email) || string.IsNullOrWhiteSpace(userLoginDto.Password)) { serviceResponse.Success = false; serviceResponse.Message = "Email or Password cannot be null."; } var request = new RestRequest("auth/login") .AddJsonBody(userLoginDto); var response = await _client.PostAsync>(request); if (response != null) { if (response.Data != null && response.Success) { SessionToken = response.Data!; await File.WriteAllTextAsync("./session.token", response.Message); var user = await SetCurrentUser(); serviceResponse.Success = true; if (response.Message != null) serviceResponse.Message = response.Message; serviceResponse.Data = user; } else { serviceResponse.Success = false; serviceResponse.Message = response.Message; } } } catch (Exception ex) { serviceResponse.Success = false; serviceResponse.Message = ex.Message; } return serviceResponse; } private async Task SetCurrentUser() { var userRequest = new RestRequest("users/user-authorized") .AddHeader("Authorization", $"Bearer {SessionToken}"); var userResponse = await _client.GetAsync>(userRequest); if (userResponse != null || userResponse!.Data != null) { user = userResponse.Data; return userResponse.Data!; } else { throw new NullReferenceException("Current User could not be set."); } } public async Task> RefreshLogin(string refreshToken) { var serviceResponse = new ServiceResponse(); try { if (string.IsNullOrEmpty(refreshToken)) { serviceResponse.Success = false; serviceResponse.Message = "No Refresh Token Specified."; } var request = new RestRequest("auth/refresh") .AddQueryParameter("token", refreshToken); var response = await _client.PostAsync>(request); if (response != null && response.Success != false) { SessionToken = response.Data; if (user == null) { var user = await SetCurrentUser(); serviceResponse.Success = true; serviceResponse.Data = user; } serviceResponse.Success = true; serviceResponse.Data = CurrentUser; } else { serviceResponse.Success = false; serviceResponse.Message = "API didn't respond with a session token."; } } catch (Exception ex) { serviceResponse.Success = false; serviceResponse.Message = ex.Message; } return serviceResponse; } public async Task> RefreshSessionIfInvalid() { var tokenHandler = new JwtSecurityTokenHandler(); var refToken = await File.ReadAllTextAsync("./session.token"); JwtSecurityToken token = tokenHandler.ReadJwtToken(SessionToken); if(DateTime.Compare(DateTime.UtcNow, token.ValidTo) > 0) { if (!File.Exists("./session.token")) { return new ServiceResponse { Success = false, Message = "Session File Not Found. Session Expired." }; } var result = await RefreshLogin(refToken); if (result == null || result.Success == false) { File.Delete("./session.token"); return new ServiceResponse { Success = false, Message = "Session Expired." }; } else return new ServiceResponse { Success = true, Data = refToken }; } else return new ServiceResponse { Success = true, Data = refToken }; } public async Task> RegisterAsync(UserDto userDto) { var serviceResponse = new ServiceResponse(); if (string.IsNullOrEmpty(userDto.Username) || string.IsNullOrEmpty(userDto.Password) || string.IsNullOrEmpty(userDto.Email)) { serviceResponse.Success = false; serviceResponse.Message = "Incomplete UserDto."; } var request = new RestRequest("auth/register") .AddJsonBody(userDto); var response = await _client.PostAsync>(request); if (response != null || response!.Success == true) { serviceResponse.Success = true; serviceResponse.Data = response.Data; } else { serviceResponse.Success = false; serviceResponse.Message = "API never responded with created user."; } return serviceResponse; } public async Task> CreateRoomAsync(RoomDto request) { await RefreshSessionIfInvalid(); var serviceResponse = new ServiceResponse(); if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made."); var restRequest = new RestRequest($"rooms/create-room?userId={user!.Id}") .AddJsonBody(request) .AddHeader("Authorization", $"Bearer {SessionToken}"); var response = await _client.PostAsync>(restRequest); if(response != null || response!.Data != null) { serviceResponse.Success = true; serviceResponse.Data = response.Data; } else { serviceResponse.Success = false; serviceResponse.Message = "API never responded with created room."; } return serviceResponse; } public async Task>> GetAllRoomsAsync() { await RefreshSessionIfInvalid(); var serviceResponse = new ServiceResponse>(); if(SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made."); var request = new RestRequest("rooms/get-all-rooms") .AddHeader("Authorization", $"Bearer {SessionToken}"); var response = await _client.GetAsync>>(request); if (response != null || response!.Data != null) { serviceResponse.Success = true; serviceResponse.Data = response.Data; } else { serviceResponse.Success = false; serviceResponse.Message = "API never responded with rooms."; } return serviceResponse; } public async Task> DeleteRoomAsync(string roomId) { await RefreshSessionIfInvalid(); var serviceResponse = new ServiceResponse(); if(SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made."); var request = new RestRequest($"rooms/delete-room?roomId={roomId}") .AddHeader("Authorization", $"Bearer {SessionToken}"); var response = await _client.DeleteAsync>(request); if (response != null || response!.Data != null) { serviceResponse.Success = true; serviceResponse.Data = response.Data; } else { serviceResponse.Success = false; serviceResponse.Message = "API never responded."; } return serviceResponse; } public async Task>> GetCurrentUserContacts() { await RefreshSessionIfInvalid(); var serviceResponse = new ServiceResponse>(); if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made."); var request = new RestRequest("contacts/get-user-contacts") .AddHeader("Authorization", $"Bearer {SessionToken}") .AddJsonBody(CurrentUser!); var response = await _client.GetAsync>>(request); if (response == null) { serviceResponse.Success = false; serviceResponse.Message = "API didn't respond."; return serviceResponse; } if (response.Message == "User Has No Contacts.") { serviceResponse.Success = true; serviceResponse.Message = "No Contacts Found."; } if (response.Success == true) { serviceResponse.Success = true; serviceResponse.Data = response.Data; } return serviceResponse; } public async Task> AddContactToCurrentUser(string userId) { await RefreshSessionIfInvalid(); var serviceResponse = new ServiceResponse(); if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made."); var restRequest = new RestRequest("contacts/add-contact") .AddHeader("Authorization", $"Bearer {SessionToken}") .AddQueryParameter("ownerId", CurrentUser!.Id) .AddQueryParameter("userId", userId); var response = await _client.PostAsync>(restRequest); if (response == null) { serviceResponse.Success = false; serviceResponse.Message = "API did not respond."; return serviceResponse; } if (response.Success) { serviceResponse.Success = true; serviceResponse.Data = response.Data; } return serviceResponse; } public async Task> AcceptContactRequest(string userId) { await RefreshSessionIfInvalid(); var serviceResponse = new ServiceResponse(); if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made."); var restRequest = new RestRequest("contacts/approve-contact") .AddHeader("Authorization", $"Bearer {SessionToken}") .AddQueryParameter("ownerId", CurrentUser!.Id) .AddQueryParameter("userId", userId); var response = await _client.PostAsync>(restRequest); if (response == null) { serviceResponse.Success = false; serviceResponse.Message = "API did not respond."; return serviceResponse; } if (response.Success) { serviceResponse.Success = true; serviceResponse.Data = response.Data; } return serviceResponse; } public async Task> RemoveContactFromCurrentUser(string userId) { await RefreshSessionIfInvalid(); var serviceResponse = new ServiceResponse(); if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made."); var restRequest = new RestRequest("contacts/remove-contact") .AddHeader("Authorization", $"Bearer {SessionToken}") .AddQueryParameter("userId", userId); var response = await _client.DeleteAsync>(restRequest); if (response == null) { serviceResponse.Success = false; serviceResponse.Message = "API did not respond."; return serviceResponse; } if (response.Success) { serviceResponse.Success = true; serviceResponse.Data = response.Data; } return serviceResponse; } public async Task> AddCurrencyToCurrentUser(int amount, bool isSpinClaim) { await RefreshSessionIfInvalid(); var serviceResponse = new ServiceResponse(); if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made."); var restRequest = new RestRequest("users/update-user-currency") .AddHeader("Authorization", $"Bearer {SessionToken}") .AddQueryParameter("amount", amount) .AddQueryParameter("isSpinClaim", isSpinClaim); var response = await _client.PostAsync>(restRequest); if (response == null) { serviceResponse.Success = false; serviceResponse.Message = "API did not respond."; return serviceResponse; } if (response.Success) { serviceResponse.Success = true; serviceResponse.Data = response.Data; } return serviceResponse; } public async Task> GetCurrentStockPrice() { await RefreshSessionIfInvalid(); var serviceResponse = new ServiceResponse(); if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made."); var restRequest = new RestRequest("games/stock-market/current-price") .AddHeader("Authorization", $"Bearer {SessionToken}"); var response = await _client.GetAsync>(restRequest); if (response == null) { serviceResponse.Success = false; serviceResponse.Message = "API did not respond."; return serviceResponse; } if (response.Success) { serviceResponse.Success = true; serviceResponse.Data = response.Data; } return serviceResponse; } public async Task> BuyStock(int amount) { await RefreshSessionIfInvalid(); var serviceResponse = new ServiceResponse(); if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made."); var restRequest = new RestRequest("games/stock-market/buy-stock") .AddHeader("Authorization", $"Bearer {SessionToken}") .AddQueryParameter("amount", amount); var response = await _client.PostAsync>(restRequest); if (response == null) { serviceResponse.Success = false; serviceResponse.Message = "API did not respond."; return serviceResponse; } if (response.Success) { serviceResponse.Success = true; serviceResponse.Data = response.Data; } return serviceResponse; } public async Task> SellStock(int amount) { await RefreshSessionIfInvalid(); var serviceResponse = new ServiceResponse(); if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made."); var restRequest = new RestRequest("games/stock-market/sell-stock") .AddHeader("Authorization", $"Bearer {SessionToken}") .AddQueryParameter("amount", amount); var response = await _client.PostAsync>(restRequest); if (response == null) { serviceResponse.Success = false; serviceResponse.Message = "API did not respond."; return serviceResponse; } if (response.Success) { serviceResponse.Success = true; serviceResponse.Data = response.Data; } return serviceResponse; } } }