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