about summary refs log tree commit diff
path: root/Tests/LibMatrix.HomeserverEmulator/Services/RoomStore.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Tests/LibMatrix.HomeserverEmulator/Services/RoomStore.cs')
-rw-r--r--Tests/LibMatrix.HomeserverEmulator/Services/RoomStore.cs308
1 files changed, 0 insertions, 308 deletions
diff --git a/Tests/LibMatrix.HomeserverEmulator/Services/RoomStore.cs b/Tests/LibMatrix.HomeserverEmulator/Services/RoomStore.cs
deleted file mode 100644
index 5cdc3ab..0000000
--- a/Tests/LibMatrix.HomeserverEmulator/Services/RoomStore.cs
+++ /dev/null
@@ -1,308 +0,0 @@
-using System.Collections.Concurrent;
-using System.Collections.Frozen;
-using System.Collections.Immutable;
-using System.Collections.ObjectModel;
-using System.Collections.Specialized;
-using System.Text.Json;
-using System.Text.Json.Nodes;
-using ArcaneLibs;
-using ArcaneLibs.Collections;
-using ArcaneLibs.Extensions;
-using LibMatrix.EventTypes.Spec.State;
-using LibMatrix.HomeserverEmulator.Controllers.Rooms;
-using LibMatrix.Responses;
-
-namespace LibMatrix.HomeserverEmulator.Services;
-
-public class RoomStore {
-    private readonly ILogger<RoomStore> _logger;
-    public ConcurrentBag<Room> _rooms = new();
-    private FrozenDictionary<string, Room> _roomsById = FrozenDictionary<string, Room>.Empty;
-
-    public RoomStore(ILogger<RoomStore> logger, HSEConfiguration config) {
-        _logger = logger;
-        if (config.StoreData) {
-            var path = Path.Combine(config.DataStoragePath, "rooms");
-            if (!Directory.Exists(path)) Directory.CreateDirectory(path);
-            foreach (var file in Directory.GetFiles(path)) {
-                var room = JsonSerializer.Deserialize<Room>(File.ReadAllText(file));
-                if (room is not null) _rooms.Add(room);
-            }
-        }
-        else
-            Console.WriteLine("Data storage is disabled, not loading rooms from disk");
-
-        RebuildIndexes();
-    }
-
-    private SemaphoreSlim a = new(1, 1);
-    private void RebuildIndexes() {
-        // a.Wait();
-        // lock (_roomsById)
-        // _roomsById = new ConcurrentDictionary<string, Room>(_rooms.ToDictionary(u => u.RoomId));
-        // foreach (var room in _rooms) {
-        //     _roomsById.AddOrUpdate(room.RoomId, room, (key, old) => room);
-        // }
-        //
-        // var roomsArr = _rooms.ToArray();
-        // foreach (var (id, room) in _roomsById) {
-        //     if (!roomsArr.Any(x => x.RoomId == id))
-        //         _roomsById.TryRemove(id, out _);
-        // }
-        
-        // _roomsById = new ConcurrentDictionary<string, Room>(_rooms.ToDictionary(u => u.RoomId));
-        _roomsById = _rooms.ToFrozenDictionary(u => u.RoomId);
-
-        // a.Release();
-    }
-
-    public Room? GetRoomById(string roomId, bool createIfNotExists = false) {
-        if (_roomsById.TryGetValue(roomId, out var room)) {
-            return room;
-        }
-
-        if (!createIfNotExists)
-            return null;
-
-        return CreateRoom(new() { });
-    }
-
-    public Room CreateRoom(CreateRoomRequest request, UserStore.User? user = null) {
-        var room = new Room(roomId: $"!{Guid.NewGuid().ToString()}");
-        var newCreateEvent = new StateEvent() {
-            Type = RoomCreateEventContent.EventId,
-            RawContent = new() { }
-        };
-
-        foreach (var (key, value) in request.CreationContent) {
-            newCreateEvent.RawContent[key] = value.DeepClone();
-        }
-
-        if (user != null) {
-            newCreateEvent.RawContent["creator"] = user.UserId;
-            var createEvent = room.SetStateInternal(newCreateEvent, user: user);
-            createEvent.Sender = user.UserId;
-
-            room.SetStateInternal(new() {
-                Type = RoomMemberEventContent.EventId,
-                StateKey = user.UserId,
-                TypedContent = new RoomMemberEventContent() {
-                    Membership = "join",
-                    AvatarUrl = (user.Profile.GetOrNull("avatar_url") as JsonObject)?.GetOrNull("avatar_url")?.GetValue<string>(),
-                    DisplayName = (user.Profile.GetOrNull("displayname") as string)
-                }
-            }, user: user);
-        }
-
-        if (!string.IsNullOrWhiteSpace(request.Name))
-            room.SetStateInternal(new StateEvent() {
-                Type = RoomNameEventContent.EventId,
-                TypedContent = new RoomNameEventContent() {
-                    Name = request.Name
-                }
-            });
-
-        if (!string.IsNullOrWhiteSpace(request.RoomAliasName))
-            room.SetStateInternal(new StateEvent() {
-                Type = RoomCanonicalAliasEventContent.EventId,
-                TypedContent = new RoomCanonicalAliasEventContent() {
-                    Alias = $"#{request.RoomAliasName}:localhost"
-                }
-            });
-
-        foreach (var stateEvent in request.InitialState ?? []) {
-            room.SetStateInternal(stateEvent);
-        }
-
-        _rooms.Add(room);
-        // _roomsById.TryAdd(room.RoomId, room);
-        RebuildIndexes();
-        return room;
-    }
-
-    public Room AddRoom(Room room) {
-        _rooms.Add(room);
-        RebuildIndexes();
-
-        return room;
-    }
-
-    public class Room : NotifyPropertyChanged {
-        private CancellationTokenSource _debounceCts = new();
-        private ObservableCollection<StateEventResponse> _timeline;
-        private ObservableDictionary<string, List<StateEventResponse>> _accountData;
-        private ObservableDictionary<string, ReadMarkersData> _readMarkers;
-        private FrozenSet<StateEventResponse> _stateCache;
-        private int _timelineHash;
-
-        public Room(string roomId) {
-            if (string.IsNullOrWhiteSpace(roomId)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(roomId));
-            if (roomId[0] != '!') throw new ArgumentException("Room ID must start with !", nameof(roomId));
-            RoomId = roomId;
-            Timeline = new();
-            AccountData = new();
-            ReadMarkers = new();
-        }
-
-        public string RoomId { get; set; }
-
-        public FrozenSet<StateEventResponse> State => _timelineHash == _timeline.GetHashCode() ? _stateCache : RebuildState();
-
-        public ObservableCollection<StateEventResponse> Timeline {
-            get => _timeline;
-            set {
-                if (Equals(value, _timeline)) return;
-                _timeline = new(value);
-                _timeline.CollectionChanged += (sender, args) => {
-                    // we dont want to do this as it's rebuilt when the state is accessed
-
-                    // if (args.Action == NotifyCollectionChangedAction.Add) {
-                    //     foreach (StateEventResponse state in args.NewItems) {
-                    //         if (state.StateKey is not null)
-                    //             // we want state to be deduplicated by type and key, and we want the latest state to be the one that is returned
-                    //             RebuildState();
-                    //     }
-                    // }
-
-                    SaveDebounced();
-                };
-                // RebuildState();
-                OnPropertyChanged();
-            }
-        }
-
-        public ObservableDictionary<string, List<StateEventResponse>> AccountData {
-            get => _accountData;
-            set {
-                if (Equals(value, _accountData)) return;
-                _accountData = new(value);
-                _accountData.CollectionChanged += (sender, args) => SaveDebounced();
-                OnPropertyChanged();
-            }
-        }
-
-        public ImmutableList<StateEventResponse> JoinedMembers =>
-            State.Where(s => s is { Type: RoomMemberEventContent.EventId, TypedContent: RoomMemberEventContent { Membership: "join" } }).ToImmutableList();
-
-        public ObservableDictionary<string, ReadMarkersData> ReadMarkers {
-            get => _readMarkers;
-            set {
-                if (Equals(value, _readMarkers)) return;
-                _readMarkers = new(value);
-                _readMarkers.CollectionChanged += (sender, args) => SaveDebounced();
-                OnPropertyChanged();
-            }
-        }
-
-        internal StateEventResponse SetStateInternal(StateEvent request, string? senderId = null, UserStore.User? user = null) {
-            var state = request as StateEventResponse ?? new StateEventResponse() {
-                Type = request.Type,
-                StateKey = request.StateKey ?? "",
-                EventId = "$" + Guid.NewGuid().ToString(),
-                RoomId = RoomId,
-                OriginServerTs = DateTimeOffset.Now.ToUnixTimeMilliseconds(),
-                Sender = user?.UserId ?? senderId ?? "",
-                RawContent = request.RawContent ?? (request.TypedContent is not null
-                    ? new JsonObject()
-                    : JsonSerializer.Deserialize<JsonObject>(JsonSerializer.Serialize(request.TypedContent)))
-            };
-            Timeline.Add(state);
-            if(state.StateKey != null)
-                RebuildState();
-            return state;
-        }
-
-        public StateEventResponse AddUser(string userId) {
-            var state = SetStateInternal(new() {
-                Type = RoomMemberEventContent.EventId,
-                StateKey = userId,
-                TypedContent = new RoomMemberEventContent() {
-                    Membership = "join"
-                },
-            });
-
-            state.Sender = userId;
-            return state;
-        }
-
-        // public async Task SaveDebounced() {
-            // if (!HSEConfiguration.Current.StoreData) return;
-            // await _debounceCts.CancelAsync();
-            // _debounceCts = new CancellationTokenSource();
-            // try {
-                // await Task.Delay(250, _debounceCts.Token);
-                // // Ensure all state events are in the timeline
-                // State.Where(s => !Timeline.Contains(s)).ToList().ForEach(s => Timeline.Add(s));
-                // var path = Path.Combine(HSEConfiguration.Current.DataStoragePath, "rooms", $"{RoomId}.json");
-                // Console.WriteLine($"Saving room {RoomId} to {path}!");
-                // await File.WriteAllTextAsync(path, this.ToJson(ignoreNull: true));
-            // }
-            // catch (TaskCanceledException) { }
-        // }
-
-        private SemaphoreSlim saveSemaphore = new(1, 1);
-
-        public async Task SaveDebounced() {
-            Task.Run(async () => {
-                await saveSemaphore.WaitAsync();
-                try {
-                    var path = Path.Combine(HSEConfiguration.Current.DataStoragePath, "rooms", $"{RoomId}.json");
-                    Console.WriteLine($"Saving room {RoomId} to {path}!");
-                    await File.WriteAllTextAsync(path, this.ToJson(ignoreNull: true));
-                }
-                finally {
-                    saveSemaphore.Release();
-                }
-            });
-        }
-
-        private SemaphoreSlim stateRebuildSemaphore = new(1, 1);
-
-        private FrozenSet<StateEventResponse> RebuildState() {
-            stateRebuildSemaphore.Wait();
-            while (true)
-                try {
-                    Console.WriteLine($"Rebuilding state for room {RoomId}");
-                    // ReSharper disable once RedundantEnumerableCastCall - This sometimes happens when the collection is modified during enumeration
-                    List<StateEventResponse>? timeline = null;
-                    lock (_timeline) {
-                        timeline = Timeline.OfType<StateEventResponse>().ToList();
-                    }
-
-                    foreach (var evt in timeline) {
-                        if (evt == null) {
-                            throw new InvalidOperationException("Event is null");
-                        }
-
-                        if (evt.EventId == null) {
-                            evt.EventId = "$" + Guid.NewGuid();
-                        }
-                        else if (!evt.EventId.StartsWith('$')) {
-                            evt.EventId = "$" + evt.EventId;
-                            Console.WriteLine($"Sanitised invalid event ID {evt.EventId}");
-                        }
-                    }
-
-                    _stateCache = timeline //.Where(s => s.Type == state.Type && s.StateKey == state.StateKey)
-                        .Where(x => x.StateKey != null)
-                        .OrderByDescending(s => s.OriginServerTs)
-                        .DistinctBy(x => (x.Type, x.StateKey))
-                        .ToFrozenSet();
-
-                    _timelineHash = _timeline.GetHashCode();
-                    stateRebuildSemaphore.Release();
-                    return _stateCache;
-                }
-                finally { }
-        }
-    }
-
-    public List<StateEventResponse> GetRoomsByMember(string userId) {
-        // return _rooms
-        // // .Where(r => r.State.Any(s => s.Type == RoomMemberEventContent.EventId && s.StateKey == userId))
-        // .Select(r => (Room: r, MemberEvent: r.State.SingleOrDefault(s => s.Type == RoomMemberEventContent.EventId && s.StateKey == userId)))
-        // .Where(r => r.MemberEvent != null)
-        // .ToDictionary(x => x.Room, x => x.MemberEvent!);
-        return _rooms.SelectMany(r => r.State.Where(s => s.Type == RoomMemberEventContent.EventId && s.StateKey == userId)).ToList();
-    }
-}
\ No newline at end of file