1
1
mirror of https://github.com/ryujinx-mirror/ryujinx.git synced 2025-04-17 14:34:05 -05:00
ryujinx/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/NotificationService.cs
gdkchan 4117c13377
Migrate friends service to new IPC (#6174)
* Migrate friends service to new IPC

* Add a note that the pointer buffer size and domain counts are wrong

* Wrong length

* Format whitespace

* PR feedback

* Fill in structs from PR feedback

* Missed that one

* Somehow forgot to save that one

* Fill in enums from PR review

* Language enum, NotificationTime

* Format whitespace

* Fix the warning
2024-01-29 22:45:40 +01:00

173 lines
5.7 KiB
C#

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);
}
}
}