diff options
Diffstat (limited to 'src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/NotificationService.cs')
| -rw-r--r-- | src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/NotificationService.cs | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/NotificationService.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/NotificationService.cs new file mode 100644 index 00000000..534bf63e --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/NotificationService.cs @@ -0,0 +1,172 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Account; +using Ryujinx.Horizon.Sdk.OsTypes; +using Ryujinx.Horizon.Sdk.Sf; +using System; +using System.Collections.Generic; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail.Ipc +{ + partial class NotificationService : INotificationService, IDisposable + { + private readonly NotificationEventHandler _notificationEventHandler; + private readonly Uid _userId; + private readonly FriendsServicePermissionLevel _permissionLevel; + + private readonly object _lock = new(); + + private SystemEventType _notificationEvent; + + private readonly LinkedList<SizedNotificationInfo> _notifications; + + private bool _hasNewFriendRequest; + private bool _hasFriendListUpdate; + + public NotificationService(NotificationEventHandler notificationEventHandler, Uid userId, FriendsServicePermissionLevel permissionLevel) + { + _notificationEventHandler = notificationEventHandler; + _userId = userId; + _permissionLevel = permissionLevel; + _notifications = new LinkedList<SizedNotificationInfo>(); + Os.CreateSystemEvent(out _notificationEvent, EventClearMode.AutoClear, interProcess: true).AbortOnFailure(); + + _hasNewFriendRequest = false; + _hasFriendListUpdate = false; + + notificationEventHandler.RegisterNotificationService(this); + } + + [CmifCommand(0)] + public Result GetEvent([CopyHandle] out int eventHandle) + { + eventHandle = Os.GetReadableHandleOfSystemEvent(ref _notificationEvent); + + return Result.Success; + } + + [CmifCommand(1)] + public Result Clear() + { + lock (_lock) + { + _hasNewFriendRequest = false; + _hasFriendListUpdate = false; + + _notifications.Clear(); + } + + return Result.Success; + } + + [CmifCommand(2)] + public Result Pop(out SizedNotificationInfo sizedNotificationInfo) + { + lock (_lock) + { + if (_notifications.Count >= 1) + { + sizedNotificationInfo = _notifications.First.Value; + _notifications.RemoveFirst(); + + if (sizedNotificationInfo.Type == NotificationEventType.FriendListUpdate) + { + _hasFriendListUpdate = false; + } + else if (sizedNotificationInfo.Type == NotificationEventType.NewFriendRequest) + { + _hasNewFriendRequest = false; + } + + return Result.Success; + } + } + + sizedNotificationInfo = default; + + return FriendResult.NotificationQueueEmpty; + } + + public void SignalFriendListUpdate(Uid targetId) + { + lock (_lock) + { + if (_userId == targetId) + { + if (!_hasFriendListUpdate) + { + SizedNotificationInfo friendListNotification = new(); + + if (_notifications.Count != 0) + { + friendListNotification = _notifications.First.Value; + _notifications.RemoveFirst(); + } + + friendListNotification.Type = NotificationEventType.FriendListUpdate; + _hasFriendListUpdate = true; + + if (_hasNewFriendRequest) + { + SizedNotificationInfo newFriendRequestNotification = new(); + + if (_notifications.Count != 0) + { + newFriendRequestNotification = _notifications.First.Value; + _notifications.RemoveFirst(); + } + + newFriendRequestNotification.Type = NotificationEventType.NewFriendRequest; + _notifications.AddFirst(newFriendRequestNotification); + } + + // We defer this to make sure we are on top of the queue. + _notifications.AddFirst(friendListNotification); + } + + Os.SignalSystemEvent(ref _notificationEvent); + } + } + } + + public void SignalNewFriendRequest(Uid targetId) + { + lock (_lock) + { + if (_permissionLevel.HasFlag(FriendsServicePermissionLevel.ViewerMask) && _userId == targetId) + { + if (!_hasNewFriendRequest) + { + if (_notifications.Count == 100) + { + SignalFriendListUpdate(targetId); + } + + SizedNotificationInfo newFriendRequestNotification = new() + { + Type = NotificationEventType.NewFriendRequest, + }; + + _notifications.AddLast(newFriendRequestNotification); + _hasNewFriendRequest = true; + } + + Os.SignalSystemEvent(ref _notificationEvent); + } + } + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + _notificationEventHandler.UnregisterNotificationService(this); + } + } + + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + } +} |
