Skip to content

Commit

Permalink
(#394) communication: udpate chats razor pages
Browse files Browse the repository at this point in the history
  • Loading branch information
SaintAngeLs committed Aug 28, 2024
1 parent ae2ed49 commit 120f7e3
Show file tree
Hide file tree
Showing 13 changed files with 759 additions and 145 deletions.
2 changes: 2 additions & 0 deletions MiniSpace.Web/src/MiniSpace.Web/App.razor
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@

@using Microsoft.AspNetCore.Components.Authorization
@using MudBlazor.Services
@using MudBlazor
@* <MudDialogProvider /> *@
<CascadingAuthenticationState>
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.JSInterop;
using MiniSpace.Web.Areas.Identity;
using MiniSpace.Web.DTO.Communication;
using System;
Expand All @@ -8,116 +9,122 @@
namespace MiniSpace.Web.Areas.Communication
{
public class ChatSignalRService : IAsyncDisposable
{
private HubConnection _hubConnection;
private readonly NavigationManager _navigationManager;
private readonly IIdentityService _identityService;
private Guid _userId;
private Guid _currentChatId;
private bool _disposed;

public event Action<MessageDto> MessageReceived;
public event Action<Guid, string> MessageStatusUpdated;
public event Action<string, bool> TypingNotificationReceived;
public event Action<bool> ConnectionChanged;

public ChatSignalRService(NavigationManager navigationManager, IIdentityService identityService)
{
private HubConnection _hubConnection;
private readonly NavigationManager _navigationManager;
private readonly IIdentityService _identityService;
private Guid _userId;
private Guid _currentChatId;
public event Action<MessageDto> MessageReceived;
public event Action<Guid, string> MessageStatusUpdated;

public ChatSignalRService(NavigationManager navigationManager, IIdentityService identityService)
{
_navigationManager = navigationManager;
_identityService = identityService;
}
_navigationManager = navigationManager;
_identityService = identityService;
}

public async Task StartAsync(Guid userId, Guid currentChatId)
{
_userId = userId;
_currentChatId = currentChatId;
var hubUrl = $"http://localhost:5016/chatHub?userId={userId}&chatId={currentChatId}";
public async Task StartAsync(Guid userId, Guid currentChatId)
{
_userId = userId;
_currentChatId = currentChatId;
var hubUrl = $"http://localhost:5016/chatHub?userId={userId}&chatId={currentChatId}";

_hubConnection = new HubConnectionBuilder()
.WithUrl(hubUrl, options =>
_hubConnection = new HubConnectionBuilder()
.WithUrl(hubUrl, options =>
{
options.AccessTokenProvider = async () =>
{
options.AccessTokenProvider = async () =>
if (_disposed)
{
return null; // Circuit is disposed, return null to avoid further calls.
}

try
{
var token = await _identityService.GetAccessTokenAsync();
return token;
};
})
.WithAutomaticReconnect()
.Build();

// Handler for receiving messages
_hubConnection.On<string>("ReceiveMessage", (jsonMessage) =>
{
Console.WriteLine("ReceiveMessage event triggered");
var message = System.Text.Json.JsonSerializer.Deserialize<MessageDto>(jsonMessage);
MessageReceived?.Invoke(message);
});
}
catch (JSDisconnectedException)
{
// Handle the JS interop disconnection gracefully
return null;
}
};
})
.WithAutomaticReconnect()
.Build();

// Handler for receiving message status updates
_hubConnection.On<string>("ReceiveMessageStatusUpdate", (jsonStatusUpdate) =>
{
try
{
Console.WriteLine("ReceiveMessageStatusUpdate event triggered: " + jsonStatusUpdate);
_hubConnection.On<string>("ReceiveMessage", (jsonMessage) =>
{
var message = System.Text.Json.JsonSerializer.Deserialize<MessageDto>(jsonMessage);
MessageReceived?.Invoke(message);
});

// Deserialize the JSON to a strongly-typed object
var statusUpdate = System.Text.Json.JsonSerializer.Deserialize<MessageStatusUpdateDto>(jsonStatusUpdate);
var chatId = statusUpdate.ChatId;
var messageId = Guid.Parse(statusUpdate.MessageId);
var status = statusUpdate.Status;
_hubConnection.On<string>("ReceiveMessageStatusUpdate", (jsonStatusUpdate) =>
{
var statusUpdate = System.Text.Json.JsonSerializer.Deserialize<MessageStatusUpdateDto>(jsonStatusUpdate);
var chatId = statusUpdate.ChatId;
var messageId = Guid.Parse(statusUpdate.MessageId);
var status = statusUpdate.Status;

Console.WriteLine($"Chat ID: {chatId}, Message ID: {messageId}, Status: {status}");
if (chatId == _currentChatId.ToString())
{
MessageStatusUpdated?.Invoke(messageId, status);
}
});

// Ensure the update is only for the current chat
if (chatId == _currentChatId.ToString())
{
MessageStatusUpdated?.Invoke(messageId, status);
}
}
catch (Exception ex)
{
Console.WriteLine("Error processing status update: " + ex.Message);
}
});
_hubConnection.On<string, bool>("ReceiveTypingNotification", (userId, isTyping) =>
{
TypingNotificationReceived?.Invoke(userId, isTyping);
});

// Log connection state changes
_hubConnection.Closed += async (error) =>
{
Console.WriteLine("SignalR connection closed. Attempting to reconnect...");
await Task.Delay(new Random().Next(0, 5) * 1000);
await _hubConnection.StartAsync();
};
_hubConnection.Reconnecting += (error) =>
{
ConnectionChanged?.Invoke(false);
return Task.CompletedTask;
};

_hubConnection.Reconnected += connectionId =>
{
Console.WriteLine($"Reconnected to SignalR with connection ID: {connectionId}");
return Task.CompletedTask;
};
_hubConnection.Reconnected += (connectionId) =>
{
ConnectionChanged?.Invoke(true);
return Task.CompletedTask;
};

_hubConnection.Reconnecting += error =>
{
Console.WriteLine("SignalR connection lost, reconnecting...");
return Task.CompletedTask;
};
_hubConnection.Closed += (error) =>
{
ConnectionChanged?.Invoke(false);
return Task.CompletedTask;
};

// Start the SignalR connection
if (!_disposed)
{
await _hubConnection.StartAsync();
Console.WriteLine("SignalR connection started successfully");
ConnectionChanged?.Invoke(true);
}
}

public async Task StopAsync()
public async Task SendTypingNotificationAsync(bool isTyping)
{
if (_hubConnection.State == HubConnectionState.Connected)
{
if (_hubConnection != null)
{
await _hubConnection.StopAsync();
Console.WriteLine("SignalR connection stopped.");
}
await _hubConnection.InvokeAsync("SendTypingNotification", _currentChatId.ToString(), _userId.ToString(), isTyping);
}
}

public async ValueTask DisposeAsync()
public async ValueTask DisposeAsync()
{
if (_hubConnection != null)
{
if (_hubConnection != null)
{
await _hubConnection.DisposeAsync();
Console.WriteLine("SignalR connection disposed.");
}
await _hubConnection.DisposeAsync();
}
_disposed = true;
}
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ namespace MiniSpace.Web.Areas.Communication.CommandsDto
public class DeleteChatCommand
{
public Guid ChatId { get; set; }
public Guid UserId { get; set; }

public DeleteChatCommand(Guid chatId)
public DeleteChatCommand(Guid chatId, Guid userId)
{
ChatId = chatId;
UserId = userId;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,14 @@ public async Task AddUserToChatAsync(Guid chatId, Guid userId)
await _httpClient.PutAsync<object>($"communication/chats/{chatId}/users", new { chatId, userId });
}

public async Task DeleteChatAsync(Guid chatId)
public async Task DeleteChatAsync(Guid chatId, Guid userId)
{
_httpClient.SetAccessToken(_identityService.JwtDto.AccessToken);
await _httpClient.DeleteAsync($"communication/chats/{chatId}");
var command = new DeleteChatCommand(chatId, userId);
await _httpClient.PostAsync<DeleteChatCommand, object>($"communication/chats/{chatId}", command);
}


public async Task<HttpResponse<object>> SendMessageAsync(SendMessageCommand command)
{
_httpClient.SetAccessToken(_identityService.JwtDto.AccessToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public interface ICommunicationService
Task<IEnumerable<MessageDto>> GetMessagesForChatAsync(Guid chatId);
Task<HttpResponse<object>> CreateChatAsync(CreateChatCommand command);
Task AddUserToChatAsync(Guid chatId, Guid userId);
Task DeleteChatAsync(Guid chatId);
Task DeleteChatAsync(Guid chatId, Guid userId);
Task<HttpResponse<object>> SendMessageAsync(SendMessageCommand command);
Task<HttpResponse<object>> UpdateMessageStatusAsync(UpdateMessageStatusCommand command);
Task DeleteMessageAsync(Guid chatId, Guid messageId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@ public interface INotificationsService
Task DeleteNotificationAsync(Guid userId, Guid notificationId);
Task<NotificationDto> GetNotificationByIdAsync(Guid userId, Guid notificationId);
Task CreateNotificationAsync(NotificationToUsersDto notification);
Task<bool> IsUserConnectedAsync(Guid userId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using MiniSpace.Web.HttpClients;
using Blazorise;
using MiniSpace.Web.DTO.Notifications;
using System.Collections.Concurrent;

namespace MiniSpace.Web.Areas.Notifications
{
Expand All @@ -16,6 +17,9 @@ public class NotificationsService: INotificationsService
private readonly IHttpClient _httpClient;
private readonly IIdentityService _identityService;

private static readonly ConcurrentDictionary<Guid, bool> ConnectedUsers = new();


public NotificationsService(IHttpClient httpClient, IIdentityService identityService)
{
_httpClient = httpClient;
Expand Down Expand Up @@ -93,5 +97,22 @@ public async Task CreateNotificationAsync(NotificationToUsersDto notification)
await _httpClient.PostAsync<NotificationToUsersDto, HttpResponse<NotificationToUsersDto>>(url, notification);
}

public void AddConnectedUser(Guid userId)
{
ConnectedUsers[userId] = true;
}

// Method to remove a user from the connected users list
public void RemoveConnectedUser(Guid userId)
{
ConnectedUsers.TryRemove(userId, out _);
}

// Method to check if a user is connected
public Task<bool> IsUserConnectedAsync(Guid userId)
{
return Task.FromResult(ConnectedUsers.ContainsKey(userId));
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,7 @@ Task UpdateStudentLanguagesAndInterestsAsync(
IEnumerable<string> languages,
IEnumerable<string> interests);

Task<bool> IsUserOnlineAsync(Guid studentId);

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Text.Json;
using System.Threading.Tasks;
using MiniSpace.Web.Areas.Identity;
using MiniSpace.Web.Areas.Notifications;
using MiniSpace.Web.DTO;
using MiniSpace.Web.DTO.Interests;
using MiniSpace.Web.DTO.Languages;
Expand All @@ -17,6 +18,8 @@ public class StudentsService : IStudentsService
private readonly IHttpClient _httpClient;
private readonly IIdentityService _identityService;

private readonly INotificationsService _notificationsService;

public StudentDto StudentDto { get; private set; }

public StudentsService(IHttpClient httpClient, IIdentityService identityService)
Expand Down Expand Up @@ -203,5 +206,11 @@ public async Task UpdateStudentLanguagesAndInterestsAsync(

await _httpClient.PutAsync($"students/{studentId}/languages-and-interests", updateData);
}

public async Task<bool> IsUserOnlineAsync(Guid studentId)
{
// Assuming the NotificationsService has a method to check if a user is connected
return await _notificationsService.IsUserConnectedAsync(studentId);
}
}
}
Loading

0 comments on commit 120f7e3

Please sign in to comment.