Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better coroutine error handling #54

Merged
merged 7 commits into from
May 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
28 changes: 24 additions & 4 deletions Runtime/Scripts/Helpers/CoroutineWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ public class CoroutineWrapper<T> : IEnumerator
/// Event raised when the coroutine is complete
/// </summary>
public readonly Action<T> Completed;
/// <summary>
/// Event raised when the coroutine throws an exception
/// </summary>
public readonly Action<Exception> ErrorHandler;

private readonly IEnumerator _targetCoroutine;

Expand All @@ -33,13 +37,18 @@ public class CoroutineWrapper<T> : IEnumerator
/// </summary>
/// <param name="coroutine">Coroutine that will be executed</param>
/// <param name="callback">Callback that will be called when the coroutine is complete</param>
public CoroutineWrapper(IEnumerator coroutine, Action<T> callback = null)
/// <param name="errorHandler">Callback that will be called when the coroutine throws an exception</param>
public CoroutineWrapper(IEnumerator coroutine, Action<T> callback = null, Action<Exception> errorHandler = null)
{
_targetCoroutine = coroutine;
if (callback != null)
{
Completed += callback;
}
if (errorHandler != null)
{
ErrorHandler += errorHandler;
}
}

/// <inheritdoc/>
Expand All @@ -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;
}
}
Expand Down Expand Up @@ -92,8 +107,13 @@ public static CoroutineRunner Instance
}
}

public Coroutine StartCoroutineWrapper(IEnumerator coroutine)
{
return StartCoroutine(new CoroutineWrapper<object>(coroutine, null, (exception) => Debug.LogError($"Exception on Coroutine: {exception.Message}")));
}

private void Awake()
{
DontDestroyOnLoad(gameObject);
}
}
}
6 changes: 3 additions & 3 deletions Runtime/Scripts/Helpers/NetezosExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public static IEnumerator ReadTZBalance(string rpcUri, string sender, Action<ulo
{
var rpc = new Rpc(rpcUri);
var getBalanceRequest = rpc.GetTzBalance<ulong>(sender);
return HttpClient.WrappedRequest(getBalanceRequest, callback);
return new CoroutineWrapper<ulong>(getBalanceRequest, callback);
}

public static IEnumerator ReadView(string rpcUri, string destination, string entrypoint,
Expand All @@ -31,7 +31,7 @@ public static IEnumerator ReadView(string rpcUri, string destination, string ent
var rpc = new Rpc(rpcUri);
var runViewOp = rpc.RunView<JsonElement>(destination, entrypoint, input);

return HttpClient.WrappedRequest(runViewOp, (JsonElement result) =>
return new CoroutineWrapper<JsonElement>(runViewOp, (JsonElement result) =>
{
if (result.ValueKind != JsonValueKind.Null && result.ValueKind != JsonValueKind.Undefined &&
result.TryGetProperty("data", out var val))
Expand All @@ -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<JsonElement>(contract);
yield return HttpClient.WrappedRequest(scriptOp, (JsonElement script) =>
yield return new CoroutineWrapper<JsonElement>(scriptOp, (JsonElement script) =>
{
var codeElement = script.GetProperty("code").GetRawText();
var code = Micheline.FromJson(codeElement);
Expand Down
5 changes: 4 additions & 1 deletion Runtime/Scripts/Helpers/UnityMainThreadDispatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@ public void Enqueue(IEnumerator action)
{
lock (_executionQueue)
{
_executionQueue.Enqueue(() => { StartCoroutine(action); });
var coroutine = new CoroutineWrapper<object>(action, null, (exception) => Debug.LogError($"Exception on MainThread Queue: {exception.Message}"));
_executionQueue.Enqueue(() => {
StartCoroutine(coroutine);
});
}
}

Expand Down
8 changes: 0 additions & 8 deletions Runtime/Scripts/TezosAPI/HttpClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,6 @@ private UnityWebRequest GetUnityWebRequest(string method, string path)
request.timeout = RequestTimeout;
return request;
}

public static IEnumerator WrappedRequest<T>(IEnumerator op, Action<T> callback)
{
var counterRoutine = new CoroutineWrapper<T>(op);
yield return counterRoutine;
var counter = counterRoutine.Result;
callback?.Invoke(counter);
}
}

internal static class HttpHeaders
Expand Down
4 changes: 2 additions & 2 deletions Runtime/Scripts/TezosAPI/Tezos.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ private void InitBeaconConnector()
{
var json = JsonSerializer.Deserialize<JsonElement>(transaction);
var transactionHash = json.GetProperty("transactionHash").GetString();
MessageReceiver.StartCoroutine(MessageReceiver.ContractCallInjection(_indexerNode, transactionHash));
MessageReceiver.StartCoroutine(new CoroutineWrapper<object>(MessageReceiver.ContractCallInjection(_indexerNode, transactionHash)));
};
}

Expand Down Expand Up @@ -167,7 +167,7 @@ TokensForOwnerOrder orderBy
$"limit={maxItems}";

var requestRoutine = GetJson<IEnumerable<TokenBalance>>(url);
return WrappedRequest(requestRoutine, cb);
return new CoroutineWrapper<IEnumerable<TokenBalance>>(requestRoutine, cb);
}
}
}
2 changes: 1 addition & 1 deletion Samples~/Scripts/DemoExample/CopyToClipboard.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
14 changes: 7 additions & 7 deletions Samples~/Scripts/DemoExample/Core/ExampleManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ public void FetchInventoryItems(Action<List<IItemModel>> 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))
);
Expand Down Expand Up @@ -127,11 +127,11 @@ public void FetchMarketItems(Action<List<IItemModel>> 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))
);
Expand Down Expand Up @@ -216,7 +216,7 @@ public User GetCurrentUser()
public void GetBalance(Action<ulong> callback)
{
var routine = _tezos.ReadBalance(callback);
CoroutineRunner.Instance.StartCoroutine(routine);
CoroutineRunner.Instance.StartCoroutineWrapper(routine);
}

public void GetSoftBalance(Action<int> callback)
Expand All @@ -238,7 +238,7 @@ private void GetSoftBalanceRoutine(Action<int> callback)
}
};

CoroutineRunner.Instance.StartCoroutine(
CoroutineRunner.Instance.StartCoroutineWrapper(
_tezos.ReadView(contractAddress, "get_balance", input, result =>
{
var intProp = result.GetProperty("int");
Expand Down Expand Up @@ -343,7 +343,7 @@ public void IsItemOnMarket(int itemID, string owner, Action<bool> callback)
}
};

CoroutineRunner.Instance.StartCoroutine(
CoroutineRunner.Instance.StartCoroutineWrapper(
_tezos.ReadView(contractAddress, entrypoint, input, result =>
{
var boolString = result.GetProperty("prim");
Expand Down
4 changes: 2 additions & 2 deletions Samples~/Scripts/DemoExample/UIManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ private void PopulateInventory(List<IItemModel> items)
inventory.Init(items);
loadingPanel.SetActive(false);
};
StartCoroutine(DoActionNextFrame(action));
CoroutineRunner.Instance.StartCoroutineWrapper(DoActionNextFrame(action));
}

private void PopulateMarket(List<IItemModel> items)
Expand All @@ -108,7 +108,7 @@ private void PopulateMarket(List<IItemModel> items)
market.Init(items);
loadingPanel.SetActive(false);
};
StartCoroutine(DoActionNextFrame(action));
CoroutineRunner.Instance.StartCoroutineWrapper(DoActionNextFrame(action));
}

private IEnumerator DoActionNextFrame(Action action)
Expand Down