From b54594a03a32dd02b5a639d98a6dba433b7648d8 Mon Sep 17 00:00:00 2001 From: Felipe Cardozo Date: Fri, 28 Apr 2023 18:12:40 -0300 Subject: [PATCH 1/6] Better coroutine error handling --- Runtime/Scripts/Helpers/CoroutineUtils.cs | 46 +++++++++++++++++++ .../Scripts/Helpers/CoroutineUtils.cs.meta | 11 +++++ .../Helpers/UnityMainThreadDispatcher.cs | 2 +- Runtime/Scripts/TezosAPI/Tezos.cs | 8 +++- .../Scripts/DemoExample/CopyToClipboard.cs | 12 +++-- .../DemoExample/Core/ExampleManager.cs | 34 +++++++------- Samples~/Scripts/DemoExample/UIManager.cs | 17 ++++++- 7 files changed, 107 insertions(+), 23 deletions(-) create mode 100644 Runtime/Scripts/Helpers/CoroutineUtils.cs create mode 100644 Runtime/Scripts/Helpers/CoroutineUtils.cs.meta diff --git a/Runtime/Scripts/Helpers/CoroutineUtils.cs b/Runtime/Scripts/Helpers/CoroutineUtils.cs new file mode 100644 index 00000000..dc60ab8c --- /dev/null +++ b/Runtime/Scripts/Helpers/CoroutineUtils.cs @@ -0,0 +1,46 @@ +using System; +using UnityEngine; +using System.Collections; + +public static class CoroutineUtils +{ + public static Coroutine TryWith( + MonoBehaviour monoBehaviour, + IEnumerator coroutine, + Action exceptionHandler = null) + { + return monoBehaviour.StartCoroutine(Try(coroutine, exceptionHandler)); + } + + public static IEnumerator Try( + IEnumerator coroutine, + Action exceptionHandler = null) + { + while (true) + { + object current; + try + { + if (coroutine.MoveNext() == false) + { + break; + } + current = coroutine.Current; + } + catch (Exception ex) + { + if (exceptionHandler == null) + { + Debug.LogError(ex); + } + else + { + exceptionHandler?.Invoke(ex); + } + yield break; + } + yield return current; + } + exceptionHandler?.Invoke(null); + } +} \ No newline at end of file diff --git a/Runtime/Scripts/Helpers/CoroutineUtils.cs.meta b/Runtime/Scripts/Helpers/CoroutineUtils.cs.meta new file mode 100644 index 00000000..01a6d296 --- /dev/null +++ b/Runtime/Scripts/Helpers/CoroutineUtils.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 01662ee29bc60473fb4d1b17ea46642d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Scripts/Helpers/UnityMainThreadDispatcher.cs b/Runtime/Scripts/Helpers/UnityMainThreadDispatcher.cs index deaff111..a91aad08 100644 --- a/Runtime/Scripts/Helpers/UnityMainThreadDispatcher.cs +++ b/Runtime/Scripts/Helpers/UnityMainThreadDispatcher.cs @@ -45,7 +45,7 @@ public void Enqueue(IEnumerator action) { lock (_executionQueue) { - _executionQueue.Enqueue(() => { StartCoroutine(action); }); + _executionQueue.Enqueue(() => { CoroutineUtils.TryWith(this, action); }); } } diff --git a/Runtime/Scripts/TezosAPI/Tezos.cs b/Runtime/Scripts/TezosAPI/Tezos.cs index 469a47b2..bf534775 100644 --- a/Runtime/Scripts/TezosAPI/Tezos.cs +++ b/Runtime/Scripts/TezosAPI/Tezos.cs @@ -84,7 +84,13 @@ private void InitBeaconConnector() { var json = JsonSerializer.Deserialize(transaction); var transactionHash = json.GetProperty("transactionHash").GetString(); - MessageReceiver.StartCoroutine(MessageReceiver.ContractCallInjection(_indexerNode, transactionHash)); + CoroutineUtils.TryWith(MessageReceiver, + MessageReceiver.ContractCallInjection(_indexerNode, transactionHash), + (ex) => + { + if (ex != null) + Debug.Log("An exception related to Tezos ContractCallInjection: " + ex); + }); }; } diff --git a/Samples~/Scripts/DemoExample/CopyToClipboard.cs b/Samples~/Scripts/DemoExample/CopyToClipboard.cs index f97a1a3b..ff97a6ea 100644 --- a/Samples~/Scripts/DemoExample/CopyToClipboard.cs +++ b/Samples~/Scripts/DemoExample/CopyToClipboard.cs @@ -19,16 +19,22 @@ public void OnPointerClick(PointerEventData eventData) { if (_blockCopy) return; - + #if UNITY_WEBGL inputField.gameObject.SetActive(true); inputField.text = text.text; text.gameObject.SetActive(false); #endif - + // copy text to the clipboard GUIUtility.systemCopyBuffer = text.text; - CoroutineRunner.Instance.StartCoroutine(OnTextCopied()); + CoroutineUtils.TryWith(CoroutineRunner.Instance, + OnTextCopied(), + (ex) => + { + if (ex != null) + Debug.Log("An exception related to CopyToClipboard: " + ex); + }); } IEnumerator OnTextCopied() diff --git a/Samples~/Scripts/DemoExample/Core/ExampleManager.cs b/Samples~/Scripts/DemoExample/Core/ExampleManager.cs index 21c0b210..92ef4802 100644 --- a/Samples~/Scripts/DemoExample/Core/ExampleManager.cs +++ b/Samples~/Scripts/DemoExample/Core/ExampleManager.cs @@ -42,12 +42,12 @@ public void FetchInventoryItems(Action> callback) var entrypoint = "view_items_of"; var input = new { @string = sender }; - CoroutineRunner.Instance.StartCoroutine( - _tezos.ReadView(contractAddress, entrypoint, input, result => + CoroutineUtils.TryWith(CoroutineRunner.Instance, + _tezos.ReadView(contractAddress, entrypoint, input, result => { Debug.Log("READING INVENTORY DATA"); // deserialize the json data to inventory items - CoroutineRunner.Instance.StartCoroutine( + CoroutineUtils.TryWith(CoroutineRunner.Instance, BeaconSDK.NetezosExtensions.HumanizeValue(result, _networkRPC, destination, "humanizeInventory", (ContractInventoryViewResult[] inventory) => OnInventoryFetched(inventory, callback)) ); @@ -127,14 +127,15 @@ public void FetchMarketItems(Action> callback) Prim = PrimType.Unit }; - CoroutineRunner.Instance.StartCoroutine( - _tezos.ReadView(contractAddress, entrypoint, input, result => + CoroutineUtils.TryWith(CoroutineRunner.Instance, + _tezos.ReadView(contractAddress, entrypoint, input, result => { - // deserialize the json data to market items - CoroutineRunner.Instance.StartCoroutine( + Debug.Log("READING INVENTORY DATA"); + // deserialize the json data to inventory items + CoroutineUtils.TryWith(CoroutineRunner.Instance, BeaconSDK.NetezosExtensions.HumanizeValue(result, _networkRPC, destination, "humanizeMarketplace", (ContractMarketplaceViewResult[] market) => OnMarketplaceFetched(market, callback)) - ); + ); })); } @@ -217,7 +218,7 @@ public User GetCurrentUser() public void GetBalance(Action callback) { var routine = _tezos.ReadBalance(callback); - CoroutineRunner.Instance.StartCoroutine(routine); + CoroutineUtils.TryWith(CoroutineRunner.Instance, routine); } public void GetSoftBalance(Action callback) @@ -239,13 +240,13 @@ private void GetSoftBalanceRoutine(Action callback) } }; - CoroutineRunner.Instance.StartCoroutine( + CoroutineUtils.TryWith(CoroutineRunner.Instance, _tezos.ReadView(contractAddress, "get_balance", input, result => - { - var intProp = result.GetProperty("int"); - var intValue = Convert.ToInt32(intProp.ToString()); - callback(intValue); - })); + { + var intProp = result.GetProperty("int"); + var intValue = Convert.ToInt32(intProp.ToString()); + callback(intValue); + })); } public void TransferItem(int itemID, int amount, string address) @@ -347,7 +348,8 @@ public void IsItemOnMarket(int itemID, string owner, Action callback) } }; - CoroutineRunner.Instance.StartCoroutine( + + CoroutineUtils.TryWith(CoroutineRunner.Instance, _tezos.ReadView(contractAddress, entrypoint, input, result => { var boolString = result.GetProperty("prim"); diff --git a/Samples~/Scripts/DemoExample/UIManager.cs b/Samples~/Scripts/DemoExample/UIManager.cs index 0127e6bf..98d10717 100644 --- a/Samples~/Scripts/DemoExample/UIManager.cs +++ b/Samples~/Scripts/DemoExample/UIManager.cs @@ -98,7 +98,13 @@ private void PopulateInventory(List items) inventory.Init(items); loadingPanel.SetActive(false); }; - StartCoroutine(DoActionNextFrame(action)); + CoroutineUtils.TryWith(this, + DoActionNextFrame(action), + (ex) => + { + if (ex != null) + Debug.Log("An exception related to PopulateInventory: " + ex); + }); } private void PopulateMarket(List items) @@ -108,7 +114,14 @@ private void PopulateMarket(List items) market.Init(items); loadingPanel.SetActive(false); }; - StartCoroutine(DoActionNextFrame(action)); + + CoroutineUtils.TryWith(this, + DoActionNextFrame(action), + (ex) => + { + if (ex != null) + Debug.Log("An exception related to PopulateMarket: " + ex); + }); } private IEnumerator DoActionNextFrame(Action action) From 1e243100d95d8eb3ef45686164ac2ff89f16f9cc Mon Sep 17 00:00:00 2001 From: Felipe Cardozo Date: Tue, 2 May 2023 17:15:45 -0300 Subject: [PATCH 2/6] Use CoroutineUtils.Try in the WrappedRequest method --- Runtime/Scripts/Helpers/CoroutineRunner.cs | 27 +++++ ...rapper.cs.meta => CoroutineRunner.cs.meta} | 2 +- Runtime/Scripts/Helpers/CoroutineUtils.cs | 3 +- Runtime/Scripts/Helpers/CoroutineWrapper.cs | 99 ------------------- Runtime/Scripts/TezosAPI/HttpClient.cs | 7 +- 5 files changed, 32 insertions(+), 106 deletions(-) create mode 100644 Runtime/Scripts/Helpers/CoroutineRunner.cs rename Runtime/Scripts/Helpers/{CoroutineWrapper.cs.meta => CoroutineRunner.cs.meta} (83%) delete mode 100644 Runtime/Scripts/Helpers/CoroutineWrapper.cs diff --git a/Runtime/Scripts/Helpers/CoroutineRunner.cs b/Runtime/Scripts/Helpers/CoroutineRunner.cs new file mode 100644 index 00000000..93cfc967 --- /dev/null +++ b/Runtime/Scripts/Helpers/CoroutineRunner.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections; +using UnityEngine; + +/// +/// Helper class that will allow to run a coroutine +/// +public class CoroutineRunner : MonoBehaviour +{ + private static CoroutineRunner _instance; + + public static CoroutineRunner Instance + { + get + { + if (_instance == null) + _instance = (new GameObject("CoroutineRunner")).AddComponent(); + + return _instance; + } + } + + private void Awake() + { + DontDestroyOnLoad(gameObject); + } +} diff --git a/Runtime/Scripts/Helpers/CoroutineWrapper.cs.meta b/Runtime/Scripts/Helpers/CoroutineRunner.cs.meta similarity index 83% rename from Runtime/Scripts/Helpers/CoroutineWrapper.cs.meta rename to Runtime/Scripts/Helpers/CoroutineRunner.cs.meta index e602a490..8fa57ae7 100644 --- a/Runtime/Scripts/Helpers/CoroutineWrapper.cs.meta +++ b/Runtime/Scripts/Helpers/CoroutineRunner.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 39830bc66b1aa4e8ca77da851c0a25ff +guid: dd493b835c5e842799b48829edd361be MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Runtime/Scripts/Helpers/CoroutineUtils.cs b/Runtime/Scripts/Helpers/CoroutineUtils.cs index dc60ab8c..4ad36a89 100644 --- a/Runtime/Scripts/Helpers/CoroutineUtils.cs +++ b/Runtime/Scripts/Helpers/CoroutineUtils.cs @@ -41,6 +41,5 @@ public static IEnumerator Try( } yield return current; } - exceptionHandler?.Invoke(null); } -} \ No newline at end of file +} diff --git a/Runtime/Scripts/Helpers/CoroutineWrapper.cs b/Runtime/Scripts/Helpers/CoroutineWrapper.cs deleted file mode 100644 index 5a053885..00000000 --- a/Runtime/Scripts/Helpers/CoroutineWrapper.cs +++ /dev/null @@ -1,99 +0,0 @@ -using System; -using System.Collections; -using UnityEngine; - -/// -/// Wraps a coroutine allowing to extract the result when it's completed -/// -/// Type of result expected -public class CoroutineWrapper : IEnumerator -{ - /// - /// Event raised when the coroutine is complete - /// - public readonly Action Completed; - - private readonly IEnumerator _targetCoroutine; - - /// - /// Exception triggered during the execution of the coroutine. - /// - public Exception Exception { get; private set; } - - /// - public object Current { get; private set; } - - /// - /// Result extracted from the coroutine when it's complete - /// - public T Result { get; private set; } - - /// - /// Create an instance of the wrapper - /// - /// Coroutine that will be executed - /// Callback that will be called when the coroutine is complete - public CoroutineWrapper(IEnumerator coroutine, Action callback = null) - { - _targetCoroutine = coroutine; - if (callback != null) - { - Completed += callback; - } - } - - /// - public bool MoveNext() - { - try - { - if (_targetCoroutine.MoveNext()) - { - Current = _targetCoroutine.Current; - return true; - } - - Result = (T)_targetCoroutine.Current; - Current = _targetCoroutine.Current; - Completed?.Invoke(Result); - return false; - } - catch (Exception e) - { - Debug.LogError("Exception " + e.Message); - Exception = e; - Completed?.Invoke(default); - return false; - } - } - - /// - public void Reset() - { - _targetCoroutine.Reset(); - } -} - -/// -/// Helper class that will allow to run a coroutine -/// -public class CoroutineRunner : MonoBehaviour -{ - private static CoroutineRunner _instance; - - public static CoroutineRunner Instance - { - get - { - if (_instance == null) - _instance = (new GameObject("CoroutineRunner")).AddComponent(); - - return _instance; - } - } - - private void Awake() - { - DontDestroyOnLoad(gameObject); - } -} \ No newline at end of file diff --git a/Runtime/Scripts/TezosAPI/HttpClient.cs b/Runtime/Scripts/TezosAPI/HttpClient.cs index d9262261..d20543f2 100644 --- a/Runtime/Scripts/TezosAPI/HttpClient.cs +++ b/Runtime/Scripts/TezosAPI/HttpClient.cs @@ -64,10 +64,9 @@ private UnityWebRequest GetUnityWebRequest(string method, string path) public static IEnumerator WrappedRequest(IEnumerator op, Action callback) { - var counterRoutine = new CoroutineWrapper(op); + var counterRoutine = CoroutineUtils.Try(op); yield return counterRoutine; - var counter = counterRoutine.Result; - callback?.Invoke(counter); + callback?.Invoke((T) counterRoutine.Current); } } @@ -77,4 +76,4 @@ internal static class HttpHeaders public static KeyValuePair Accept => new("Accept", "application/json"); public static KeyValuePair UserAgent => new("User-Agent", "tezos-unity-sdk"); } -} \ No newline at end of file +} From 6c22a6b1a1c6d4080d2da10cec83507ab8f41196 Mon Sep 17 00:00:00 2001 From: Felipe Cardozo Date: Fri, 5 May 2023 13:25:59 -0300 Subject: [PATCH 3/6] Revert "Use CoroutineUtils.Try in the WrappedRequest method" This reverts commit 1e243100d95d8eb3ef45686164ac2ff89f16f9cc. --- Runtime/Scripts/Helpers/CoroutineRunner.cs | 27 ----- Runtime/Scripts/Helpers/CoroutineUtils.cs | 3 +- Runtime/Scripts/Helpers/CoroutineWrapper.cs | 99 +++++++++++++++++++ ...unner.cs.meta => CoroutineWrapper.cs.meta} | 2 +- Runtime/Scripts/TezosAPI/HttpClient.cs | 7 +- 5 files changed, 106 insertions(+), 32 deletions(-) delete mode 100644 Runtime/Scripts/Helpers/CoroutineRunner.cs create mode 100644 Runtime/Scripts/Helpers/CoroutineWrapper.cs rename Runtime/Scripts/Helpers/{CoroutineRunner.cs.meta => CoroutineWrapper.cs.meta} (83%) diff --git a/Runtime/Scripts/Helpers/CoroutineRunner.cs b/Runtime/Scripts/Helpers/CoroutineRunner.cs deleted file mode 100644 index 93cfc967..00000000 --- a/Runtime/Scripts/Helpers/CoroutineRunner.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Collections; -using UnityEngine; - -/// -/// Helper class that will allow to run a coroutine -/// -public class CoroutineRunner : MonoBehaviour -{ - private static CoroutineRunner _instance; - - public static CoroutineRunner Instance - { - get - { - if (_instance == null) - _instance = (new GameObject("CoroutineRunner")).AddComponent(); - - return _instance; - } - } - - private void Awake() - { - DontDestroyOnLoad(gameObject); - } -} diff --git a/Runtime/Scripts/Helpers/CoroutineUtils.cs b/Runtime/Scripts/Helpers/CoroutineUtils.cs index 4ad36a89..dc60ab8c 100644 --- a/Runtime/Scripts/Helpers/CoroutineUtils.cs +++ b/Runtime/Scripts/Helpers/CoroutineUtils.cs @@ -41,5 +41,6 @@ public static IEnumerator Try( } yield return current; } + exceptionHandler?.Invoke(null); } -} +} \ No newline at end of file diff --git a/Runtime/Scripts/Helpers/CoroutineWrapper.cs b/Runtime/Scripts/Helpers/CoroutineWrapper.cs new file mode 100644 index 00000000..5a053885 --- /dev/null +++ b/Runtime/Scripts/Helpers/CoroutineWrapper.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections; +using UnityEngine; + +/// +/// Wraps a coroutine allowing to extract the result when it's completed +/// +/// Type of result expected +public class CoroutineWrapper : IEnumerator +{ + /// + /// Event raised when the coroutine is complete + /// + public readonly Action Completed; + + private readonly IEnumerator _targetCoroutine; + + /// + /// Exception triggered during the execution of the coroutine. + /// + public Exception Exception { get; private set; } + + /// + public object Current { get; private set; } + + /// + /// Result extracted from the coroutine when it's complete + /// + public T Result { get; private set; } + + /// + /// Create an instance of the wrapper + /// + /// Coroutine that will be executed + /// Callback that will be called when the coroutine is complete + public CoroutineWrapper(IEnumerator coroutine, Action callback = null) + { + _targetCoroutine = coroutine; + if (callback != null) + { + Completed += callback; + } + } + + /// + public bool MoveNext() + { + try + { + if (_targetCoroutine.MoveNext()) + { + Current = _targetCoroutine.Current; + return true; + } + + Result = (T)_targetCoroutine.Current; + Current = _targetCoroutine.Current; + Completed?.Invoke(Result); + return false; + } + catch (Exception e) + { + Debug.LogError("Exception " + e.Message); + Exception = e; + Completed?.Invoke(default); + return false; + } + } + + /// + public void Reset() + { + _targetCoroutine.Reset(); + } +} + +/// +/// Helper class that will allow to run a coroutine +/// +public class CoroutineRunner : MonoBehaviour +{ + private static CoroutineRunner _instance; + + public static CoroutineRunner Instance + { + get + { + if (_instance == null) + _instance = (new GameObject("CoroutineRunner")).AddComponent(); + + return _instance; + } + } + + private void Awake() + { + DontDestroyOnLoad(gameObject); + } +} \ No newline at end of file diff --git a/Runtime/Scripts/Helpers/CoroutineRunner.cs.meta b/Runtime/Scripts/Helpers/CoroutineWrapper.cs.meta similarity index 83% rename from Runtime/Scripts/Helpers/CoroutineRunner.cs.meta rename to Runtime/Scripts/Helpers/CoroutineWrapper.cs.meta index 8fa57ae7..e602a490 100644 --- a/Runtime/Scripts/Helpers/CoroutineRunner.cs.meta +++ b/Runtime/Scripts/Helpers/CoroutineWrapper.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: dd493b835c5e842799b48829edd361be +guid: 39830bc66b1aa4e8ca77da851c0a25ff MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Runtime/Scripts/TezosAPI/HttpClient.cs b/Runtime/Scripts/TezosAPI/HttpClient.cs index d20543f2..d9262261 100644 --- a/Runtime/Scripts/TezosAPI/HttpClient.cs +++ b/Runtime/Scripts/TezosAPI/HttpClient.cs @@ -64,9 +64,10 @@ private UnityWebRequest GetUnityWebRequest(string method, string path) public static IEnumerator WrappedRequest(IEnumerator op, Action callback) { - var counterRoutine = CoroutineUtils.Try(op); + var counterRoutine = new CoroutineWrapper(op); yield return counterRoutine; - callback?.Invoke((T) counterRoutine.Current); + var counter = counterRoutine.Result; + callback?.Invoke(counter); } } @@ -76,4 +77,4 @@ internal static class HttpHeaders public static KeyValuePair Accept => new("Accept", "application/json"); public static KeyValuePair UserAgent => new("User-Agent", "tezos-unity-sdk"); } -} +} \ No newline at end of file From e2d1274df15c98279811eee1cda5d14dbf0f1edb Mon Sep 17 00:00:00 2001 From: Felipe Cardozo Date: Fri, 5 May 2023 13:26:01 -0300 Subject: [PATCH 4/6] Revert "Better coroutine error handling" This reverts commit b54594a03a32dd02b5a639d98a6dba433b7648d8. --- Runtime/Scripts/Helpers/CoroutineUtils.cs | 46 ------------------- .../Scripts/Helpers/CoroutineUtils.cs.meta | 11 ----- .../Helpers/UnityMainThreadDispatcher.cs | 2 +- Runtime/Scripts/TezosAPI/Tezos.cs | 8 +--- .../Scripts/DemoExample/CopyToClipboard.cs | 12 ++--- .../DemoExample/Core/ExampleManager.cs | 34 +++++++------- Samples~/Scripts/DemoExample/UIManager.cs | 17 +------ 7 files changed, 23 insertions(+), 107 deletions(-) delete mode 100644 Runtime/Scripts/Helpers/CoroutineUtils.cs delete mode 100644 Runtime/Scripts/Helpers/CoroutineUtils.cs.meta diff --git a/Runtime/Scripts/Helpers/CoroutineUtils.cs b/Runtime/Scripts/Helpers/CoroutineUtils.cs deleted file mode 100644 index dc60ab8c..00000000 --- a/Runtime/Scripts/Helpers/CoroutineUtils.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System; -using UnityEngine; -using System.Collections; - -public static class CoroutineUtils -{ - public static Coroutine TryWith( - MonoBehaviour monoBehaviour, - IEnumerator coroutine, - Action exceptionHandler = null) - { - return monoBehaviour.StartCoroutine(Try(coroutine, exceptionHandler)); - } - - public static IEnumerator Try( - IEnumerator coroutine, - Action exceptionHandler = null) - { - while (true) - { - object current; - try - { - if (coroutine.MoveNext() == false) - { - break; - } - current = coroutine.Current; - } - catch (Exception ex) - { - if (exceptionHandler == null) - { - Debug.LogError(ex); - } - else - { - exceptionHandler?.Invoke(ex); - } - yield break; - } - yield return current; - } - exceptionHandler?.Invoke(null); - } -} \ No newline at end of file diff --git a/Runtime/Scripts/Helpers/CoroutineUtils.cs.meta b/Runtime/Scripts/Helpers/CoroutineUtils.cs.meta deleted file mode 100644 index 01a6d296..00000000 --- a/Runtime/Scripts/Helpers/CoroutineUtils.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 01662ee29bc60473fb4d1b17ea46642d -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/Scripts/Helpers/UnityMainThreadDispatcher.cs b/Runtime/Scripts/Helpers/UnityMainThreadDispatcher.cs index a91aad08..deaff111 100644 --- a/Runtime/Scripts/Helpers/UnityMainThreadDispatcher.cs +++ b/Runtime/Scripts/Helpers/UnityMainThreadDispatcher.cs @@ -45,7 +45,7 @@ public void Enqueue(IEnumerator action) { lock (_executionQueue) { - _executionQueue.Enqueue(() => { CoroutineUtils.TryWith(this, action); }); + _executionQueue.Enqueue(() => { StartCoroutine(action); }); } } diff --git a/Runtime/Scripts/TezosAPI/Tezos.cs b/Runtime/Scripts/TezosAPI/Tezos.cs index bf534775..469a47b2 100644 --- a/Runtime/Scripts/TezosAPI/Tezos.cs +++ b/Runtime/Scripts/TezosAPI/Tezos.cs @@ -84,13 +84,7 @@ private void InitBeaconConnector() { var json = JsonSerializer.Deserialize(transaction); var transactionHash = json.GetProperty("transactionHash").GetString(); - CoroutineUtils.TryWith(MessageReceiver, - MessageReceiver.ContractCallInjection(_indexerNode, transactionHash), - (ex) => - { - if (ex != null) - Debug.Log("An exception related to Tezos ContractCallInjection: " + ex); - }); + MessageReceiver.StartCoroutine(MessageReceiver.ContractCallInjection(_indexerNode, transactionHash)); }; } diff --git a/Samples~/Scripts/DemoExample/CopyToClipboard.cs b/Samples~/Scripts/DemoExample/CopyToClipboard.cs index ff97a6ea..f97a1a3b 100644 --- a/Samples~/Scripts/DemoExample/CopyToClipboard.cs +++ b/Samples~/Scripts/DemoExample/CopyToClipboard.cs @@ -19,22 +19,16 @@ public void OnPointerClick(PointerEventData eventData) { if (_blockCopy) return; - + #if UNITY_WEBGL inputField.gameObject.SetActive(true); inputField.text = text.text; text.gameObject.SetActive(false); #endif - + // copy text to the clipboard GUIUtility.systemCopyBuffer = text.text; - CoroutineUtils.TryWith(CoroutineRunner.Instance, - OnTextCopied(), - (ex) => - { - if (ex != null) - Debug.Log("An exception related to CopyToClipboard: " + ex); - }); + CoroutineRunner.Instance.StartCoroutine(OnTextCopied()); } IEnumerator OnTextCopied() diff --git a/Samples~/Scripts/DemoExample/Core/ExampleManager.cs b/Samples~/Scripts/DemoExample/Core/ExampleManager.cs index 92ef4802..21c0b210 100644 --- a/Samples~/Scripts/DemoExample/Core/ExampleManager.cs +++ b/Samples~/Scripts/DemoExample/Core/ExampleManager.cs @@ -42,12 +42,12 @@ public void FetchInventoryItems(Action> callback) var entrypoint = "view_items_of"; var input = new { @string = sender }; - CoroutineUtils.TryWith(CoroutineRunner.Instance, - _tezos.ReadView(contractAddress, entrypoint, input, result => + CoroutineRunner.Instance.StartCoroutine( + _tezos.ReadView(contractAddress, entrypoint, input, result => { Debug.Log("READING INVENTORY DATA"); // deserialize the json data to inventory items - CoroutineUtils.TryWith(CoroutineRunner.Instance, + CoroutineRunner.Instance.StartCoroutine( BeaconSDK.NetezosExtensions.HumanizeValue(result, _networkRPC, destination, "humanizeInventory", (ContractInventoryViewResult[] inventory) => OnInventoryFetched(inventory, callback)) ); @@ -127,15 +127,14 @@ public void FetchMarketItems(Action> callback) Prim = PrimType.Unit }; - CoroutineUtils.TryWith(CoroutineRunner.Instance, - _tezos.ReadView(contractAddress, entrypoint, input, result => + CoroutineRunner.Instance.StartCoroutine( + _tezos.ReadView(contractAddress, entrypoint, input, result => { - Debug.Log("READING INVENTORY DATA"); - // deserialize the json data to inventory items - CoroutineUtils.TryWith(CoroutineRunner.Instance, + // deserialize the json data to market items + CoroutineRunner.Instance.StartCoroutine( BeaconSDK.NetezosExtensions.HumanizeValue(result, _networkRPC, destination, "humanizeMarketplace", (ContractMarketplaceViewResult[] market) => OnMarketplaceFetched(market, callback)) - ); + ); })); } @@ -218,7 +217,7 @@ public User GetCurrentUser() public void GetBalance(Action callback) { var routine = _tezos.ReadBalance(callback); - CoroutineUtils.TryWith(CoroutineRunner.Instance, routine); + CoroutineRunner.Instance.StartCoroutine(routine); } public void GetSoftBalance(Action callback) @@ -240,13 +239,13 @@ private void GetSoftBalanceRoutine(Action callback) } }; - CoroutineUtils.TryWith(CoroutineRunner.Instance, + CoroutineRunner.Instance.StartCoroutine( _tezos.ReadView(contractAddress, "get_balance", input, result => - { - var intProp = result.GetProperty("int"); - var intValue = Convert.ToInt32(intProp.ToString()); - callback(intValue); - })); + { + var intProp = result.GetProperty("int"); + var intValue = Convert.ToInt32(intProp.ToString()); + callback(intValue); + })); } public void TransferItem(int itemID, int amount, string address) @@ -348,8 +347,7 @@ public void IsItemOnMarket(int itemID, string owner, Action callback) } }; - - CoroutineUtils.TryWith(CoroutineRunner.Instance, + CoroutineRunner.Instance.StartCoroutine( _tezos.ReadView(contractAddress, entrypoint, input, result => { var boolString = result.GetProperty("prim"); diff --git a/Samples~/Scripts/DemoExample/UIManager.cs b/Samples~/Scripts/DemoExample/UIManager.cs index 98d10717..0127e6bf 100644 --- a/Samples~/Scripts/DemoExample/UIManager.cs +++ b/Samples~/Scripts/DemoExample/UIManager.cs @@ -98,13 +98,7 @@ private void PopulateInventory(List items) inventory.Init(items); loadingPanel.SetActive(false); }; - CoroutineUtils.TryWith(this, - DoActionNextFrame(action), - (ex) => - { - if (ex != null) - Debug.Log("An exception related to PopulateInventory: " + ex); - }); + StartCoroutine(DoActionNextFrame(action)); } private void PopulateMarket(List items) @@ -114,14 +108,7 @@ private void PopulateMarket(List items) market.Init(items); loadingPanel.SetActive(false); }; - - CoroutineUtils.TryWith(this, - DoActionNextFrame(action), - (ex) => - { - if (ex != null) - Debug.Log("An exception related to PopulateMarket: " + ex); - }); + StartCoroutine(DoActionNextFrame(action)); } private IEnumerator DoActionNextFrame(Action action) From 6c06be283c72c02cb309ddc7daf184a134527c9b Mon Sep 17 00:00:00 2001 From: Felipe Cardozo Date: Fri, 5 May 2023 18:43:41 -0300 Subject: [PATCH 5/6] Add error handling for CoroutineWrapper --- Runtime/Scripts/Helpers/CoroutineWrapper.cs | 28 ++++++++++++++++--- Runtime/Scripts/Helpers/NetezosExtensions.cs | 6 ++-- .../Helpers/UnityMainThreadDispatcher.cs | 5 +++- Runtime/Scripts/TezosAPI/HttpClient.cs | 8 ------ Runtime/Scripts/TezosAPI/Tezos.cs | 4 +-- .../Scripts/DemoExample/CopyToClipboard.cs | 2 +- .../DemoExample/Core/ExampleManager.cs | 14 +++++----- Samples~/Scripts/DemoExample/UIManager.cs | 4 +-- 8 files changed, 43 insertions(+), 28 deletions(-) diff --git a/Runtime/Scripts/Helpers/CoroutineWrapper.cs b/Runtime/Scripts/Helpers/CoroutineWrapper.cs index 5a053885..2d2bb0fd 100644 --- a/Runtime/Scripts/Helpers/CoroutineWrapper.cs +++ b/Runtime/Scripts/Helpers/CoroutineWrapper.cs @@ -12,6 +12,10 @@ public class CoroutineWrapper : IEnumerator /// Event raised when the coroutine is complete /// public readonly Action Completed; + /// + /// Event raised when the coroutine throws an exception + /// + public readonly Action ErrorHandler; private readonly IEnumerator _targetCoroutine; @@ -33,13 +37,18 @@ public class CoroutineWrapper : IEnumerator /// /// Coroutine that will be executed /// Callback that will be called when the coroutine is complete - public CoroutineWrapper(IEnumerator coroutine, Action callback = null) + /// Callback that will be called when the coroutine throws an exception + public CoroutineWrapper(IEnumerator coroutine, Action callback = null, Action errorHandler = null) { _targetCoroutine = coroutine; if (callback != null) { Completed += callback; } + if (errorHandler != null) + { + ErrorHandler += errorHandler; + } } /// @@ -60,9 +69,15 @@ public bool MoveNext() } catch (Exception e) { - Debug.LogError("Exception " + e.Message); Exception = e; - Completed?.Invoke(default); + if (ErrorHandler == null) + { + Debug.LogError($"Exception: {e.Message}"); + } + else + { + ErrorHandler?.Invoke(e); + } return false; } } @@ -92,8 +107,13 @@ public static CoroutineRunner Instance } } + public Coroutine StartCoroutineWrapper(IEnumerator coroutine) + { + return StartCoroutine(new CoroutineWrapper(coroutine, null, (exception) => Debug.LogError($"Exception on Coroutine: {exception.Message}"))); + } + private void Awake() { DontDestroyOnLoad(gameObject); } -} \ No newline at end of file +} diff --git a/Runtime/Scripts/Helpers/NetezosExtensions.cs b/Runtime/Scripts/Helpers/NetezosExtensions.cs index d3f74f66..091d5a46 100644 --- a/Runtime/Scripts/Helpers/NetezosExtensions.cs +++ b/Runtime/Scripts/Helpers/NetezosExtensions.cs @@ -22,7 +22,7 @@ public static IEnumerator ReadTZBalance(string rpcUri, string sender, Action(sender); - return HttpClient.WrappedRequest(getBalanceRequest, callback); + return new CoroutineWrapper(getBalanceRequest, callback); } public static IEnumerator ReadView(string rpcUri, string destination, string entrypoint, @@ -31,7 +31,7 @@ public static IEnumerator ReadView(string rpcUri, string destination, string ent var rpc = new Rpc(rpcUri); var runViewOp = rpc.RunView(destination, entrypoint, input); - return HttpClient.WrappedRequest(runViewOp, (JsonElement result) => + return new CoroutineWrapper(runViewOp, (JsonElement result) => { if (result.ValueKind != JsonValueKind.Null && result.ValueKind != JsonValueKind.Undefined && result.TryGetProperty("data", out var val)) @@ -57,7 +57,7 @@ private static IEnumerator FetchContractCode(string rpcUri, string contract) if (_contracts.ContainsKey(contract)) yield break; var rpc = new Rpc(rpcUri); var scriptOp = rpc.GetContractCode(contract); - yield return HttpClient.WrappedRequest(scriptOp, (JsonElement script) => + yield return new CoroutineWrapper(scriptOp, (JsonElement script) => { var codeElement = script.GetProperty("code").GetRawText(); var code = Micheline.FromJson(codeElement); diff --git a/Runtime/Scripts/Helpers/UnityMainThreadDispatcher.cs b/Runtime/Scripts/Helpers/UnityMainThreadDispatcher.cs index deaff111..04de46fa 100644 --- a/Runtime/Scripts/Helpers/UnityMainThreadDispatcher.cs +++ b/Runtime/Scripts/Helpers/UnityMainThreadDispatcher.cs @@ -45,7 +45,10 @@ public void Enqueue(IEnumerator action) { lock (_executionQueue) { - _executionQueue.Enqueue(() => { StartCoroutine(action); }); + var coroutine = new CoroutineWrapper(action, null, (exception) => Debug.LogError($"Exception on MainThread Queue: {exception.Message}")); + _executionQueue.Enqueue(() => { + StartCoroutine(coroutine); + }); } } diff --git a/Runtime/Scripts/TezosAPI/HttpClient.cs b/Runtime/Scripts/TezosAPI/HttpClient.cs index d9262261..1a2dd2ec 100644 --- a/Runtime/Scripts/TezosAPI/HttpClient.cs +++ b/Runtime/Scripts/TezosAPI/HttpClient.cs @@ -61,14 +61,6 @@ private UnityWebRequest GetUnityWebRequest(string method, string path) request.timeout = RequestTimeout; return request; } - - public static IEnumerator WrappedRequest(IEnumerator op, Action callback) - { - var counterRoutine = new CoroutineWrapper(op); - yield return counterRoutine; - var counter = counterRoutine.Result; - callback?.Invoke(counter); - } } internal static class HttpHeaders diff --git a/Runtime/Scripts/TezosAPI/Tezos.cs b/Runtime/Scripts/TezosAPI/Tezos.cs index 469a47b2..3fb4d802 100644 --- a/Runtime/Scripts/TezosAPI/Tezos.cs +++ b/Runtime/Scripts/TezosAPI/Tezos.cs @@ -84,7 +84,7 @@ private void InitBeaconConnector() { var json = JsonSerializer.Deserialize(transaction); var transactionHash = json.GetProperty("transactionHash").GetString(); - MessageReceiver.StartCoroutine(MessageReceiver.ContractCallInjection(_indexerNode, transactionHash)); + MessageReceiver.StartCoroutine(new CoroutineWrapper(MessageReceiver.ContractCallInjection(_indexerNode, transactionHash))); }; } @@ -167,7 +167,7 @@ TokensForOwnerOrder orderBy $"limit={maxItems}"; var requestRoutine = GetJson>(url); - return WrappedRequest(requestRoutine, cb); + return new CoroutineWrapper>(requestRoutine, cb); } } } \ No newline at end of file diff --git a/Samples~/Scripts/DemoExample/CopyToClipboard.cs b/Samples~/Scripts/DemoExample/CopyToClipboard.cs index f97a1a3b..f110dc3f 100644 --- a/Samples~/Scripts/DemoExample/CopyToClipboard.cs +++ b/Samples~/Scripts/DemoExample/CopyToClipboard.cs @@ -28,7 +28,7 @@ public void OnPointerClick(PointerEventData eventData) // copy text to the clipboard GUIUtility.systemCopyBuffer = text.text; - CoroutineRunner.Instance.StartCoroutine(OnTextCopied()); + CoroutineRunner.Instance.StartCoroutineWrapper(OnTextCopied()); } IEnumerator OnTextCopied() diff --git a/Samples~/Scripts/DemoExample/Core/ExampleManager.cs b/Samples~/Scripts/DemoExample/Core/ExampleManager.cs index 21c0b210..49b6dd58 100644 --- a/Samples~/Scripts/DemoExample/Core/ExampleManager.cs +++ b/Samples~/Scripts/DemoExample/Core/ExampleManager.cs @@ -42,12 +42,12 @@ public void FetchInventoryItems(Action> callback) var entrypoint = "view_items_of"; var input = new { @string = sender }; - CoroutineRunner.Instance.StartCoroutine( + CoroutineRunner.Instance.StartCoroutineWrapper( _tezos.ReadView(contractAddress, entrypoint, input, result => { Debug.Log("READING INVENTORY DATA"); // deserialize the json data to inventory items - CoroutineRunner.Instance.StartCoroutine( + CoroutineRunner.Instance.StartCoroutineWrapper( BeaconSDK.NetezosExtensions.HumanizeValue(result, _networkRPC, destination, "humanizeInventory", (ContractInventoryViewResult[] inventory) => OnInventoryFetched(inventory, callback)) ); @@ -127,11 +127,11 @@ public void FetchMarketItems(Action> callback) Prim = PrimType.Unit }; - CoroutineRunner.Instance.StartCoroutine( + CoroutineRunner.Instance.StartCoroutineWrapper( _tezos.ReadView(contractAddress, entrypoint, input, result => { // deserialize the json data to market items - CoroutineRunner.Instance.StartCoroutine( + CoroutineRunner.Instance.StartCoroutineWrapper( BeaconSDK.NetezosExtensions.HumanizeValue(result, _networkRPC, destination, "humanizeMarketplace", (ContractMarketplaceViewResult[] market) => OnMarketplaceFetched(market, callback)) ); @@ -217,7 +217,7 @@ public User GetCurrentUser() public void GetBalance(Action callback) { var routine = _tezos.ReadBalance(callback); - CoroutineRunner.Instance.StartCoroutine(routine); + CoroutineRunner.Instance.StartCoroutineWrapper(routine); } public void GetSoftBalance(Action callback) @@ -239,7 +239,7 @@ private void GetSoftBalanceRoutine(Action callback) } }; - CoroutineRunner.Instance.StartCoroutine( + CoroutineRunner.Instance.StartCoroutineWrapper( _tezos.ReadView(contractAddress, "get_balance", input, result => { var intProp = result.GetProperty("int"); @@ -347,7 +347,7 @@ public void IsItemOnMarket(int itemID, string owner, Action callback) } }; - CoroutineRunner.Instance.StartCoroutine( + CoroutineRunner.Instance.StartCoroutineWrapper( _tezos.ReadView(contractAddress, entrypoint, input, result => { var boolString = result.GetProperty("prim"); diff --git a/Samples~/Scripts/DemoExample/UIManager.cs b/Samples~/Scripts/DemoExample/UIManager.cs index 0127e6bf..5ed01a4e 100644 --- a/Samples~/Scripts/DemoExample/UIManager.cs +++ b/Samples~/Scripts/DemoExample/UIManager.cs @@ -98,7 +98,7 @@ private void PopulateInventory(List items) inventory.Init(items); loadingPanel.SetActive(false); }; - StartCoroutine(DoActionNextFrame(action)); + CoroutineRunner.Instance.StartCoroutineWrapper(DoActionNextFrame(action)); } private void PopulateMarket(List items) @@ -108,7 +108,7 @@ private void PopulateMarket(List items) market.Init(items); loadingPanel.SetActive(false); }; - StartCoroutine(DoActionNextFrame(action)); + CoroutineRunner.Instance.StartCoroutineWrapper(DoActionNextFrame(action)); } private IEnumerator DoActionNextFrame(Action action) From 5d3a46c29d5d94b37cc9b9c593ff959868b21853 Mon Sep 17 00:00:00 2001 From: Konstantin Karuna Date: Thu, 11 May 2023 17:24:07 +0300 Subject: [PATCH 6/6] Changelog updated --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 178e30d7..348bbae2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - [Bug](https://github.com/trilitech/tezos-unity-sdk/issues/57) with BeaconConnectorWebGl +### Added +- Better [coroutine error handling](https://github.com/trilitech/tezos-unity-sdk/issues/39) + ## [1.3.1] - 2023-04-27 ### Changed