using UnityEditor;
|
|
using UnityEngine.Networking;
|
|
using System.Text.RegularExpressions;
|
|
#if UNITY_EDITOR
|
|
using System;
|
|
using UnityEngine;
|
|
using System.Collections.Generic;
|
|
|
|
namespace Bolt.Utils
|
|
{
|
|
/// <summary>
|
|
/// Creates a instance of the Account Service to register Photon Cloud accounts.
|
|
/// </summary>
|
|
public class AccountService
|
|
{
|
|
private const string ServiceUrl = "https://partner.photonengine.com/api/Unity/User/RegisterEx";
|
|
|
|
private readonly Dictionary<string, string> requestHeaders = new Dictionary<string, string>
|
|
{
|
|
{"Content-Type", "application/json"},
|
|
{"x-functions-key", "VQ920wVUieLHT9c3v1ZCbytaLXpXbktUztKb3iYLCdiRKjUagcl6eg=="}
|
|
};
|
|
|
|
/// <summary>
|
|
/// Attempts to create a Photon Cloud Account asynchronously.
|
|
/// Once your callback is called, check ReturnCode, Message and AppId to get the result of this attempt.
|
|
/// </summary>
|
|
/// <param name="email">Email of the account.</param>
|
|
/// <param name="serviceTypes">Defines which type of Photon-service is being requested.</param>
|
|
/// <param name="callback">Called when the result is available.</param>
|
|
public bool RegisterByEmail(string email, string serviceTypes, Action<AccountServiceResponse> callback = null,
|
|
Action<string> errorCallback = null)
|
|
{
|
|
if (IsValidEmail(email) == false)
|
|
{
|
|
Debug.LogErrorFormat("Email \"{0}\" is not valid", email);
|
|
return false;
|
|
}
|
|
|
|
if (string.IsNullOrEmpty(serviceTypes))
|
|
{
|
|
Debug.LogError("serviceTypes string is null or empty");
|
|
return false;
|
|
}
|
|
|
|
AccountServiceRequest req = new AccountServiceRequest();
|
|
req.Email = email;
|
|
req.ServiceTypes = serviceTypes;
|
|
return this.RegisterByEmail(req, callback, errorCallback);
|
|
}
|
|
|
|
public bool RegisterByEmail(string email, List<ServiceTypes> serviceTypes,
|
|
Action<AccountServiceResponse> callback = null, Action<string> errorCallback = null)
|
|
{
|
|
if (serviceTypes == null || serviceTypes.Count == 0)
|
|
{
|
|
Debug.LogError("serviceTypes list is null or empty");
|
|
return false;
|
|
}
|
|
|
|
return this.RegisterByEmail(email, GetServiceTypesFromList(serviceTypes), callback, errorCallback);
|
|
}
|
|
|
|
public bool RegisterByEmail(AccountServiceRequest request, Action<AccountServiceResponse> callback = null,
|
|
Action<string> errorCallback = null)
|
|
{
|
|
if (request == null)
|
|
{
|
|
Debug.LogError("Registration request is null");
|
|
return false;
|
|
}
|
|
|
|
StartCoroutine(
|
|
HttpPost(GetUrlWithQueryStringEscaped(request),
|
|
requestHeaders,
|
|
null,
|
|
s =>
|
|
{
|
|
if (string.IsNullOrEmpty(s))
|
|
{
|
|
if (errorCallback != null)
|
|
{
|
|
errorCallback(
|
|
"Server's response was empty. Please register through account website during this service interruption.");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
AccountServiceResponse ase = this.ParseResult(s);
|
|
if (ase == null)
|
|
{
|
|
if (errorCallback != null)
|
|
{
|
|
errorCallback(
|
|
"Error parsing registration response. Please try registering from account website");
|
|
}
|
|
}
|
|
else if (callback != null)
|
|
{
|
|
callback(ase);
|
|
}
|
|
}
|
|
},
|
|
e =>
|
|
{
|
|
if (errorCallback != null)
|
|
{
|
|
errorCallback(e);
|
|
}
|
|
})
|
|
);
|
|
return true;
|
|
}
|
|
|
|
private static string GetUrlWithQueryStringEscaped(AccountServiceRequest request)
|
|
{
|
|
string email = UnityEngine.Networking.UnityWebRequest.EscapeURL(request.Email);
|
|
string st = UnityEngine.Networking.UnityWebRequest.EscapeURL(request.ServiceTypes);
|
|
return string.Format("{0}?email={1}&st={2}", ServiceUrl, email, st);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reads the Json response and applies it to local properties.
|
|
/// </summary>
|
|
/// <param name="result"></param>
|
|
private AccountServiceResponse ParseResult(string result)
|
|
{
|
|
try
|
|
{
|
|
AccountServiceResponse res = JsonUtility.FromJson<AccountServiceResponse>(result);
|
|
// Unity's JsonUtility does not support deserializing Dictionary, we manually parse it, dirty & ugly af, better then using a 3rd party lib
|
|
if (res.ReturnCode == AccountServiceReturnCodes.Success)
|
|
{
|
|
string[] parts = result.Split(new[] {"\"ApplicationIds\":{"},
|
|
StringSplitOptions.RemoveEmptyEntries);
|
|
parts = parts[1].Split('}');
|
|
string applicationIds = parts[0];
|
|
if (!string.IsNullOrEmpty(applicationIds))
|
|
{
|
|
parts = applicationIds.Split(new[] {',', '"', ':'}, StringSplitOptions.RemoveEmptyEntries);
|
|
res.ApplicationIds = new Dictionary<string, string>(parts.Length / 2);
|
|
for (int i = 0; i < parts.Length; i = i + 2)
|
|
{
|
|
res.ApplicationIds.Add(parts[i], parts[i + 1]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Debug.LogError(
|
|
"The server did not return any AppId, ApplicationIds was empty in the response.");
|
|
return null;
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
catch (Exception ex) // probably JSON parsing exception, check if returned string is valid JSON
|
|
{
|
|
Debug.LogException(ex);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private static string GetServiceTypesFromList(List<ServiceTypes> appTypes)
|
|
{
|
|
if (appTypes != null)
|
|
{
|
|
string serviceTypes = string.Empty;
|
|
if (appTypes.Count > 0)
|
|
{
|
|
serviceTypes = ((int) appTypes[0]).ToString();
|
|
for (int i = 1; i < appTypes.Count; i++)
|
|
{
|
|
int appType = (int) appTypes[i];
|
|
serviceTypes = string.Format("{0},{1}", serviceTypes, appType);
|
|
}
|
|
}
|
|
|
|
return serviceTypes;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
// RFC2822 compliant matching 99.9% of all email addresses in actual use today
|
|
// according to http://www.regular-expressions.info/email.html [22.02.2012]
|
|
private static Regex reg = new Regex(
|
|
"^((?>[a-zA-Z\\d!#$%&'*+\\-/=?^_{|}~]+\\x20*|\"((?=[\\x01-\\x7f])[^\"\\]|\\[\\x01-\\x7f])*\"\\x20*)*(?<angle><))?((?!\\.)(?>\\.?[a-zA-Z\\d!#$%&'*+\\-/=?^_{|}~]+)+|\"((?=[\\x01-\\x7f])[^\"\\]|\\[\\x01-\\x7f])*\")@(((?!-)[a-zA-Z\\d\\-]+(?<!-)\\.)+[a-zA-Z]{2,}|\\[(((?(?<!\\[)\\.)(25[0-5]|2[0-4]\\d|[01]?\\d?\\d)){4}|[a-zA-Z\\d\\-]*[a-zA-Z\\d]:((?=[\\x01-\\x7f])[^\\\\[\\]]|\\[\\x01-\\x7f])+)\\])(?(angle)>)$",
|
|
RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);
|
|
|
|
public static bool IsValidEmail(string mailAddress)
|
|
{
|
|
if (string.IsNullOrEmpty(mailAddress))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
var result = reg.Match(mailAddress);
|
|
return result.Success;
|
|
}
|
|
|
|
//https://forum.unity.com/threads/using-unitywebrequest-in-editor-tools.397466/#post-4485181
|
|
private static void StartCoroutine(System.Collections.IEnumerator update)
|
|
{
|
|
EditorApplication.CallbackFunction closureCallback = null;
|
|
|
|
closureCallback = () =>
|
|
{
|
|
try
|
|
{
|
|
if (update.MoveNext() == false)
|
|
{
|
|
EditorApplication.update -= closureCallback;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.LogException(ex);
|
|
EditorApplication.update -= closureCallback;
|
|
}
|
|
};
|
|
|
|
EditorApplication.update += closureCallback;
|
|
}
|
|
|
|
private static System.Collections.IEnumerator HttpPost(string url, Dictionary<string, string> headers,
|
|
byte[] payload, Action<string> successCallback, Action<string> errorCallback)
|
|
{
|
|
using (UnityWebRequest w = new UnityWebRequest(url, "POST"))
|
|
{
|
|
if (payload != null)
|
|
{
|
|
w.uploadHandler = new UploadHandlerRaw(payload);
|
|
}
|
|
|
|
w.downloadHandler = new DownloadHandlerBuffer();
|
|
if (headers != null)
|
|
{
|
|
foreach (var header in headers)
|
|
{
|
|
w.SetRequestHeader(header.Key, header.Value);
|
|
}
|
|
}
|
|
|
|
#if UNITY_2017_2_OR_NEWER
|
|
yield return w.SendWebRequest();
|
|
#else
|
|
yield return w.Send();
|
|
#endif
|
|
|
|
while (w.isDone == false)
|
|
yield return null;
|
|
|
|
#if UNITY_2017_1_OR_NEWER
|
|
if (w.isNetworkError || w.isHttpError)
|
|
#else
|
|
if (w.isError)
|
|
#endif
|
|
{
|
|
if (errorCallback != null)
|
|
{
|
|
errorCallback(w.error);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (successCallback != null)
|
|
{
|
|
successCallback(w.downloadHandler.text);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
[Serializable]
|
|
public class AccountServiceResponse
|
|
{
|
|
public int ReturnCode;
|
|
public string Message;
|
|
|
|
public Dictionary<string, string>
|
|
ApplicationIds; // Unity's JsonUtility does not support deserializing Dictionary
|
|
}
|
|
|
|
[Serializable]
|
|
public class AccountServiceRequest
|
|
{
|
|
public string Email;
|
|
public string ServiceTypes;
|
|
}
|
|
|
|
public class AccountServiceReturnCodes
|
|
{
|
|
public static int Success = 0;
|
|
public static int EmailAlreadyRegistered = 8;
|
|
public static int InvalidParameters = 12;
|
|
|
|
public static readonly Dictionary<int, string> ReturnCodes = new Dictionary<int, string>()
|
|
{
|
|
{Success, "Success"},
|
|
{EmailAlreadyRegistered, "Email Already Registered"},
|
|
{InvalidParameters, "Invalid Parameters"}
|
|
};
|
|
}
|
|
|
|
public enum ServiceTypes
|
|
{
|
|
Realtime = 0,
|
|
Turnbased = 1,
|
|
Chat = 2,
|
|
Voice = 3,
|
|
TrueSync = 4,
|
|
Pun = 5,
|
|
Thunder = 6,
|
|
Bolt = 20
|
|
}
|
|
}
|
|
|
|
#endif
|