From c663525f59b8eb1d0b476ff1202778b5bd5221cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Dobrza=C5=84ski?= Date: Wed, 20 Jul 2022 15:24:18 +0200 Subject: [PATCH 1/2] feat: dispatcher and publish extension --- .../PubNubUnity/Extensions/SdkExtensions.cs | 16 ++++ .../Extensions/SdkExtensions.cs.meta | 11 +++ .../Assets/PubNubUnity/Utils/Editor.meta | 8 ++ .../Utils/Editor/PNDispatcherEditor.cs | 12 +++ .../Utils/Editor/PNDispatcherEditor.cs.meta | 11 +++ .../Assets/PubNubUnity/Utils/PNDispatcher.cs | 81 +++++++++++++++++++ .../PubNubUnity/Utils/PNDispatcher.cs.meta | 11 +++ 7 files changed, 150 insertions(+) create mode 100644 PubNubUnity/Assets/PubNubUnity/Extensions/SdkExtensions.cs create mode 100644 PubNubUnity/Assets/PubNubUnity/Extensions/SdkExtensions.cs.meta create mode 100644 PubNubUnity/Assets/PubNubUnity/Utils/Editor.meta create mode 100644 PubNubUnity/Assets/PubNubUnity/Utils/Editor/PNDispatcherEditor.cs create mode 100644 PubNubUnity/Assets/PubNubUnity/Utils/Editor/PNDispatcherEditor.cs.meta create mode 100644 PubNubUnity/Assets/PubNubUnity/Utils/PNDispatcher.cs create mode 100644 PubNubUnity/Assets/PubNubUnity/Utils/PNDispatcher.cs.meta diff --git a/PubNubUnity/Assets/PubNubUnity/Extensions/SdkExtensions.cs b/PubNubUnity/Assets/PubNubUnity/Extensions/SdkExtensions.cs new file mode 100644 index 00000000..bc64a7af --- /dev/null +++ b/PubNubUnity/Assets/PubNubUnity/Extensions/SdkExtensions.cs @@ -0,0 +1,16 @@ +using PubnubApi; +using PubnubApi.EndPoint; +using PubNubUnity.Internal; + +namespace PubNubUnity { + public static class SdkExtensions { + /// + /// Execute the publish operation and run the callback upon completion. The callback is dispatched to Unity main thread + /// + /// Publish operation + /// Callback to run upon operation completion + public static void Execute(this PublishOperation operation, System.Action callback) { + operation.Execute(new PNPublishResultExt((a, b) => PNDispatcher.Dispatch(() => callback?.Invoke(a, b)))); + } + } +} diff --git a/PubNubUnity/Assets/PubNubUnity/Extensions/SdkExtensions.cs.meta b/PubNubUnity/Assets/PubNubUnity/Extensions/SdkExtensions.cs.meta new file mode 100644 index 00000000..f983e312 --- /dev/null +++ b/PubNubUnity/Assets/PubNubUnity/Extensions/SdkExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8544b57b7467fe94c97df53c5946d51a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/PubNubUnity/Assets/PubNubUnity/Utils/Editor.meta b/PubNubUnity/Assets/PubNubUnity/Utils/Editor.meta new file mode 100644 index 00000000..6a58fb2d --- /dev/null +++ b/PubNubUnity/Assets/PubNubUnity/Utils/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fad0b04c561290049aef3b9c9905eb49 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/PubNubUnity/Assets/PubNubUnity/Utils/Editor/PNDispatcherEditor.cs b/PubNubUnity/Assets/PubNubUnity/Utils/Editor/PNDispatcherEditor.cs new file mode 100644 index 00000000..c60f1f71 --- /dev/null +++ b/PubNubUnity/Assets/PubNubUnity/Utils/Editor/PNDispatcherEditor.cs @@ -0,0 +1,12 @@ +using UnityEditor; + +namespace PubNubUnity.Internal { + [CustomEditor(typeof(PNDispatcher))] + public class PNDispatcherEditor : Editor { + public class DispatcherEditor : Editor { + public override void OnInspectorGUI() { + EditorGUILayout.HelpBox("This script allows dispatching to the main Unity render thread", MessageType.Info); + } + } + } +} \ No newline at end of file diff --git a/PubNubUnity/Assets/PubNubUnity/Utils/Editor/PNDispatcherEditor.cs.meta b/PubNubUnity/Assets/PubNubUnity/Utils/Editor/PNDispatcherEditor.cs.meta new file mode 100644 index 00000000..1e65970b --- /dev/null +++ b/PubNubUnity/Assets/PubNubUnity/Utils/Editor/PNDispatcherEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f6184428bc11a3844be76626a046be94 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/PubNubUnity/Assets/PubNubUnity/Utils/PNDispatcher.cs b/PubNubUnity/Assets/PubNubUnity/Utils/PNDispatcher.cs new file mode 100644 index 00000000..76c70380 --- /dev/null +++ b/PubNubUnity/Assets/PubNubUnity/Utils/PNDispatcher.cs @@ -0,0 +1,81 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using UnityEngine; + +namespace PubNubUnity.Internal { + public class PNDispatcher : MonoBehaviour { + static PNDispatcher instance; + static object lockObject; + + static volatile Queue dispatchQueue = new Queue(); + + void FixedUpdate() { + HandleDispatch(); + } + + static void HandleDispatch() { + lock (lockObject) { + var c = dispatchQueue.Count; + for (int i = 0; i < c; i++) { + try { + dispatchQueue.Dequeue()(); + } catch (System.Exception e) { + // TODO investigate if we need more error handling mechanisms + Debug.LogError($"{e.Message} ::\n{e.StackTrace}"); + } + } + } + } + + /// + /// Dispatches the callback to Unity's main thread. Facilitates working on Unity's objects within the callback. + /// + /// Action to dispatch to main thread + public static void Dispatch(System.Action action) { + if (action is null) { + return; + } + + lock (lockObject) { + dispatchQueue.Enqueue(action); + } + } + + /// + /// Dispatch an async operation's result to the main thread. Facilitates working on Unity's objects within the callback. + /// + /// Async task to dispatch + /// Callback function which accepts task result as the argument + /// Task return type + public static async void DispatchTask(Task task, System.Action callback) { + if (callback is null) { + return; + } + + T res; + if (task.IsCompleted) { + res = task.Result; + } else { + res = await task; + } + + Dispatch(() => callback(res)); + } + + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] + static void Initialize() { + if (!instance) { + instance = new GameObject("[PubNub Dispatcher]").AddComponent(); + } + instance.gameObject.hideFlags = HideFlags.NotEditable | HideFlags.DontSave; + instance.transform.hideFlags = HideFlags.HideInInspector; + + // For future potential edit-mode dispatching + if (Application.isPlaying) { + DontDestroyOnLoad(instance.gameObject); + } + + lockObject ??= new object(); + } + } +} diff --git a/PubNubUnity/Assets/PubNubUnity/Utils/PNDispatcher.cs.meta b/PubNubUnity/Assets/PubNubUnity/Utils/PNDispatcher.cs.meta new file mode 100644 index 00000000..cb1daf34 --- /dev/null +++ b/PubNubUnity/Assets/PubNubUnity/Utils/PNDispatcher.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a535dff998692134baec58cef1e5aa15 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 6f77b2d0f562fa4c3c7011e1233a624f957d6dd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Dobrza=C5=84ski?= Date: Wed, 20 Jul 2022 15:24:18 +0200 Subject: [PATCH 2/2] feat: dispatcher and publish extension --- .../PubNubUnity/Extensions/SdkExtensions.cs | 16 ++++ .../Extensions/SdkExtensions.cs.meta | 11 +++ .../Assets/PubNubUnity/Utils/Editor.meta | 8 ++ .../Utils/Editor/PNDispatcherEditor.cs | 12 +++ .../Utils/Editor/PNDispatcherEditor.cs.meta | 11 +++ .../Assets/PubNubUnity/Utils/PNDispatcher.cs | 81 +++++++++++++++++++ .../PubNubUnity/Utils/PNDispatcher.cs.meta | 11 +++ 7 files changed, 150 insertions(+) create mode 100644 PubNubUnity/Assets/PubNubUnity/Extensions/SdkExtensions.cs create mode 100644 PubNubUnity/Assets/PubNubUnity/Extensions/SdkExtensions.cs.meta create mode 100644 PubNubUnity/Assets/PubNubUnity/Utils/Editor.meta create mode 100644 PubNubUnity/Assets/PubNubUnity/Utils/Editor/PNDispatcherEditor.cs create mode 100644 PubNubUnity/Assets/PubNubUnity/Utils/Editor/PNDispatcherEditor.cs.meta create mode 100644 PubNubUnity/Assets/PubNubUnity/Utils/PNDispatcher.cs create mode 100644 PubNubUnity/Assets/PubNubUnity/Utils/PNDispatcher.cs.meta diff --git a/PubNubUnity/Assets/PubNubUnity/Extensions/SdkExtensions.cs b/PubNubUnity/Assets/PubNubUnity/Extensions/SdkExtensions.cs new file mode 100644 index 00000000..bc64a7af --- /dev/null +++ b/PubNubUnity/Assets/PubNubUnity/Extensions/SdkExtensions.cs @@ -0,0 +1,16 @@ +using PubnubApi; +using PubnubApi.EndPoint; +using PubNubUnity.Internal; + +namespace PubNubUnity { + public static class SdkExtensions { + /// + /// Execute the publish operation and run the callback upon completion. The callback is dispatched to Unity main thread + /// + /// Publish operation + /// Callback to run upon operation completion + public static void Execute(this PublishOperation operation, System.Action callback) { + operation.Execute(new PNPublishResultExt((a, b) => PNDispatcher.Dispatch(() => callback?.Invoke(a, b)))); + } + } +} diff --git a/PubNubUnity/Assets/PubNubUnity/Extensions/SdkExtensions.cs.meta b/PubNubUnity/Assets/PubNubUnity/Extensions/SdkExtensions.cs.meta new file mode 100644 index 00000000..f983e312 --- /dev/null +++ b/PubNubUnity/Assets/PubNubUnity/Extensions/SdkExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8544b57b7467fe94c97df53c5946d51a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/PubNubUnity/Assets/PubNubUnity/Utils/Editor.meta b/PubNubUnity/Assets/PubNubUnity/Utils/Editor.meta new file mode 100644 index 00000000..6a58fb2d --- /dev/null +++ b/PubNubUnity/Assets/PubNubUnity/Utils/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fad0b04c561290049aef3b9c9905eb49 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/PubNubUnity/Assets/PubNubUnity/Utils/Editor/PNDispatcherEditor.cs b/PubNubUnity/Assets/PubNubUnity/Utils/Editor/PNDispatcherEditor.cs new file mode 100644 index 00000000..c60f1f71 --- /dev/null +++ b/PubNubUnity/Assets/PubNubUnity/Utils/Editor/PNDispatcherEditor.cs @@ -0,0 +1,12 @@ +using UnityEditor; + +namespace PubNubUnity.Internal { + [CustomEditor(typeof(PNDispatcher))] + public class PNDispatcherEditor : Editor { + public class DispatcherEditor : Editor { + public override void OnInspectorGUI() { + EditorGUILayout.HelpBox("This script allows dispatching to the main Unity render thread", MessageType.Info); + } + } + } +} \ No newline at end of file diff --git a/PubNubUnity/Assets/PubNubUnity/Utils/Editor/PNDispatcherEditor.cs.meta b/PubNubUnity/Assets/PubNubUnity/Utils/Editor/PNDispatcherEditor.cs.meta new file mode 100644 index 00000000..1e65970b --- /dev/null +++ b/PubNubUnity/Assets/PubNubUnity/Utils/Editor/PNDispatcherEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f6184428bc11a3844be76626a046be94 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/PubNubUnity/Assets/PubNubUnity/Utils/PNDispatcher.cs b/PubNubUnity/Assets/PubNubUnity/Utils/PNDispatcher.cs new file mode 100644 index 00000000..76c70380 --- /dev/null +++ b/PubNubUnity/Assets/PubNubUnity/Utils/PNDispatcher.cs @@ -0,0 +1,81 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using UnityEngine; + +namespace PubNubUnity.Internal { + public class PNDispatcher : MonoBehaviour { + static PNDispatcher instance; + static object lockObject; + + static volatile Queue dispatchQueue = new Queue(); + + void FixedUpdate() { + HandleDispatch(); + } + + static void HandleDispatch() { + lock (lockObject) { + var c = dispatchQueue.Count; + for (int i = 0; i < c; i++) { + try { + dispatchQueue.Dequeue()(); + } catch (System.Exception e) { + // TODO investigate if we need more error handling mechanisms + Debug.LogError($"{e.Message} ::\n{e.StackTrace}"); + } + } + } + } + + /// + /// Dispatches the callback to Unity's main thread. Facilitates working on Unity's objects within the callback. + /// + /// Action to dispatch to main thread + public static void Dispatch(System.Action action) { + if (action is null) { + return; + } + + lock (lockObject) { + dispatchQueue.Enqueue(action); + } + } + + /// + /// Dispatch an async operation's result to the main thread. Facilitates working on Unity's objects within the callback. + /// + /// Async task to dispatch + /// Callback function which accepts task result as the argument + /// Task return type + public static async void DispatchTask(Task task, System.Action callback) { + if (callback is null) { + return; + } + + T res; + if (task.IsCompleted) { + res = task.Result; + } else { + res = await task; + } + + Dispatch(() => callback(res)); + } + + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] + static void Initialize() { + if (!instance) { + instance = new GameObject("[PubNub Dispatcher]").AddComponent(); + } + instance.gameObject.hideFlags = HideFlags.NotEditable | HideFlags.DontSave; + instance.transform.hideFlags = HideFlags.HideInInspector; + + // For future potential edit-mode dispatching + if (Application.isPlaying) { + DontDestroyOnLoad(instance.gameObject); + } + + lockObject ??= new object(); + } + } +} diff --git a/PubNubUnity/Assets/PubNubUnity/Utils/PNDispatcher.cs.meta b/PubNubUnity/Assets/PubNubUnity/Utils/PNDispatcher.cs.meta new file mode 100644 index 00000000..cb1daf34 --- /dev/null +++ b/PubNubUnity/Assets/PubNubUnity/Utils/PNDispatcher.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a535dff998692134baec58cef1e5aa15 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: