1
+ using Google . Protobuf ;
2
+ using GameWorkstore . Patterns ;
3
+ using System ;
4
+ using System . Collections ;
5
+ using System . Text ;
6
+ using UnityEngine . Networking ;
7
+ using System . Collections . Generic ;
8
+ using System . Linq ;
9
+ // ReSharper disable StaticMemberInGenericType
10
+
11
+ namespace GameWorkstore . AsyncNetworkEngine
12
+ {
13
+ public enum CloudProvider
14
+ {
15
+ Gcp = 0 ,
16
+ Aws = 1
17
+ }
18
+
19
+ public class FileData
20
+ {
21
+ public string URL ;
22
+ public byte [ ] Data ;
23
+ }
24
+
25
+ public static class AsyncNetworkEngineMap
26
+ {
27
+ internal static bool IsSingleCloud = true ;
28
+ internal static CloudProvider SingleCloudProvider = CloudProvider . Aws ;
29
+ internal static Dictionary < string , CloudProvider > MapCloudProvider ;
30
+
31
+ /// <summary>
32
+ /// Setup a single cloud provider for all functions.
33
+ /// </summary>
34
+ /// <param name="cloudProvider">Target cloud provider implementation.</param>
35
+ public static void SetupCloud ( CloudProvider cloudProvider )
36
+ {
37
+ IsSingleCloud = true ;
38
+ SingleCloudProvider = cloudProvider ;
39
+ }
40
+
41
+ /// <summary>
42
+ /// Setup a multi cloud provider for all functions.
43
+ /// </summary>
44
+ /// <param name="mapCloudProvider">Maps base url to cloud provider. Use the lowest possible string to differentiate clouds.</param>
45
+ public static void SetupCloudMap ( Dictionary < string , CloudProvider > mapCloudProvider )
46
+ {
47
+ IsSingleCloud = false ;
48
+ MapCloudProvider = mapCloudProvider ;
49
+ }
50
+ }
51
+
52
+ public static class AsyncNetworkEngine
53
+ {
54
+ private static EventService _eventService ;
55
+
56
+ public static void Download ( string url , Action < Transmission , FileData > callback )
57
+ {
58
+ if ( _eventService == null ) _eventService = ServiceProvider . GetService < EventService > ( ) ;
59
+ _eventService . StartCoroutine ( SendRequest ( new [ ] { url } , ( result , files ) => {
60
+ callback ? . Invoke ( result , files . FirstOrDefault ( ) ) ;
61
+ } ) ) ;
62
+ }
63
+
64
+ public static void Download ( string [ ] urls , Action < Transmission , HighSpeedArray < FileData > > callback )
65
+ {
66
+ if ( _eventService == null ) _eventService = ServiceProvider . GetService < EventService > ( ) ;
67
+ _eventService . StartCoroutine ( SendRequest ( urls , callback ) ) ;
68
+ }
69
+
70
+ public static IEnumerator SendRequest ( string [ ] urls , Action < Transmission , HighSpeedArray < FileData > > callback )
71
+ {
72
+ var data = new HighSpeedArray < FileData > ( urls . Length ) ;
73
+ foreach ( var url in urls )
74
+ {
75
+ using var rqt = UnityWebRequest . Get ( url ) ;
76
+ yield return rqt . SendWebRequest ( ) ;
77
+
78
+ switch ( rqt . result )
79
+ {
80
+ case UnityWebRequest . Result . ConnectionError :
81
+ Return ( Transmission . ErrorConnection , null , callback ) ;
82
+ break ;
83
+ case UnityWebRequest . Result . Success :
84
+ data . Add ( new FileData ( )
85
+ {
86
+ URL = url ,
87
+ Data = rqt . downloadHandler . data
88
+ } ) ;
89
+ break ;
90
+ case UnityWebRequest . Result . ProtocolError :
91
+ Return ( Transmission . ErrorProtocol , null , callback ) ;
92
+ break ;
93
+ case UnityWebRequest . Result . DataProcessingError :
94
+ Return ( Transmission . ErrorDecode , null , callback ) ;
95
+ break ;
96
+ }
97
+ }
98
+ Return ( Transmission . Success , data , callback ) ;
99
+ }
100
+
101
+ private static void Return ( Transmission result , HighSpeedArray < FileData > data , Action < Transmission , HighSpeedArray < FileData > > callback )
102
+ {
103
+ if ( _eventService != null )
104
+ {
105
+ _eventService . QueueAction ( ( ) => callback . Invoke ( result , data ) ) ;
106
+ }
107
+ else
108
+ {
109
+ callback ? . Invoke ( result , data ) ;
110
+ }
111
+ }
112
+ }
113
+
114
+ /// <summary>
115
+ /// Implements a UnityRequest for google protobuf web functions.
116
+ /// </summary>
117
+ /// <typeparam name="TRqt">Request</typeparam>
118
+ /// <typeparam name="TResp">Response</typeparam>
119
+ public static class AsyncNetworkEngine < TRqt , TResp >
120
+ where TRqt : IMessage < TRqt > , new ( )
121
+ where TResp : IMessage < TResp > , new ( )
122
+ {
123
+ private static readonly MessageParser < TResp > _tuParser = new MessageParser < TResp > ( ( ) => new TResp ( ) ) ;
124
+ private static readonly MessageParser < GenericErrorResponse > _tvParser = new MessageParser < GenericErrorResponse > ( ( ) => new GenericErrorResponse ( ) ) ;
125
+ private static EventService _eventService ;
126
+
127
+ public static void Send ( string url , TRqt request , Action < Transmission , TResp , GenericErrorResponse > callback )
128
+ {
129
+ if ( _eventService == null ) _eventService = ServiceProvider . GetService < EventService > ( ) ;
130
+ _eventService . StartCoroutine ( SendRequest ( url , request , callback ) ) ;
131
+ }
132
+
133
+ public static IEnumerator SendRequest ( string url , TRqt request , Action < Transmission , TResp , GenericErrorResponse > callback )
134
+ {
135
+ //Notice: APIGateway automatically converts binary data into base64 strings
136
+ using var rqt = new UnityWebRequest ( url , "POST" )
137
+ {
138
+ uploadHandler = new UploadHandlerRaw ( request . ToByteArray ( ) ) ,
139
+ downloadHandler = new DownloadHandlerBuffer ( )
140
+ } ;
141
+ yield return rqt . SendWebRequest ( ) ;
142
+
143
+ switch ( rqt . result )
144
+ {
145
+ case UnityWebRequest . Result . ConnectionError :
146
+ Return ( Transmission . ErrorConnection , callback ) ;
147
+ break ;
148
+ case UnityWebRequest . Result . ProtocolError :
149
+ HandleError ( GetCloudProvider ( ref url ) , rqt , callback ) ;
150
+ break ;
151
+ case UnityWebRequest . Result . Success :
152
+ while ( ! rqt . downloadHandler . isDone ) yield return null ;
153
+ HandleSuccess ( GetCloudProvider ( ref url ) , rqt , callback ) ;
154
+ break ;
155
+ }
156
+ }
157
+
158
+ private static CloudProvider GetCloudProvider ( ref string url )
159
+ {
160
+ if ( ! AsyncNetworkEngineMap . IsSingleCloud )
161
+ {
162
+ foreach ( var pair in AsyncNetworkEngineMap . MapCloudProvider )
163
+ {
164
+ if ( ! url . StartsWith ( pair . Key ) ) continue ;
165
+ return pair . Value ;
166
+ }
167
+ }
168
+ return AsyncNetworkEngineMap . SingleCloudProvider ;
169
+ }
170
+
171
+ private static void HandleSuccess ( CloudProvider provider , UnityWebRequest rqt , Action < Transmission , TResp , GenericErrorResponse > callback )
172
+ {
173
+ if ( rqt . downloadHandler . data == null )
174
+ {
175
+ Return ( Transmission . ErrorNoData , callback ) ;
176
+ return ;
177
+ }
178
+
179
+ var data = rqt . downloadHandler . data ;
180
+ if ( provider == CloudProvider . Aws )
181
+ {
182
+ var s = Encoding . ASCII . GetString ( rqt . downloadHandler . data ) ;
183
+ if ( ! Base64StdEncoding . Decode ( s , out data ) )
184
+ {
185
+ Return ( Transmission . ErrorParser , default , new GenericErrorResponse ( ) { Error = "base64 string is invalid:" + s } , callback ) ;
186
+ return ;
187
+ }
188
+ }
189
+
190
+ TResp packet ;
191
+ try
192
+ {
193
+ packet = _tuParser . ParseFrom ( data ) ;
194
+ }
195
+ catch
196
+ {
197
+ Return ( Transmission . ErrorParser , callback ) ;
198
+ return ;
199
+ }
200
+ Return ( Transmission . Success , packet , default , callback ) ;
201
+ }
202
+
203
+ private static void HandleError ( CloudProvider provider , UnityWebRequest rqt , Action < Transmission , TResp , GenericErrorResponse > callback )
204
+ {
205
+ if ( rqt . downloadHandler . data == null )
206
+ {
207
+ Return ( Transmission . ErrorProtocol , callback ) ;
208
+ return ;
209
+ }
210
+
211
+ var data = rqt . downloadHandler . data ;
212
+ if ( provider == CloudProvider . Aws )
213
+ {
214
+ var s = Encoding . ASCII . GetString ( rqt . downloadHandler . data ) ;
215
+ if ( ! Base64StdEncoding . Decode ( s , out data ) )
216
+ {
217
+ Return ( Transmission . ErrorParser , default , new GenericErrorResponse ( ) { Error = "base64 string is invalid:" + s } , callback ) ;
218
+ return ;
219
+ }
220
+ }
221
+
222
+ var transmission = ( Transmission ) rqt . responseCode ;
223
+ GenericErrorResponse packet ;
224
+ try
225
+ {
226
+ packet = _tvParser . ParseFrom ( data ) ;
227
+ }
228
+ catch
229
+ {
230
+ Return ( Transmission . ErrorParser , callback ) ;
231
+ return ;
232
+ }
233
+ Return ( transmission , default , packet , callback ) ;
234
+ }
235
+
236
+ private static void Return ( Transmission result , Action < Transmission , TResp , GenericErrorResponse > callback )
237
+ {
238
+ Return ( result , default , default , callback ) ;
239
+ }
240
+
241
+ private static void Return ( Transmission result , TResp data , GenericErrorResponse error , Action < Transmission , TResp , GenericErrorResponse > callback )
242
+ {
243
+ if ( callback == null ) return ;
244
+ if ( _eventService != null )
245
+ {
246
+ _eventService . QueueAction ( ( ) => callback . Invoke ( result , data , error ) ) ;
247
+ }
248
+ else
249
+ {
250
+ callback . Invoke ( result , data , error ) ;
251
+ }
252
+ }
253
+ }
254
+ }
0 commit comments