/
UnityHTTPClient.cs
140 lines (116 loc) · 4.36 KB
/
UnityHTTPClient.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
using Segment.Analytics.Utilities;
using UnityEngine.Networking;
namespace UnitySample
{
/// <summary>
/// Http client based on UnityWebRequest.
/// NOTE: this implementation shows how you can customize the network logic with your favorite network library.
/// Though it is based on UnityWebRequest, it does not work in WebGL due to the fact that the Analytics library
/// is architected to be a multi-thread library, whereas WebGL does not support multi-threading as of right now.
/// </summary>
public class UnityHTTPClient : HTTPClient
{
public UnityHTTPClient(string apiKey, string apiHost = null, string cdnHost = null) : base(apiKey, apiHost, cdnHost)
{
}
public override async Task<Response> DoGet(string url)
{
using (var request = new NetworkRequest {URL = url, Action = GetRequest})
{
MainThreadDispatcher.Instance.Post(request);
await request.Semaphore.WaitAsync();
return request.Response;
}
}
IEnumerator GetRequest(NetworkRequest networkRequest)
{
using (var request = UnityWebRequest.Get(networkRequest.URL))
{
request.SetRequestHeader("Content-Type", "application/json; charset=utf-8");
yield return request.SendWebRequest();
networkRequest.Response.StatusCode = (int)request.responseCode;
networkRequest.Response.Content = request.downloadHandler.text;
networkRequest.Semaphore.Release();
}
}
public override async Task<Response> DoPost(string url, byte[] data)
{
using (var request = new NetworkRequest {URL = url, Data = data, Action = PostRequest})
{
MainThreadDispatcher.Instance.Post(request);
await request.Semaphore.WaitAsync();
return request.Response;
}
}
IEnumerator PostRequest(NetworkRequest networkRequest)
{
using (var request = UnityWebRequest.Put(networkRequest.URL, networkRequest.Data))
{
request.SetRequestHeader("Content-Type", "text/plain");
yield return request.SendWebRequest();
networkRequest.Response.StatusCode = (int)request.responseCode;
networkRequest.Semaphore.Release();
}
}
}
public class UnityHTTPClientProvider : IHTTPClientProvider
{
/// <summary>
/// Provider that creates a Http client based on UnityWebRequest
/// </summary>
/// <param name="dispatcher">the dispatcher is required to force instantiation of MainThreadDispatcher</param>
public UnityHTTPClientProvider(MainThreadDispatcher dispatcher)
{
}
public HTTPClient CreateHTTPClient(string apiKey, string apiHost = null, string cdnHost = null)
{
return new UnityHTTPClient(apiKey, apiHost, cdnHost);
}
}
public class NetworkRequest : IDisposable
{
public HTTPClient.Response Response { get; set; }
public SemaphoreSlim Semaphore { get; set; }
public string URL { get; set; }
public byte[] Data { get; set; }
public Func<NetworkRequest, IEnumerator> Action { get; set; }
public NetworkRequest()
{
Response = new HTTPClient.Response();
Semaphore = new SemaphoreSlim(0);
}
public IEnumerator Run() => Action(this);
public void Dispose()
{
Semaphore?.Dispose();
}
}
public class MainThreadDispatcher : Singleton<MainThreadDispatcher>
{
private ConcurrentQueue<NetworkRequest> _tasks;
protected override void Awake()
{
base.Awake();
_tasks= new ConcurrentQueue<NetworkRequest>();
}
public void Post(NetworkRequest task)
{
_tasks.Enqueue(task);
}
private void Update()
{
while (!_tasks.IsEmpty)
{
if (_tasks.TryDequeue(out NetworkRequest task))
{
StartCoroutine(task.Run());
}
}
}
}
}