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