using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text.RegularExpressions;
using System.IO;
using System.Web;
using System.Linq;
using System.Net;
using System.Text;
using UnityEngine.Networking;
using MoralisUnity.Web3Api;
using WebRequest = MoralisUnity.Web3Api.Models.WebRequest;
using Newtonsoft.Json;
using Cysharp.Threading.Tasks;
using MoralisUnity.Web3Api.Core;
using MoralisUnity.Web3Api.Core.Models;
using UnityEngine;
using Object = System.Object;
namespace MoralisUnity.Web3Api.Client
{
///
/// API client is mainly responible for making the HTTP call to the API backend.
///
public class ApiClient
{
private readonly Dictionary _defaultHeaderMap = new Dictionary();
///
/// Initializes a new instance of the class.
///
/// The base path.
public ApiClient(String basePath="http://localhost:3063/api/v2")
{
BasePath = basePath;
RestClient = new UniversalWebClient();
_defaultHeaderMap.Add("x-moralis-platform", "UNITY SDK");
_defaultHeaderMap.Add("x-moralis-platform-version", "v1.2.10");
}
///
/// Gets or sets the base path.
///
/// The base path
public string BasePath { get; set; }
///
/// Gets or sets the RestClient.
///
/// An instance of the RestClient
//public RestClient RestClient { get; set; }
public UniversalWebClient RestClient { get; set; }
///
/// Gets the default header.
///
public Dictionary DefaultHeader
{
get { return _defaultHeaderMap; }
}
///
/// Makes the HTTP request (Sync).
///
/// URL path.
/// HTTP method.
/// Query parameters.
/// HTTP body (POST request).
/// Header parameters.
/// Form parameters.
/// File parameters.
/// Authentication settings.
/// Object
public async UniTask, string>> CallApi(String path, Method method, Dictionary queryParams, String postBody,
Dictionary headerParams, Dictionary formParams,
Dictionary fileParams, String[] authSettings)
{
bool paramsAdded = false;
//var request = new RestRequest(path, method);
Models.WebRequest request = new Models.WebRequest();
request.Resource = BasePath;
request.Path = path;
request.Method = method.ToString().ToUpper();
UpdateParamsForAuth(queryParams, headerParams, authSettings);
if (!String.IsNullOrWhiteSpace(postBody))
{
request.Data = new MemoryStream(Encoding.UTF8.GetBytes(postBody));
}
if (_defaultHeaderMap.Count > 0)
{
if (request.Headers == null)
{
request.Headers = new List>();
}
// add default header, if any
foreach (var defaultHeader in _defaultHeaderMap)
{
request.Headers.Add(new KeyValuePair(defaultHeader.Key, defaultHeader.Value));
}
}
if (headerParams.Count > 0)
{
if (request.Headers == null)
{
request.Headers = new List>();
}
// add header parameter, if any
foreach (var param in headerParams)
{
if (!String.IsNullOrEmpty(param.Key) && !String.IsNullOrEmpty(param.Value))
{
request.Headers.Add(new KeyValuePair(param.Key, param.Value));
}
}
}
if (queryParams.Count > 0)
{
// add query parameter, if any
foreach (var param in queryParams)
{
if (paramsAdded == false)
{
paramsAdded = true;
request.Method = $"{request.Method}?{param.Key}={UnityWebRequest.EscapeURL(param.Value)}";
}
else
{
request.Method = $"{request.Method}&{param.Key}={UnityWebRequest.EscapeURL(param.Value)}";
}
}
}
// add form parameter, if any
if (formParams != null && formParams.Count > 0)
{
string data = JsonConvert.SerializeObject(formParams);
request.Data = new MemoryStream(Encoding.UTF8.GetBytes(data));
}
// add file parameter, if any
if (fileParams != null && fileParams.Count > 0)
{
string data = JsonConvert.SerializeObject(fileParams);
request.Data = new MemoryStream(Encoding.UTF8.GetBytes(data));
}
//request.AddFile(param.Value.Name, param.Value.Writer, param.Value.FileName, param.Value.ContentType);
return await RestClient.ExecuteAsync(request);
}
///
/// Add default header.
///
/// Header field name.
/// Header field value.
///
public void AddDefaultHeader(string key, string value)
{
_defaultHeaderMap.Add(key, value);
}
///
/// Escape string (url-encoded).
///
/// String to be escaped.
/// Escaped string.
public string EscapeString(string str)
{
#if UNITY_2017_1_OR_NEWER
return UnityEngine.Networking.UnityWebRequest.EscapeURL(str);
#else
return HttpUtility.UrlEncode(str);
#endif
}
///
/// Create FileParameter based on Stream.
///
/// Parameter name.
/// Input stream.
/// FileParameter.
public FileParameter ParameterToFile(string name, Stream stream)
{
byte[] buffer = new byte[stream.Length];
stream.Read(buffer, 0, buffer.Length);
stream.Position = 0;
if (stream is FileStream)
return FileParameter.Create(name, buffer, Path.GetFileName(((FileStream)stream).Name));
else
return FileParameter.Create(name, buffer, "no_file_name_provided");
}
///
/// If parameter is DateTime, output in a formatted string (default ISO 8601), customizable with Configuration.DateTime.
/// If parameter is a list of string, join the list with ",".
/// Otherwise just return the string.
///
/// The parameter (header, path, query, form).
/// Formatted string.
public string ParameterToString(object obj)
{
if (obj is DateTime)
// Return a formatted date string - Can be customized with Configuration.DateTimeFormat
// Defaults to an ISO 8601, using the known as a Round-trip date/time pattern ("o")
// https://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.110).aspx#Anchor_8
// For example: 2009-06-15T13:45:30.0000000
return ((DateTime)obj).ToString(Configuration.DateTimeFormat);
else if (obj is List)
return String.Join(",", (obj as List).ToArray());
else if (obj is string || obj is int || obj is long || obj is decimal || obj is bool || obj is float || obj is double || obj is byte || obj is char)
{
return obj.ToString();
}
else
return JsonConvert.SerializeObject(obj);
}
///
/// Convert a number to a HEX string.
///
/// Value to convert
/// Hex string.
public string ParameterToHex(long val)
{
string resp = $"0x{val.ToString("X")}";
return resp;
}
///
/// Deserialize the JSON string into a proper object.
///
/// HTTP body (e.g. string, JSON).
/// Object type.
/// HTTP headers.
/// Object representation of the JSON string.
public object Deserialize(string content, Type type, Dictionary headers=null)
{
if (type == typeof(Object)) // return an object
{
return content;
}
if (type == typeof(Stream))
{
var filePath = String.IsNullOrEmpty(Configuration.TempFolderPath)
? Path.GetTempPath()
: Configuration.TempFolderPath;
var fileName = filePath + Guid.NewGuid();
if (headers != null)
{
//var regex = new Regex(@"Content-Disposition:.*filename=['""]?([^'""\s]+)['""]?$");
//var match = regex.Match(headers.ToString());
//if (match.Success)
if (headers.ContainsKey("Content-Disposition"))
{
string cntDisp = headers["Content-Disposition"];
fileName = filePath + cntDisp.Replace("\"", "").Replace("'", "");
}
}
File.WriteAllText(fileName, content);
return new FileStream(fileName, FileMode.Open);
}
if (type.Name.StartsWith("System.Nullable`1[[System.DateTime")) // return a datetime object
{
return DateTime.Parse(content, null, System.Globalization.DateTimeStyles.RoundtripKind);
}
if (type == typeof(String) || type.Name.StartsWith("System.Nullable")) // return primitive type
{
return ConvertType(content, type);
}
// at this point, it must be a model (json)
try
{
return JsonConvert.DeserializeObject(content, type);
}
catch (IOException e)
{
throw new ApiException(500, e.Message);
}
}
///
/// Serialize an object into JSON string.
///
/// Object.
/// JSON string.
public string Serialize(object obj)
{
try
{
return obj != null ? JsonConvert.SerializeObject(obj) : null;
}
catch (Exception e)
{
throw new ApiException(500, e.Message);
}
}
///
/// Get the API key with prefix.
///
/// API key identifier (authentication scheme).
/// API key with prefix.
public string GetApiKeyWithPrefix (string apiKeyIdentifier)
{
var apiKeyValue = "";
Configuration.ApiKey.TryGetValue (apiKeyIdentifier, out apiKeyValue);
var apiKeyPrefix = "";
if (Configuration.ApiKeyPrefix.TryGetValue (apiKeyIdentifier, out apiKeyPrefix))
return apiKeyPrefix + " " + apiKeyValue;
else
return apiKeyValue;
}
///
/// Update parameters based on authentication.
///
/// Query parameters.
/// Header parameters.
/// Authentication settings.
public void UpdateParamsForAuth(Dictionary queryParams, Dictionary headerParams, string[] authSettings)
{
if (authSettings == null || authSettings.Length == 0)
return;
foreach (string auth in authSettings)
{
// determine which one to use
switch(auth)
{
case "ApiKeyAuth":
headerParams["X-API-Key"] = GetApiKeyWithPrefix("X-API-Key");
break;
default:
//TODO show warning about security definition not found
break;
}
}
}
///
/// Encode string in base64 format.
///
/// String to be encoded.
/// Encoded string.
public static string Base64Encode(string text)
{
var textByte = System.Text.Encoding.UTF8.GetBytes(text);
return System.Convert.ToBase64String(textByte);
}
///
/// Dynamically cast the object into target type.
///
/// Object to be casted
/// Target type
/// Casted object
public static Object ConvertType(Object fromObject, Type toObject) {
return Convert.ChangeType(fromObject, toObject);
}
}
}