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
+ {
77
+ yield return rqt . SendWebRequest ( ) ;
78
+
79
+ switch ( rqt . result )
80
+ {
81
+ case UnityWebRequest . Result . ConnectionError :
82
+ Return ( Transmission . ErrorConnection , data , callback ) ;
83
+ break ;
84
+ case UnityWebRequest . Result . ProtocolError :
85
+ Return ( Transmission . ErrorProtocol , data , callback ) ;
86
+ break ;
87
+ case UnityWebRequest . Result . DataProcessingError :
88
+ Return ( Transmission . ErrorDecode , data , callback ) ;
89
+ break ;
90
+ case UnityWebRequest . Result . Success :
91
+ data . Add ( new FileData ( )
92
+ {
93
+ URL = url ,
94
+ Data = rqt . downloadHandler . data
95
+ } ) ;
96
+ break ;
97
+ }
98
+ }
99
+ }
100
+ Return ( Transmission . Success , data , callback ) ;
101
+ }
102
+
103
+ private static void Return ( Transmission result , HighSpeedArray < FileData > data , Action < Transmission , HighSpeedArray < FileData > > callback )
104
+ {
105
+ if ( _eventService != null )
106
+ {
107
+ _eventService . QueueAction ( ( ) => callback . Invoke ( result , data ) ) ;
108
+ }
109
+ else
110
+ {
111
+ callback ? . Invoke ( result , data ) ;
112
+ }
113
+ }
114
+ }
115
+
116
+ /// <summary>
117
+ /// Implements a UnityRequest for google protobuf web functions.
118
+ /// </summary>
119
+ /// <typeparam name="TRqt">Request</typeparam>
120
+ /// <typeparam name="TResp">Response</typeparam>
121
+ public static class AsyncNetworkEngine < TRqt , TResp >
122
+ where TRqt : IMessage < TRqt > , new ( )
123
+ where TResp : IMessage < TResp > , new ( )
124
+ {
125
+ private static readonly MessageParser < TResp > _tuParser = new MessageParser < TResp > ( ( ) => new TResp ( ) ) ;
126
+ private static readonly MessageParser < GenericErrorResponse > _tvParser = new MessageParser < GenericErrorResponse > ( ( ) => new GenericErrorResponse ( ) ) ;
127
+ private static EventService _eventService ;
128
+
129
+ public static void Send ( string url , TRqt request , Action < Transmission , TResp , GenericErrorResponse > callback )
130
+ {
131
+ if ( _eventService == null ) _eventService = ServiceProvider . GetService < EventService > ( ) ;
132
+ _eventService . StartCoroutine ( SendRequest ( url , request , callback ) ) ;
133
+ }
134
+
135
+ public static IEnumerator SendRequest ( string url , TRqt request , Action < Transmission , TResp , GenericErrorResponse > callback )
136
+ {
137
+ //Notice: APIGateway automatically converts binary data into base64 strings
138
+ using ( var rqt = new UnityWebRequest ( url , "POST" )
139
+ {
140
+ uploadHandler = new UploadHandlerRaw ( request . ToByteArray ( ) ) ,
141
+ downloadHandler = new DownloadHandlerBuffer ( )
142
+ } )
143
+ {
144
+ yield return rqt . SendWebRequest ( ) ;
145
+
146
+ switch ( rqt . result )
147
+ {
148
+ case UnityWebRequest . Result . ConnectionError :
149
+ Return ( Transmission . ErrorConnection , callback ) ;
150
+ break ;
151
+ case UnityWebRequest . Result . ProtocolError :
152
+ HandleError ( GetCloudProvider ( ref url ) , rqt , callback ) ;
153
+ break ;
154
+ case UnityWebRequest . Result . Success :
155
+ while ( ! rqt . downloadHandler . isDone ) yield return null ;
156
+ HandleSuccess ( GetCloudProvider ( ref url ) , rqt , callback ) ;
157
+ break ;
158
+ }
159
+ }
160
+ }
161
+
162
+ private static CloudProvider GetCloudProvider ( ref string url )
163
+ {
164
+ if ( ! AsyncNetworkEngineMap . IsSingleCloud )
165
+ {
166
+ foreach ( var pair in AsyncNetworkEngineMap . MapCloudProvider )
167
+ {
168
+ if ( ! url . StartsWith ( pair . Key ) ) continue ;
169
+ return pair . Value ;
170
+ }
171
+ }
172
+ return AsyncNetworkEngineMap . SingleCloudProvider ;
173
+ }
174
+
175
+ private static void HandleSuccess ( CloudProvider provider , UnityWebRequest rqt , Action < Transmission , TResp , GenericErrorResponse > callback )
176
+ {
177
+ if ( rqt . downloadHandler . data == null )
178
+ {
179
+ Return ( Transmission . ErrorNoData , callback ) ;
180
+ return ;
181
+ }
182
+
183
+ var data = rqt . downloadHandler . data ;
184
+ if ( provider == CloudProvider . Aws )
185
+ {
186
+ var s = Encoding . ASCII . GetString ( rqt . downloadHandler . data ) ;
187
+ if ( ! Base64StdEncoding . Decode ( s , out data ) )
188
+ {
189
+ Return ( Transmission . ErrorParser , default , new GenericErrorResponse ( ) { Error = "base64 string is invalid:" + s } , callback ) ;
190
+ return ;
191
+ }
192
+ }
193
+
194
+ TResp packet ;
195
+ try
196
+ {
197
+ packet = _tuParser . ParseFrom ( data ) ;
198
+ }
199
+ catch
200
+ {
201
+ Return ( Transmission . ErrorParser , callback ) ;
202
+ return ;
203
+ }
204
+ Return ( Transmission . Success , packet , default , callback ) ;
205
+ }
206
+
207
+ private static void HandleError ( CloudProvider provider , UnityWebRequest rqt , Action < Transmission , TResp , GenericErrorResponse > callback )
208
+ {
209
+ if ( rqt . downloadHandler . data == null )
210
+ {
211
+ Return ( Transmission . ErrorProtocol , callback ) ;
212
+ return ;
213
+ }
214
+
215
+ var data = rqt . downloadHandler . data ;
216
+ if ( provider == CloudProvider . Aws )
217
+ {
218
+ var s = Encoding . ASCII . GetString ( rqt . downloadHandler . data ) ;
219
+ if ( ! Base64StdEncoding . Decode ( s , out data ) )
220
+ {
221
+ Return ( Transmission . ErrorParser , default , new GenericErrorResponse ( ) { Error = "base64 string is invalid:" + s } , callback ) ;
222
+ return ;
223
+ }
224
+ }
225
+
226
+ var transmission = ( Transmission ) rqt . responseCode ;
227
+ GenericErrorResponse packet ;
228
+ try
229
+ {
230
+ packet = _tvParser . ParseFrom ( data ) ;
231
+ }
232
+ catch
233
+ {
234
+ Return ( Transmission . ErrorParser , callback ) ;
235
+ return ;
236
+ }
237
+ Return ( transmission , default , packet , callback ) ;
238
+ }
239
+
240
+ private static void Return ( Transmission result , Action < Transmission , TResp , GenericErrorResponse > callback )
241
+ {
242
+ Return ( result , default , default , callback ) ;
243
+ }
244
+
245
+ private static void Return ( Transmission result , TResp data , GenericErrorResponse error , Action < Transmission , TResp , GenericErrorResponse > callback )
246
+ {
247
+ if ( callback == null ) return ;
248
+ if ( _eventService != null )
249
+ {
250
+ _eventService . QueueAction ( ( ) => callback . Invoke ( result , data , error ) ) ;
251
+ }
252
+ else
253
+ {
254
+ callback . Invoke ( result , data , error ) ;
255
+ }
256
+ }
257
+ }
258
+ }
0 commit comments