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