// Copyright (c) Arlo Godfrey. All Rights Reserved. // Licensed under the GNU Lesser General Public License, Version 3.0 with additional terms. // See the LICENSE, LICENSE.LESSER and LICENSE.ADDITIONAL files in the project root for more information. using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using CommunityToolkit.Diagnostics; using OwlCore.AbstractUI.Models; using OwlCore.Remoting; using StrixMusic.Sdk.AppModels; using StrixMusic.Sdk.Services; namespace StrixMusic.Sdk.Plugins.CoreRemote { /// /// A remoting-enabled wrapper for . /// [RemoteOptions(RemotingDirection.Bidirectional)] public sealed class RemoteNotificationService : IDisposable { private readonly INotificationService? _notificationService; private readonly MemberRemote _memberRemote; private readonly List _notificationMemberRemotes; /// /// Increments when a notification is displayed from this service, to provide unique IDs for remoting. /// private int _notificationTick; /// public int MaxActiveNotifications => _notificationService?.MaxActiveNotifications ?? 0; /// /// Creates a new instance of , wrapping an existing implementation. /// /// A consistent, unique identifier for synchronizing an instance of this service remotely. /// The notification service to wrap around. public RemoteNotificationService(string id, INotificationService notificationService) : this(id) { _memberRemote = new MemberRemote(this, $"{nameof(RemoteNotificationService)}.{id}", RemoteCoreMessageHandler.SingletonClient); _notificationService = notificationService; } /// /// Creates a new instance of . /// /// A consistent, unique identifier for synchronizing an instance of this service remotely. public RemoteNotificationService(string id) { _memberRemote = new MemberRemote(this, $"{nameof(RemoteNotificationService)}.{id}", RemoteCoreMessageHandler.SingletonHost); _notificationMemberRemotes = new List(); } private void AttachEvents() { if (_notificationService is null) return; _notificationService.NotificationRaised += OnNotificationRaised; _notificationService.NotificationDismissed += OnNotificationDismissed; } private void DetachEvents() { if (_notificationService is null) return; _notificationService.NotificationRaised -= OnNotificationRaised; _notificationService.NotificationDismissed -= OnNotificationDismissed; } private void OnNotificationRaised(object sender, Notification e) => OnNotificationRaised_Internal(e); private void OnNotificationDismissed(object sender, Notification e) => OnNotificationDismissed_Internal(e); [RemoteMethod] private void OnNotificationRaised_Internal(Notification notification) { NotificationRaised?.Invoke(this, notification); } [RemoteMethod] private void OnNotificationDismissed_Internal(Notification notification) { NotificationDismissed?.Invoke(this, notification); var target = _notificationMemberRemotes.FirstOrDefault(x => x.Id == notification.AbstractUICollection.Id); if (!(target is null)) _notificationMemberRemotes.Remove(target); target?.Dispose(); } /// public event EventHandler? NotificationRaised; /// public event EventHandler? NotificationDismissed; /// [RemoteMethod] public Task RaiseNotification(string title, string message = "") => Task.Run(async () => { if (_memberRemote.Mode == RemotingMode.Client) { Guard.IsNotNull(_notificationService, nameof(_notificationService)); var notification = _notificationService.RaiseNotification(title, message); _notificationMemberRemotes.Add(new MemberRemote(notification, notification.AbstractUICollection.Id)); await _memberRemote.PublishDataAsync($"{_notificationTick++}", notification); return notification; } else if (_memberRemote.Mode == RemotingMode.Host) { var data = await _memberRemote.ReceiveDataAsync($"{_notificationTick++}"); Guard.IsNotNull(data, nameof(data)); return data; } else { return ThrowHelper.ThrowNotSupportedException(); } }); /// [RemoteMethod] public Task RaiseNotification(AbstractUICollection elementGroup) => Task.Run(async () => { if (_memberRemote.Mode == RemotingMode.Client) { Guard.IsNotNull(_notificationService, nameof(_notificationService)); var notification = _notificationService.RaiseNotification(elementGroup); _notificationMemberRemotes.Add(new MemberRemote(notification, notification.AbstractUICollection.Id)); await _memberRemote.PublishDataAsync($"{_notificationTick++}", notification); return notification; } else if (_memberRemote.Mode == RemotingMode.Host) { var data = await _memberRemote.ReceiveDataAsync($"{_notificationTick++}"); Guard.IsNotNull(data, nameof(data)); return data; } else { return ThrowHelper.ThrowNotSupportedException(); } }); /// public void Dispose() { _memberRemote.Dispose(); DetachEvents(); } } }