Skip to content

Commit e94df8a

Browse files
author
Hanza Ru
committed
+version 0.2.1
+Base64StdEncoding now don't throw direct errors. Instead returnTransmission.ErrorParser with error msg.
0 parents  commit e94df8a

17 files changed

+1120
-0
lines changed

.icon.png

6.3 KB
Loading

LICENSE.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
MIT License
2+
3+
Copyright (c) 2015, Unity Technologies
4+
5+
Copyright (c) 2020 Game Workstore
6+
7+
Permission is hereby granted, free of charge, to any person obtaining a copy
8+
of this software and associated documentation files (the "Software"), to deal
9+
in the Software without restriction, including without limitation the rights
10+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
copies of the Software, and to permit persons to whom the Software is
12+
furnished to do so, subject to the following conditions:
13+
14+
The above copyright notice and this permission notice shall be included in all
15+
copies or substantial portions of the Software.
16+
17+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23+
SOFTWARE.

LICENSE.md.meta

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# Async Network Engine
2+
3+
Unity http requests made easy to interoperability with Go Lang + Google Protobuf functions!
4+
5+
Supported Cloud Functions:
6+
- Google Cloud Functions
7+
- Amazon Web Services Lambdas
8+
9+
Use at your own risk!
10+
11+
# How to install
12+
13+
At package.json, add these 3 lines of code:
14+
```json
15+
"com.gameworkstore.asyncnetworkengine": "git://github.com/GameWorkstore/async-network-engine.git",
16+
"com.gameworkstore.googleprotobufunity": "git://github.com/GameWorkstore/google-protobuf-unity.git",
17+
"com.gameworkstore.patterns": "git://github.com/GameWorkstore/patterns.git"
18+
```
19+
20+
And wait for unity to download and compile the package.
21+
22+
for update package for a newer version, install UpmGitExtension and update on [ Window > Package Manager ]!
23+
> https://github.com/mob-sakai/UpmGitExtension
24+
25+
# Usage Examples
26+
27+
You can find usage examples on Assets/Tests/ folder, for each cloud.
28+
29+
## Uploading to Google Cloud Functions
30+
31+
on upmsync, the job 'upload_gcp' illustrates a possible way to upload your functions into GCP.
32+
Requires a service account to enable it to upload.
33+
34+
## Uploading to Amazon Web Services
35+
36+
on upmsync.yaml, the job 'upload_aws' illustrates a possible way to upload your functions into AWS.
37+
Requires a service account to enable it to upload.
38+
> You need to set the template 'cloudformation_function.yaml' public in your bucket repository to enable AWS::Stack to read from it.
39+
40+
# Implementation
41+
42+
## GCP Troubleshoot
43+
44+
> My function is returning ErrorProtocol for any input.
45+
if you don't give access public for your function it might fail
46+
47+
## AWS Troubleshoot
48+
> CloudFormation is returning errors
49+
50+
Verify all variables, !Ref and links, you might be forgetting something. CloudFormations is very sensitive to linkage errors.
51+
52+
> My lambda is returning error 500 Internal Server error.
53+
If you are receiving this and error object is returning null, it might be a bad configuration causing your lambda to not run.
54+
Verify if you function is running by adding a fmt.Println("test") at main() function to ensure the function is starting.
55+
Some issues that may prevent the start of function:
56+
- The functions ins't at correct path when extracted from the zip.
57+
- The function package name isn't main where main() function is declared.
58+
- lambda.Start() is never begin called to initialize the function.
59+
- The function is crashing upon initialization
60+
61+
If the function is working normally, them you might receive error 500 - ErrorInternalServer with AWSError, when specified by the programmer.
62+
63+
# Contributions
64+
65+
If you are using this library and want to submit a change, go ahead! Overall, this project accepts contributions if:
66+
- Is a bug fix;
67+
- Or, is a generalization of a well-known issue;
68+
- Or is performance improvement;
69+
- Or is an improvement to already supported feature.
70+
71+
Also, you can donate to allow us to drink coffee while we improve it for you!

README.md.meta

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Runtime.meta

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Runtime/AsyncNetworkEngine.cs

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

Runtime/AsyncNetworkEngine.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)