
* Introduced a new claim on the Token to get UserId as well as Username, thus allowing for many places of reduced DB calls. All users will need to reauthenticate. Introduced UTC Dates throughout the application, they are not exposed in all DTOs, that will come later when we fully switch over. For now, Utc dates will be updated along side timezone specific dates. Refactored get-progress/progress api to be 50% faster by reducing how much data is loaded from the query. * Speed up the following apis: collection/search, download/bookmarks, reader/bookmark-info, recommended/quick-reads, recommended/quick-catchup-reads, recommended/highly-rated, recommended/more-in, recommended/rediscover, want-to-read/ * Added a migration to sync all dates with their new UTC counterpart. * Added LastReadingProgressUtc onto ChapterDto for some browsing apis, but not all. Added LastReadingProgressUtc to reading list items. Refactored the migration to run raw SQL which is much faster. * Added LastReadingProgressUtc onto ChapterDto for some browsing apis, but not all. Added LastReadingProgressUtc to reading list items. Refactored the migration to run raw SQL which is much faster. * Fixed the unit tests * Fixed an issue with auto mapper which was causing progress page number to not get sent to UI * series/volume has chapter last reading progress * Added filesize and library name on reading list item dto for CDisplayEx. * Some minor code cleanup * Forgot to fill a field
113 lines
3.2 KiB
C#
113 lines
3.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using API.Data;
|
|
|
|
namespace API.SignalR.Presence;
|
|
|
|
public interface IPresenceTracker
|
|
{
|
|
Task UserConnected(string username, string connectionId);
|
|
Task UserDisconnected(string username, string connectionId);
|
|
Task<string[]> GetOnlineAdmins();
|
|
Task<List<string>> GetConnectionsForUser(string username);
|
|
|
|
}
|
|
|
|
internal class ConnectionDetail
|
|
{
|
|
public List<string> ConnectionIds { get; set; }
|
|
public bool IsAdmin { get; set; }
|
|
}
|
|
|
|
// TODO: This can respond to UserRoleUpdate events to handle online users
|
|
/// <summary>
|
|
/// This is a singleton service for tracking what users have a SignalR connection and their difference connectionIds
|
|
/// </summary>
|
|
public class PresenceTracker : IPresenceTracker
|
|
{
|
|
private readonly IUnitOfWork _unitOfWork;
|
|
private static readonly Dictionary<string, ConnectionDetail> OnlineUsers = new Dictionary<string, ConnectionDetail>();
|
|
|
|
public PresenceTracker(IUnitOfWork unitOfWork)
|
|
{
|
|
_unitOfWork = unitOfWork;
|
|
}
|
|
|
|
public async Task UserConnected(string username, string connectionId)
|
|
{
|
|
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(username);
|
|
if (user == null) return;
|
|
var isAdmin = await _unitOfWork.UserRepository.IsUserAdminAsync(user);
|
|
lock (OnlineUsers)
|
|
{
|
|
if (OnlineUsers.ContainsKey(username))
|
|
{
|
|
OnlineUsers[username].ConnectionIds.Add(connectionId);
|
|
}
|
|
else
|
|
{
|
|
OnlineUsers.Add(username, new ConnectionDetail()
|
|
{
|
|
ConnectionIds = new List<string>() {connectionId},
|
|
IsAdmin = isAdmin
|
|
});
|
|
}
|
|
}
|
|
|
|
// Update the last active for the user
|
|
user.UpdateLastActive();
|
|
await _unitOfWork.CommitAsync();
|
|
}
|
|
|
|
public Task UserDisconnected(string username, string connectionId)
|
|
{
|
|
lock (OnlineUsers)
|
|
{
|
|
if (!OnlineUsers.ContainsKey(username)) return Task.CompletedTask;
|
|
|
|
OnlineUsers[username].ConnectionIds.Remove(connectionId);
|
|
|
|
if (OnlineUsers[username].ConnectionIds.Count == 0)
|
|
{
|
|
OnlineUsers.Remove(username);
|
|
}
|
|
}
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
public static Task<string[]> GetOnlineUsers()
|
|
{
|
|
string[] onlineUsers;
|
|
lock (OnlineUsers)
|
|
{
|
|
onlineUsers = OnlineUsers.OrderBy(k => k.Key).Select(k => k.Key).ToArray();
|
|
}
|
|
|
|
return Task.FromResult(onlineUsers);
|
|
}
|
|
|
|
public Task<string[]> GetOnlineAdmins()
|
|
{
|
|
string[] onlineUsers;
|
|
lock (OnlineUsers)
|
|
{
|
|
onlineUsers = OnlineUsers.Where(pair => pair.Value.IsAdmin).OrderBy(k => k.Key).Select(k => k.Key).ToArray();
|
|
}
|
|
|
|
|
|
return Task.FromResult(onlineUsers);
|
|
}
|
|
|
|
public Task<List<string>> GetConnectionsForUser(string username)
|
|
{
|
|
List<string> connectionIds;
|
|
lock (OnlineUsers)
|
|
{
|
|
connectionIds = OnlineUsers.GetValueOrDefault(username)?.ConnectionIds;
|
|
}
|
|
|
|
return Task.FromResult(connectionIds ?? new List<string>());
|
|
}
|
|
}
|