using Immense.RemoteControl.Server.Models; using Remotely.Shared.Models; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; namespace Remotely.Server.Services; public interface IAgentHubSessionCache { void AddOrUpdateByConnectionId(string connectionId, Device device); IEnumerable FilterDevicesByOnlineStatus(IEnumerable deviceIds, bool isOnline); ICollection GetAllDevices(); IEnumerable GetConnectionIdsByDeviceIds(IEnumerable deviceIds); bool TryGetByDeviceId(string deviceId, [NotNullWhen(true)] out Device? device); bool TryGetConnectionId(string deviceId, [NotNullWhen(true)] out string? serviceConnectionId); bool TryRemoveByConnectionId(string connectionId, [NotNullWhen(true)] out Device? device); } public class AgentHubSessionCache : IAgentHubSessionCache { private readonly ConcurrentDictionary _connectionIdToDeviceLookup = new(); private readonly ConcurrentDictionary _deviceIdToConnectionIdLookup = new(); public void AddOrUpdateByConnectionId(string connectionId, Device device) { _connectionIdToDeviceLookup.AddOrUpdate(connectionId, device, (k, v) => device); _deviceIdToConnectionIdLookup.AddOrUpdate(device.ID, connectionId, (k, v) => connectionId); } public IEnumerable FilterDevicesByOnlineStatus(IEnumerable deviceIds, bool isOnline) { foreach (var deviceId in deviceIds) { var result = TryGetConnectionId(deviceId, out _); if (result == isOnline) { yield return deviceId; } } } public ICollection GetAllDevices() => _connectionIdToDeviceLookup.Values; public IEnumerable GetConnectionIdsByDeviceIds(IEnumerable deviceIds) { foreach (var deviceId in deviceIds) { if (TryGetConnectionId(deviceId, out var connectionId)) { yield return connectionId; } } } public bool TryGetByDeviceId(string deviceId, [NotNullWhen(true)] out Device? device) { if (_deviceIdToConnectionIdLookup.TryGetValue(deviceId, out var connectionId) && _connectionIdToDeviceLookup.TryGetValue(connectionId, out device)) { return true; } device = default; return false; } public bool TryGetConnectionId(string deviceId, [NotNullWhen(true)] out string? serviceConnectionId) { return _deviceIdToConnectionIdLookup.TryGetValue(deviceId, out serviceConnectionId); } public bool TryRemoveByConnectionId(string connectionId, [NotNullWhen(true)] out Device? device) { if (_connectionIdToDeviceLookup.TryRemove(connectionId, out var lookupResult)) { device = lookupResult; _ = _deviceIdToConnectionIdLookup.TryRemove(lookupResult.ID, out _); return true; } device = null; return false; } }