From a35e5f929d575a7c084c2440367c166b24e11ec8 Mon Sep 17 00:00:00 2001 From: neuecc Date: Mon, 8 Feb 2021 19:09:02 +0900 Subject: [PATCH] UNITASK_WEBREQUEST_SUPPORT --- .../Assets/Editor/EditorRunnerChecker.cs | 5 +- .../Internal/UnityWebRequestExtensions.cs | 2 +- .../Plugins/UniTask/Runtime/UniTask.asmdef | 11 +- .../UniTask/Runtime/UnityAsyncExtensions.cs | 4 +- .../Runtime/UnityWebRequestException.cs | 2 +- src/UniTask/Assets/Scenes/MiddlewareSample.cs | 942 +++++++++--------- src/UniTask/Assets/Scenes/SandboxMain.cs | 64 +- .../Assets/TempAsm/FooMonoBehaviour.cs | 8 +- .../ProjectSettings/ProjectVersion.txt | 4 +- 9 files changed, 524 insertions(+), 518 deletions(-) diff --git a/src/UniTask/Assets/Editor/EditorRunnerChecker.cs b/src/UniTask/Assets/Editor/EditorRunnerChecker.cs index 46372f9..b91524d 100644 --- a/src/UniTask/Assets/Editor/EditorRunnerChecker.cs +++ b/src/UniTask/Assets/Editor/EditorRunnerChecker.cs @@ -20,8 +20,9 @@ public static class EditorRunnerChecker { Debug.Log("Start"); - var r = await UnityWebRequest.Get("https://bing.com/").SendWebRequest().ToUniTask(); - Debug.Log(r.downloadHandler.text.Substring(0, 100)); + //var r = await UnityWebRequest.Get("https://bing.com/").SendWebRequest().ToUniTask(); + //Debug.Log(r.downloadHandler.text.Substring(0, 100)); + await UniTask.Yield(); Debug.Log("End"); } diff --git a/src/UniTask/Assets/Plugins/UniTask/Runtime/Internal/UnityWebRequestExtensions.cs b/src/UniTask/Assets/Plugins/UniTask/Runtime/Internal/UnityWebRequestExtensions.cs index d09cbd2..0da9f5a 100644 --- a/src/UniTask/Assets/Plugins/UniTask/Runtime/Internal/UnityWebRequestExtensions.cs +++ b/src/UniTask/Assets/Plugins/UniTask/Runtime/Internal/UnityWebRequestExtensions.cs @@ -7,7 +7,7 @@ using UnityEngine.Networking; namespace Cysharp.Threading.Tasks.Internal { -#if ENABLE_UNITYWEBREQUEST && UNITASK_WEBREQUEST_SUPPORT +#if ENABLE_UNITYWEBREQUEST && (!UNITY_2019_1_OR_NEWER || UNITASK_WEBREQUEST_SUPPORT) internal static class UnityWebRequestResultExtensions { diff --git a/src/UniTask/Assets/Plugins/UniTask/Runtime/UniTask.asmdef b/src/UniTask/Assets/Plugins/UniTask/Runtime/UniTask.asmdef index 98c66a2..f82d22a 100644 --- a/src/UniTask/Assets/Plugins/UniTask/Runtime/UniTask.asmdef +++ b/src/UniTask/Assets/Plugins/UniTask/Runtime/UniTask.asmdef @@ -1,7 +1,7 @@ { "name": "UniTask", - "references": [ - ], + "rootNamespace": "", + "references": [], "includePlatforms": [], "excludePlatforms": [], "allowUnsafeCode": false, @@ -13,7 +13,7 @@ { "name": "com.unity.modules.assetbundle", "expression": "", - "define": "NITASK_ASSETBUNDLE_SUPPORT" + "define": "UNITASK_ASSETBUNDLE_SUPPORT" }, { "name": "com.unity.modules.physics", @@ -34,6 +34,11 @@ "name": "com.unity.ugui", "expression": "", "define": "UNITASK_UGUI_SUPPORT" + }, + { + "name": "com.unity.modules.unitywebrequestwww", + "expression": "", + "define": "UNITASK_WEBREQUEST_SUPPORT" } ], "noEngineReferences": false diff --git a/src/UniTask/Assets/Plugins/UniTask/Runtime/UnityAsyncExtensions.cs b/src/UniTask/Assets/Plugins/UniTask/Runtime/UnityAsyncExtensions.cs index 23e2783..ebb44d0 100644 --- a/src/UniTask/Assets/Plugins/UniTask/Runtime/UnityAsyncExtensions.cs +++ b/src/UniTask/Assets/Plugins/UniTask/Runtime/UnityAsyncExtensions.cs @@ -5,7 +5,7 @@ using System.Runtime.CompilerServices; using System.Threading; using UnityEngine; using Cysharp.Threading.Tasks.Internal; -#if !UNITY_2019_1_OR_NEWER && (ENABLE_UNITYWEBREQUEST && UNITASK_WEBREQUEST_SUPPORT) +#if ENABLE_UNITYWEBREQUEST && (!UNITY_2019_1_OR_NEWER || UNITASK_WEBREQUEST_SUPPORT) using UnityEngine.Networking; #endif @@ -1221,7 +1221,7 @@ namespace Cysharp.Threading.Tasks #endregion #endif -#if ENABLE_UNITYWEBREQUEST && UNITASK_WEBREQUEST_SUPPORT +#if ENABLE_UNITYWEBREQUEST && (!UNITY_2019_1_OR_NEWER || UNITASK_WEBREQUEST_SUPPORT) #region UnityWebRequestAsyncOperation public static UnityWebRequestAsyncOperationAwaiter GetAwaiter(this UnityWebRequestAsyncOperation asyncOperation) diff --git a/src/UniTask/Assets/Plugins/UniTask/Runtime/UnityWebRequestException.cs b/src/UniTask/Assets/Plugins/UniTask/Runtime/UnityWebRequestException.cs index 2386a74..d2a37ce 100644 --- a/src/UniTask/Assets/Plugins/UniTask/Runtime/UnityWebRequestException.cs +++ b/src/UniTask/Assets/Plugins/UniTask/Runtime/UnityWebRequestException.cs @@ -1,4 +1,4 @@ -#if ENABLE_UNITYWEBREQUEST +#if ENABLE_UNITYWEBREQUEST && (!UNITY_2019_1_OR_NEWER || UNITASK_WEBREQUEST_SUPPORT) using System; using System.Collections.Generic; diff --git a/src/UniTask/Assets/Scenes/MiddlewareSample.cs b/src/UniTask/Assets/Scenes/MiddlewareSample.cs index c64ca76..01ab778 100644 --- a/src/UniTask/Assets/Scenes/MiddlewareSample.cs +++ b/src/UniTask/Assets/Scenes/MiddlewareSample.cs @@ -1,471 +1,471 @@ -using Cysharp.Threading.Tasks; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using UnityEngine; -using UnityEngine.Networking; -using UnityEngine.SceneManagement; -using UnityEngine.UI; - -namespace Cysharp.Threading.Tasks.Sample -{ - //public class Sample2 - //{ - // public Sample2() - // { - // // デコレーターの詰まったClientを生成(これは一度作ったらフィールドに保存可) - // var client = new NetworkClient("http://localhost", TimeSpan.FromSeconds(10), - // new QueueRequestDecorator(), - // new LoggingDecorator(), - // new AppendTokenDecorator(), - // new SetupHeaderDecorator()); - - - // await client.PostAsync("/User/Register", new { Id = 100 }); - - - // } - //} - - - public class ReturnToTitleDecorator : IAsyncDecorator - { - public async UniTask SendAsync(RequestContext context, CancellationToken cancellationToken, Func> next) - { - try - { - return await next(context, cancellationToken); - } - catch (Exception ex) - { - if (ex is OperationCanceledException) - { - // キャンセルはきっと想定されている処理なのでそのまんまスルー(呼び出し側でOperationCanceledExceptionとして飛んでいく) - throw; - } - - if (ex is UnityWebRequestException uwe) - { - // ステータスコードを使って、タイトルに戻す例外です、とかリトライさせる例外です、とかハンドリングさせると便利 - // if (uwe.ResponseCode) { }... - } - - // サーバー例外のMessageを直接出すなんて乱暴なことはデバッグ時だけですよ勿論。 - var result = await MessageDialog.ShowAsync(ex.Message); - - // OK か Cancelかで分岐するなら。今回はボタン一個、OKのみの想定なので無視 - // if (result == DialogResult.Ok) { }... - - // シーン呼び出しはawaitしないこと!awaitして正常終了しちゃうと、この通信の呼び出し元に処理が戻って続行してしまいます - // のでForget。 - SceneManager.LoadSceneAsync("TitleScene").ToUniTask().Forget(); - - - // そしてOperationCanceledExceptionを投げて、この通信の呼び出し元の処理はキャンセル扱いにして終了させる - throw new OperationCanceledException(); - } - } - } - - public enum DialogResult - { - Ok, - Cancel - } - - public static class MessageDialog - { - public static async UniTask ShowAsync(string message) - { - // (例えば)Prefabで作っておいたダイアログを生成する - var view = await Resources.LoadAsync("Prefabs/Dialog"); - - // Ok, Cancelボタンのどちらかが押されるのを待機 - return await (view as GameObject).GetComponent().ClickResult; - } - } - - public class MessageDialogView : MonoBehaviour - { - [SerializeField] Button okButton = default; - [SerializeField] Button closeButton = default; - - UniTaskCompletionSource taskCompletion; - - // これでどちらかが押されるまで無限に待つを表現 - public UniTask ClickResult => taskCompletion.Task; - - private void Start() - { - taskCompletion = new UniTaskCompletionSource(); - - okButton.onClick.AddListener(() => - { - taskCompletion.TrySetResult(DialogResult.Ok); - }); - - closeButton.onClick.AddListener(() => - { - taskCompletion.TrySetResult(DialogResult.Cancel); - }); - } - - // もしボタンが押されずに消滅した場合にネンノタメ。 - private void OnDestroy() - { - taskCompletion.TrySetResult(DialogResult.Cancel); - } - } - - public class MockDecorator : IAsyncDecorator - { - Dictionary mock; - - // Pathと型を1:1にして事前定義したオブジェクトを返す辞書を渡す - public MockDecorator(Dictionary mock) - { - this.mock = mock; - } - - public UniTask SendAsync(RequestContext context, CancellationToken cancellationToken, Func> next) - { - if (mock.TryGetValue(context.Path, out var value)) - { - // 一致したものがあればそれを返す(実際の通信は行わない) - return new UniTask(new ResponseContext(value)); - } - else - { - return next(context, cancellationToken); - } - } - } - - //public class LoggingDecorator : IAsyncDecorator - //{ - // public async UniTask SendAsync(RequestContext context, CancellationToken cancellationToken, Func> next) - // { - // var sw = Stopwatch.StartNew(); - // try - // { - // UnityEngine.Debug.Log("Start Network Request:" + context.Path); - - // var response = await next(context, cancellationToken); - - // UnityEngine.Debug.Log($"Complete Network Request: {context.Path} , Elapsed: {sw.Elapsed}, Size: {response.GetRawData().Length}"); - - // return response; - // } - // catch (Exception ex) - // { - // if (ex is OperationCanceledException) - // { - // UnityEngine.Debug.Log("Request Canceled:" + context.Path); - // } - // else if (ex is TimeoutException) - // { - // UnityEngine.Debug.Log("Request Timeout:" + context.Path); - // } - // else if (ex is UnityWebRequestException webex) - // { - // if (webex.IsHttpError) - // { - // UnityEngine.Debug.Log($"Request HttpError: {context.Path} Code:{webex.ResponseCode} Message:{webex.Message}"); - // } - // else if (webex.IsNetworkError) - // { - // UnityEngine.Debug.Log($"Request NetworkError: {context.Path} Code:{webex.ResponseCode} Message:{webex.Message}"); - // } - // } - // throw; - // } - // finally - // { - // /* log other */ - // } - // } - //} - - public class SetupHeaderDecorator : IAsyncDecorator - { - public async UniTask SendAsync(RequestContext context, CancellationToken cancellationToken, Func> next) - { - context.RequestHeaders["x-app-timestamp"] = context.Timestamp.ToString(); - context.RequestHeaders["x-user-id"] = "132141411"; // どこかから持ってくる - context.RequestHeaders["x-access-token"] = "fafafawfafewaea"; // どこかから持ってくる2 - - var respsonse = await next(context, cancellationToken); - - var nextToken = respsonse.ResponseHeaders["token"]; - // UserProfile.Token = nextToken; // どこかにセットするということにする - - return respsonse; - } - } - - - public class AppendTokenDecorator : IAsyncDecorator - { - public async UniTask SendAsync(RequestContext context, CancellationToken cancellationToken, Func> next) - { - string token = "token"; // どっかから取ってくるということにする - RETRY: - try - { - context.RequestHeaders["x-accesss-token"] = token; - return await next(context, cancellationToken); - } - catch (UnityWebRequestException ex) - { - // 例えば700はTokenを再取得してください的な意味だったとする - if (ex.ResponseCode == 700) - { - // 別口でTokenを取得します的な処理 - var newToken = await new NetworkClient(context.BasePath, context.Timeout).PostAsync("/Auth/GetToken", "access_token", cancellationToken); - context.Reset(this); - goto RETRY; - } - - goto RETRY; - } - } - } - - public class QueueRequestDecorator : IAsyncDecorator - { - readonly Queue<(UniTaskCompletionSource, RequestContext, CancellationToken, Func>)> q = new Queue<(UniTaskCompletionSource, RequestContext, CancellationToken, Func>)>(); - bool running; - - public async UniTask SendAsync(RequestContext context, CancellationToken cancellationToken, Func> next) - { - if (q.Count == 0) - { - return await next(context, cancellationToken); - } - else - { - var completionSource = new UniTaskCompletionSource(); - q.Enqueue((completionSource, context, cancellationToken, next)); - if (!running) - { - Run().Forget(); - } - return await completionSource.Task; - } - } - - async UniTaskVoid Run() - { - running = true; - try - { - while (q.Count != 0) - { - var (tcs, context, cancellationToken, next) = q.Dequeue(); - try - { - var response = await next(context, cancellationToken); - tcs.TrySetResult(response); - } - catch (Exception ex) - { - tcs.TrySetException(ex); - } - } - } - finally - { - running = false; - } - } - } - - - public class RequestContext - { - int decoratorIndex; - readonly IAsyncDecorator[] decorators; - Dictionary headers; - - public string BasePath { get; } - public string Path { get; } - public object Value { get; } - public TimeSpan Timeout { get; } - public DateTimeOffset Timestamp { get; private set; } - - public IDictionary RequestHeaders - { - get - { - if (headers == null) - { - headers = new Dictionary(); - } - return headers; - } - } - - public RequestContext(string basePath, string path, object value, TimeSpan timeout, IAsyncDecorator[] filters) - { - this.decoratorIndex = -1; - this.decorators = filters; - this.BasePath = basePath; - this.Path = path; - this.Value = value; - this.Timeout = timeout; - this.Timestamp = DateTimeOffset.UtcNow; - } - - internal Dictionary GetRawHeaders() => headers; - internal IAsyncDecorator GetNextDecorator() => decorators[++decoratorIndex]; - - public void Reset(IAsyncDecorator currentFilter) - { - decoratorIndex = Array.IndexOf(decorators, currentFilter); - if (headers != null) - { - headers.Clear(); - } - Timestamp = DateTimeOffset.UtcNow; - } - } - - public class ResponseContext - { - bool hasValue; - object value; - readonly byte[] bytes; - - public long StatusCode { get; } - public Dictionary ResponseHeaders { get; } - - public ResponseContext(object value, Dictionary header = null) - { - this.hasValue = true; - this.value = value; - this.StatusCode = 200; - this.ResponseHeaders = (header ?? new Dictionary()); - } - - public ResponseContext(byte[] bytes, long statusCode, Dictionary responseHeaders) - { - this.hasValue = false; - this.bytes = bytes; - this.StatusCode = statusCode; - this.ResponseHeaders = responseHeaders; - } - - public byte[] GetRawData() => bytes; - - public T GetResponseAs() - { - if (hasValue) - { - return (T)value; - } - - value = JsonUtility.FromJson(Encoding.UTF8.GetString(bytes)); - hasValue = true; - return (T)value; - } - } - - public interface IAsyncDecorator - { - UniTask SendAsync(RequestContext context, CancellationToken cancellationToken, Func> next); - } - - - public class NetworkClient : IAsyncDecorator - { - readonly Func> next; - readonly IAsyncDecorator[] decorators; - readonly TimeSpan timeout; - readonly IProgress progress; - readonly string basePath; - - public NetworkClient(string basePath, TimeSpan timeout, params IAsyncDecorator[] decorators) - : this(basePath, timeout, null, decorators) - { - } - - public NetworkClient(string basePath, TimeSpan timeout, IProgress progress, params IAsyncDecorator[] decorators) - { - this.next = InvokeRecursive; // setup delegate - - this.basePath = basePath; - this.timeout = timeout; - this.progress = progress; - this.decorators = new IAsyncDecorator[decorators.Length + 1]; - Array.Copy(decorators, this.decorators, decorators.Length); - this.decorators[this.decorators.Length - 1] = this; - } - - public async UniTask PostAsync(string path, T value, CancellationToken cancellationToken = default) - { - var request = new RequestContext(basePath, path, value, timeout, decorators); - var response = await InvokeRecursive(request, cancellationToken); - return response.GetResponseAs(); - } - - - UniTask InvokeRecursive(RequestContext context, CancellationToken cancellationToken) - { - return context.GetNextDecorator().SendAsync(context, cancellationToken, next); // マジカル再帰処理 - } - - async UniTask IAsyncDecorator.SendAsync(RequestContext context, CancellationToken cancellationToken, Func> _) - { - // Postしか興味ないからPostにしかしないよ! - // パフォーマンスを最大限にしたい場合はuploadHandler, downloadHandlerをカスタマイズすること - - // JSONでbodyに送るというパラメータで送るという雑設定。 - var data = JsonUtility.ToJson(context.Value); - var formData = new Dictionary { { "body", data } }; - - using (var req = UnityWebRequest.Post(basePath + context.Path, formData)) - { - var header = context.GetRawHeaders(); - if (header != null) - { - foreach (var item in header) - { - req.SetRequestHeader(item.Key, item.Value); - } - } - - // Timeout処理はCancellationTokenSourceのCancelAfterSlim(UniTask拡張)を使ってサクッと処理 - var linkToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); - linkToken.CancelAfterSlim(timeout); - try - { - // 完了待ちや終了処理はUniTaskの拡張自体に丸投げ - await req.SendWebRequest().ToUniTask(progress: progress, cancellationToken: linkToken.Token); - } - catch (OperationCanceledException) - { - // 元キャンセレーションソースがキャンセルしてなければTimeoutによるものと判定 - if (!cancellationToken.IsCancellationRequested) - { - throw new TimeoutException(); - } - } - finally - { - // Timeoutに引っかからなかった場合にてるのでCancelAfterSlimの裏で回ってるループをこれで終わらせとく - if (!linkToken.IsCancellationRequested) - { - linkToken.Cancel(); - } - } - - // UnityWebRequestを先にDisposeしちゃうので先に必要なものを取得しておく(性能的には無駄なのでパフォーマンスを最大限にしたい場合は更に一工夫を) - return new ResponseContext(req.downloadHandler.data, req.responseCode, req.GetResponseHeaders()); - } - } - } -} \ No newline at end of file +//using Cysharp.Threading.Tasks; +//using System; +//using System.Collections.Generic; +//using System.Diagnostics; +//using System.Linq; +//using System.Text; +//using System.Threading; +//using System.Threading.Tasks; +//using UnityEngine; +//using UnityEngine.Networking; +//using UnityEngine.SceneManagement; +//using UnityEngine.UI; + +//namespace Cysharp.Threading.Tasks.Sample +//{ +// //public class Sample2 +// //{ +// // public Sample2() +// // { +// // // デコレーターの詰まったClientを生成(これは一度作ったらフィールドに保存可) +// // var client = new NetworkClient("http://localhost", TimeSpan.FromSeconds(10), +// // new QueueRequestDecorator(), +// // new LoggingDecorator(), +// // new AppendTokenDecorator(), +// // new SetupHeaderDecorator()); + + +// // await client.PostAsync("/User/Register", new { Id = 100 }); + + +// // } +// //} + + +// public class ReturnToTitleDecorator : IAsyncDecorator +// { +// public async UniTask SendAsync(RequestContext context, CancellationToken cancellationToken, Func> next) +// { +// try +// { +// return await next(context, cancellationToken); +// } +// catch (Exception ex) +// { +// if (ex is OperationCanceledException) +// { +// // キャンセルはきっと想定されている処理なのでそのまんまスルー(呼び出し側でOperationCanceledExceptionとして飛んでいく) +// throw; +// } + +// if (ex is UnityWebRequestException uwe) +// { +// // ステータスコードを使って、タイトルに戻す例外です、とかリトライさせる例外です、とかハンドリングさせると便利 +// // if (uwe.ResponseCode) { }... +// } + +// // サーバー例外のMessageを直接出すなんて乱暴なことはデバッグ時だけですよ勿論。 +// var result = await MessageDialog.ShowAsync(ex.Message); + +// // OK か Cancelかで分岐するなら。今回はボタン一個、OKのみの想定なので無視 +// // if (result == DialogResult.Ok) { }... + +// // シーン呼び出しはawaitしないこと!awaitして正常終了しちゃうと、この通信の呼び出し元に処理が戻って続行してしまいます +// // のでForget。 +// SceneManager.LoadSceneAsync("TitleScene").ToUniTask().Forget(); + + +// // そしてOperationCanceledExceptionを投げて、この通信の呼び出し元の処理はキャンセル扱いにして終了させる +// throw new OperationCanceledException(); +// } +// } +// } + +// public enum DialogResult +// { +// Ok, +// Cancel +// } + +// public static class MessageDialog +// { +// public static async UniTask ShowAsync(string message) +// { +// // (例えば)Prefabで作っておいたダイアログを生成する +// var view = await Resources.LoadAsync("Prefabs/Dialog"); + +// // Ok, Cancelボタンのどちらかが押されるのを待機 +// return await (view as GameObject).GetComponent().ClickResult; +// } +// } + +// public class MessageDialogView : MonoBehaviour +// { +// [SerializeField] Button okButton = default; +// [SerializeField] Button closeButton = default; + +// UniTaskCompletionSource taskCompletion; + +// // これでどちらかが押されるまで無限に待つを表現 +// public UniTask ClickResult => taskCompletion.Task; + +// private void Start() +// { +// taskCompletion = new UniTaskCompletionSource(); + +// okButton.onClick.AddListener(() => +// { +// taskCompletion.TrySetResult(DialogResult.Ok); +// }); + +// closeButton.onClick.AddListener(() => +// { +// taskCompletion.TrySetResult(DialogResult.Cancel); +// }); +// } + +// // もしボタンが押されずに消滅した場合にネンノタメ。 +// private void OnDestroy() +// { +// taskCompletion.TrySetResult(DialogResult.Cancel); +// } +// } + +// public class MockDecorator : IAsyncDecorator +// { +// Dictionary mock; + +// // Pathと型を1:1にして事前定義したオブジェクトを返す辞書を渡す +// public MockDecorator(Dictionary mock) +// { +// this.mock = mock; +// } + +// public UniTask SendAsync(RequestContext context, CancellationToken cancellationToken, Func> next) +// { +// if (mock.TryGetValue(context.Path, out var value)) +// { +// // 一致したものがあればそれを返す(実際の通信は行わない) +// return new UniTask(new ResponseContext(value)); +// } +// else +// { +// return next(context, cancellationToken); +// } +// } +// } + +// //public class LoggingDecorator : IAsyncDecorator +// //{ +// // public async UniTask SendAsync(RequestContext context, CancellationToken cancellationToken, Func> next) +// // { +// // var sw = Stopwatch.StartNew(); +// // try +// // { +// // UnityEngine.Debug.Log("Start Network Request:" + context.Path); + +// // var response = await next(context, cancellationToken); + +// // UnityEngine.Debug.Log($"Complete Network Request: {context.Path} , Elapsed: {sw.Elapsed}, Size: {response.GetRawData().Length}"); + +// // return response; +// // } +// // catch (Exception ex) +// // { +// // if (ex is OperationCanceledException) +// // { +// // UnityEngine.Debug.Log("Request Canceled:" + context.Path); +// // } +// // else if (ex is TimeoutException) +// // { +// // UnityEngine.Debug.Log("Request Timeout:" + context.Path); +// // } +// // else if (ex is UnityWebRequestException webex) +// // { +// // if (webex.IsHttpError) +// // { +// // UnityEngine.Debug.Log($"Request HttpError: {context.Path} Code:{webex.ResponseCode} Message:{webex.Message}"); +// // } +// // else if (webex.IsNetworkError) +// // { +// // UnityEngine.Debug.Log($"Request NetworkError: {context.Path} Code:{webex.ResponseCode} Message:{webex.Message}"); +// // } +// // } +// // throw; +// // } +// // finally +// // { +// // /* log other */ +// // } +// // } +// //} + +// public class SetupHeaderDecorator : IAsyncDecorator +// { +// public async UniTask SendAsync(RequestContext context, CancellationToken cancellationToken, Func> next) +// { +// context.RequestHeaders["x-app-timestamp"] = context.Timestamp.ToString(); +// context.RequestHeaders["x-user-id"] = "132141411"; // どこかから持ってくる +// context.RequestHeaders["x-access-token"] = "fafafawfafewaea"; // どこかから持ってくる2 + +// var respsonse = await next(context, cancellationToken); + +// var nextToken = respsonse.ResponseHeaders["token"]; +// // UserProfile.Token = nextToken; // どこかにセットするということにする + +// return respsonse; +// } +// } + + +// public class AppendTokenDecorator : IAsyncDecorator +// { +// public async UniTask SendAsync(RequestContext context, CancellationToken cancellationToken, Func> next) +// { +// string token = "token"; // どっかから取ってくるということにする +// RETRY: +// try +// { +// context.RequestHeaders["x-accesss-token"] = token; +// return await next(context, cancellationToken); +// } +// catch (UnityWebRequestException ex) +// { +// // 例えば700はTokenを再取得してください的な意味だったとする +// if (ex.ResponseCode == 700) +// { +// // 別口でTokenを取得します的な処理 +// var newToken = await new NetworkClient(context.BasePath, context.Timeout).PostAsync("/Auth/GetToken", "access_token", cancellationToken); +// context.Reset(this); +// goto RETRY; +// } + +// goto RETRY; +// } +// } +// } + +// public class QueueRequestDecorator : IAsyncDecorator +// { +// readonly Queue<(UniTaskCompletionSource, RequestContext, CancellationToken, Func>)> q = new Queue<(UniTaskCompletionSource, RequestContext, CancellationToken, Func>)>(); +// bool running; + +// public async UniTask SendAsync(RequestContext context, CancellationToken cancellationToken, Func> next) +// { +// if (q.Count == 0) +// { +// return await next(context, cancellationToken); +// } +// else +// { +// var completionSource = new UniTaskCompletionSource(); +// q.Enqueue((completionSource, context, cancellationToken, next)); +// if (!running) +// { +// Run().Forget(); +// } +// return await completionSource.Task; +// } +// } + +// async UniTaskVoid Run() +// { +// running = true; +// try +// { +// while (q.Count != 0) +// { +// var (tcs, context, cancellationToken, next) = q.Dequeue(); +// try +// { +// var response = await next(context, cancellationToken); +// tcs.TrySetResult(response); +// } +// catch (Exception ex) +// { +// tcs.TrySetException(ex); +// } +// } +// } +// finally +// { +// running = false; +// } +// } +// } + + +// public class RequestContext +// { +// int decoratorIndex; +// readonly IAsyncDecorator[] decorators; +// Dictionary headers; + +// public string BasePath { get; } +// public string Path { get; } +// public object Value { get; } +// public TimeSpan Timeout { get; } +// public DateTimeOffset Timestamp { get; private set; } + +// public IDictionary RequestHeaders +// { +// get +// { +// if (headers == null) +// { +// headers = new Dictionary(); +// } +// return headers; +// } +// } + +// public RequestContext(string basePath, string path, object value, TimeSpan timeout, IAsyncDecorator[] filters) +// { +// this.decoratorIndex = -1; +// this.decorators = filters; +// this.BasePath = basePath; +// this.Path = path; +// this.Value = value; +// this.Timeout = timeout; +// this.Timestamp = DateTimeOffset.UtcNow; +// } + +// internal Dictionary GetRawHeaders() => headers; +// internal IAsyncDecorator GetNextDecorator() => decorators[++decoratorIndex]; + +// public void Reset(IAsyncDecorator currentFilter) +// { +// decoratorIndex = Array.IndexOf(decorators, currentFilter); +// if (headers != null) +// { +// headers.Clear(); +// } +// Timestamp = DateTimeOffset.UtcNow; +// } +// } + +// public class ResponseContext +// { +// bool hasValue; +// object value; +// readonly byte[] bytes; + +// public long StatusCode { get; } +// public Dictionary ResponseHeaders { get; } + +// public ResponseContext(object value, Dictionary header = null) +// { +// this.hasValue = true; +// this.value = value; +// this.StatusCode = 200; +// this.ResponseHeaders = (header ?? new Dictionary()); +// } + +// public ResponseContext(byte[] bytes, long statusCode, Dictionary responseHeaders) +// { +// this.hasValue = false; +// this.bytes = bytes; +// this.StatusCode = statusCode; +// this.ResponseHeaders = responseHeaders; +// } + +// public byte[] GetRawData() => bytes; + +// public T GetResponseAs() +// { +// if (hasValue) +// { +// return (T)value; +// } + +// value = JsonUtility.FromJson(Encoding.UTF8.GetString(bytes)); +// hasValue = true; +// return (T)value; +// } +// } + +// public interface IAsyncDecorator +// { +// UniTask SendAsync(RequestContext context, CancellationToken cancellationToken, Func> next); +// } + + +// public class NetworkClient : IAsyncDecorator +// { +// readonly Func> next; +// readonly IAsyncDecorator[] decorators; +// readonly TimeSpan timeout; +// readonly IProgress progress; +// readonly string basePath; + +// public NetworkClient(string basePath, TimeSpan timeout, params IAsyncDecorator[] decorators) +// : this(basePath, timeout, null, decorators) +// { +// } + +// public NetworkClient(string basePath, TimeSpan timeout, IProgress progress, params IAsyncDecorator[] decorators) +// { +// this.next = InvokeRecursive; // setup delegate + +// this.basePath = basePath; +// this.timeout = timeout; +// this.progress = progress; +// this.decorators = new IAsyncDecorator[decorators.Length + 1]; +// Array.Copy(decorators, this.decorators, decorators.Length); +// this.decorators[this.decorators.Length - 1] = this; +// } + +// public async UniTask PostAsync(string path, T value, CancellationToken cancellationToken = default) +// { +// var request = new RequestContext(basePath, path, value, timeout, decorators); +// var response = await InvokeRecursive(request, cancellationToken); +// return response.GetResponseAs(); +// } + + +// UniTask InvokeRecursive(RequestContext context, CancellationToken cancellationToken) +// { +// return context.GetNextDecorator().SendAsync(context, cancellationToken, next); // マジカル再帰処理 +// } + +// async UniTask IAsyncDecorator.SendAsync(RequestContext context, CancellationToken cancellationToken, Func> _) +// { +// // Postしか興味ないからPostにしかしないよ! +// // パフォーマンスを最大限にしたい場合はuploadHandler, downloadHandlerをカスタマイズすること + +// // JSONでbodyに送るというパラメータで送るという雑設定。 +// var data = JsonUtility.ToJson(context.Value); +// var formData = new Dictionary { { "body", data } }; + +// using (var req = UnityWebRequest.Post(basePath + context.Path, formData)) +// { +// var header = context.GetRawHeaders(); +// if (header != null) +// { +// foreach (var item in header) +// { +// req.SetRequestHeader(item.Key, item.Value); +// } +// } + +// // Timeout処理はCancellationTokenSourceのCancelAfterSlim(UniTask拡張)を使ってサクッと処理 +// var linkToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); +// linkToken.CancelAfterSlim(timeout); +// try +// { +// // 完了待ちや終了処理はUniTaskの拡張自体に丸投げ +// await req.SendWebRequest().ToUniTask(progress: progress, cancellationToken: linkToken.Token); +// } +// catch (OperationCanceledException) +// { +// // 元キャンセレーションソースがキャンセルしてなければTimeoutによるものと判定 +// if (!cancellationToken.IsCancellationRequested) +// { +// throw new TimeoutException(); +// } +// } +// finally +// { +// // Timeoutに引っかからなかった場合にてるのでCancelAfterSlimの裏で回ってるループをこれで終わらせとく +// if (!linkToken.IsCancellationRequested) +// { +// linkToken.Cancel(); +// } +// } + +// // UnityWebRequestを先にDisposeしちゃうので先に必要なものを取得しておく(性能的には無駄なのでパフォーマンスを最大限にしたい場合は更に一工夫を) +// return new ResponseContext(req.downloadHandler.data, req.responseCode, req.GetResponseHeaders()); +// } +// } +// } +//} \ No newline at end of file diff --git a/src/UniTask/Assets/Scenes/SandboxMain.cs b/src/UniTask/Assets/Scenes/SandboxMain.cs index 3077e05..516f7f9 100644 --- a/src/UniTask/Assets/Scenes/SandboxMain.cs +++ b/src/UniTask/Assets/Scenes/SandboxMain.cs @@ -18,7 +18,6 @@ using UnityEngine.SceneManagement; using UnityEngine.Rendering; using System.IO; using System.Linq.Expressions; -using Cysharp.Threading.Tasks.Sample; // using DG.Tweening; @@ -269,32 +268,33 @@ public class SandboxMain : MonoBehaviour async Task Test1() { - var r = await TcsAsync("https://bing.com/"); + // var r = await TcsAsync("https://bing.com/"); + await Task.Yield(); Debug.Log("TASKASYNC"); } - async UniTaskVoid Test2() - { - try - { - //var cts = new CancellationTokenSource(); - //var r = UniAsync("https://bing.com/", cts.Token); - //cts.Cancel(); - //await r; - Debug.Log("SendWebRequestDone:" + PlayerLoopInfo.CurrentLoopType); + //async UniTaskVoid Test2() + //{ + // try + // { + // //var cts = new CancellationTokenSource(); + // //var r = UniAsync("https://bing.com/", cts.Token); + // //cts.Cancel(); + // //await r; + // Debug.Log("SendWebRequestDone:" + PlayerLoopInfo.CurrentLoopType); - // var foo = await UnityWebRequest.Get("https://bing.com/").SendWebRequest(); - // foo.downloadHandler.text; - // - _ = await UnityWebRequest.Get("https://bing.com/").SendWebRequest().WithCancellation(CancellationToken.None); - Debug.Log("SendWebRequestWithCancellationDone:" + PlayerLoopInfo.CurrentLoopType); - } - catch - { - Debug.Log("Canceled"); - } - } + // // var foo = await UnityWebRequest.Get("https://bing.com/").SendWebRequest(); + // // foo.downloadHandler.text; + // // + // _ = await UnityWebRequest.Get("https://bing.com/").SendWebRequest().WithCancellation(CancellationToken.None); + // Debug.Log("SendWebRequestWithCancellationDone:" + PlayerLoopInfo.CurrentLoopType); + // } + // catch + // { + // Debug.Log("Canceled"); + // } + //} IEnumerator Test3(string url) { @@ -303,17 +303,17 @@ public class SandboxMain : MonoBehaviour Debug.Log("COROUTINE"); } - static async Task TcsAsync(string url) - { - var req = await UnityWebRequest.Get(url).SendWebRequest(); - return req; - } + //static async Task TcsAsync(string url) + //{ + // var req = await UnityWebRequest.Get(url).SendWebRequest(); + // return req; + //} - static async UniTask UniAsync(string url, CancellationToken cancellationToken) - { - var req = await UnityWebRequest.Get(url).SendWebRequest().WithCancellation(cancellationToken); - return req; - } + //static async UniTask UniAsync(string url, CancellationToken cancellationToken) + //{ + // var req = await UnityWebRequest.Get(url).SendWebRequest().WithCancellation(cancellationToken); + // return req; + //} async Task Test() { diff --git a/src/UniTask/Assets/TempAsm/FooMonoBehaviour.cs b/src/UniTask/Assets/TempAsm/FooMonoBehaviour.cs index c57b11e..6c62ccb 100644 --- a/src/UniTask/Assets/TempAsm/FooMonoBehaviour.cs +++ b/src/UniTask/Assets/TempAsm/FooMonoBehaviour.cs @@ -14,14 +14,14 @@ public class FooMonoBehaviour : MonoBehaviour private async UniTask Download(UnityWebRequest req, string filePath) { - var foo = req.SendWebRequest(); + _ = req.SendWebRequest(); - - var aaa = await foo; - Debug.Log(aaa); + // var aaa = await foo; + // Debug.Log(aaa); + await UniTask.Yield(); //File.WriteAllText(filePath, req.downloadHandler.text ?? string.Empty); } } diff --git a/src/UniTask/ProjectSettings/ProjectVersion.txt b/src/UniTask/ProjectSettings/ProjectVersion.txt index a328ffd..0560e11 100644 --- a/src/UniTask/ProjectSettings/ProjectVersion.txt +++ b/src/UniTask/ProjectSettings/ProjectVersion.txt @@ -1,2 +1,2 @@ -m_EditorVersion: 2020.2.1f1 -m_EditorVersionWithRevision: 2020.2.1f1 (270dd8c3da1c) +m_EditorVersion: 2020.2.0f1 +m_EditorVersionWithRevision: 2020.2.0f1 (3721df5a8b28)