| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178 |
- using Ryujinx.Common;
- using Ryujinx.HLE.HOS.Ipc;
- using Ryujinx.HLE.HOS.Kernel.Common;
- using Ryujinx.HLE.HOS.Kernel.Threading;
- using Ryujinx.HLE.HOS.Services.Account.Acc;
- using Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.NotificationService;
- using System;
- using System.Collections.Generic;
- namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator
- {
- class INotificationService : DisposableIpcService
- {
- private readonly UserId _userId;
- private readonly FriendServicePermissionLevel _permissionLevel;
- private readonly object _lock = new object();
- private KEvent _notificationEvent;
- private int _notificationEventHandle = 0;
- private LinkedList<NotificationInfo> _notifications;
- private bool _hasNewFriendRequest;
- private bool _hasFriendListUpdate;
- public INotificationService(ServiceCtx context, UserId userId, FriendServicePermissionLevel permissionLevel)
- {
- _userId = userId;
- _permissionLevel = permissionLevel;
- _notifications = new LinkedList<NotificationInfo>();
- _notificationEvent = new KEvent(context.Device.System.KernelContext);
- _hasNewFriendRequest = false;
- _hasFriendListUpdate = false;
- NotificationEventHandler.Instance.RegisterNotificationService(this);
- }
- [CommandHipc(0)] //2.0.0+
- // nn::friends::detail::ipc::INotificationService::GetEvent() -> handle<copy>
- public ResultCode GetEvent(ServiceCtx context)
- {
- if (_notificationEventHandle == 0)
- {
- if (context.Process.HandleTable.GenerateHandle(_notificationEvent.ReadableEvent, out _notificationEventHandle) != KernelResult.Success)
- {
- throw new InvalidOperationException("Out of handles!");
- }
- }
- context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_notificationEventHandle);
- return ResultCode.Success;
- }
- [CommandHipc(1)] //2.0.0+
- // nn::friends::detail::ipc::INotificationService::Clear()
- public ResultCode Clear(ServiceCtx context)
- {
- lock (_lock)
- {
- _hasNewFriendRequest = false;
- _hasFriendListUpdate = false;
- _notifications.Clear();
- }
- return ResultCode.Success;
- }
- [CommandHipc(2)] // 2.0.0+
- // nn::friends::detail::ipc::INotificationService::Pop() -> nn::friends::detail::ipc::SizedNotificationInfo
- public ResultCode Pop(ServiceCtx context)
- {
- lock (_lock)
- {
- if (_notifications.Count >= 1)
- {
- NotificationInfo notificationInfo = _notifications.First.Value;
- _notifications.RemoveFirst();
- if (notificationInfo.Type == NotificationEventType.FriendListUpdate)
- {
- _hasFriendListUpdate = false;
- }
- else if (notificationInfo.Type == NotificationEventType.NewFriendRequest)
- {
- _hasNewFriendRequest = false;
- }
- context.ResponseData.WriteStruct(notificationInfo);
- return ResultCode.Success;
- }
- }
- return ResultCode.NotificationQueueEmpty;
- }
- public void SignalFriendListUpdate(UserId targetId)
- {
- lock (_lock)
- {
- if (_userId == targetId)
- {
- if (!_hasFriendListUpdate)
- {
- NotificationInfo friendListNotification = new NotificationInfo();
- if (_notifications.Count != 0)
- {
- friendListNotification = _notifications.First.Value;
- _notifications.RemoveFirst();
- }
- friendListNotification.Type = NotificationEventType.FriendListUpdate;
- _hasFriendListUpdate = true;
- if (_hasNewFriendRequest)
- {
- NotificationInfo newFriendRequestNotification = new NotificationInfo();
- 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);
- }
- _notificationEvent.ReadableEvent.Signal();
- }
- }
- }
- public void SignalNewFriendRequest(UserId targetId)
- {
- lock (_lock)
- {
- if ((_permissionLevel & FriendServicePermissionLevel.ViewerMask) != 0 && _userId == targetId)
- {
- if (!_hasNewFriendRequest)
- {
- if (_notifications.Count == 100)
- {
- SignalFriendListUpdate(targetId);
- }
- NotificationInfo newFriendRequestNotification = new NotificationInfo
- {
- Type = NotificationEventType.NewFriendRequest
- };
- _notifications.AddLast(newFriendRequestNotification);
- _hasNewFriendRequest = true;
- }
- _notificationEvent.ReadableEvent.Signal();
- }
- }
- }
- protected override void Dispose(bool isDisposing)
- {
- if (isDisposing)
- {
- NotificationEventHandler.Instance.UnregisterNotificationService(this);
- }
- }
- }
- }
|