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