20240422
This commit is contained in:
commit
e0afef912e
1285 files changed
+83219
No files matched your search
@@ -0,0 +1,255 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// <copyright file="FileSource.cs" company="Mapbox">
|
||||
// Copyright (c) 2016 Mapbox. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
using Mapbox.Unity;
|
||||
|
||||
namespace Mapbox.Platform
|
||||
{
|
||||
using Mapbox.Map;
|
||||
using Mapbox.Unity.Utilities;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Security;
|
||||
#if !NETFX_CORE
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
#endif
|
||||
#if !UNITY_5_3_OR_NEWER
|
||||
using System.Threading;
|
||||
#endif
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
#if UNITY_5_3_OR_NEWER
|
||||
using UnityEngine;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Mono implementation of the FileSource class. It will use Mono's
|
||||
/// <see href="http://www.mono-project.com/docs/advanced/runtime/">runtime</see> to
|
||||
/// asynchronously fetch data from the network via HTTP or HTTPS requests.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This implementation requires .NET 4.5 and later. The access token is expected to
|
||||
/// be exported to the environment as MAPBOX_ACCESS_TOKEN.
|
||||
/// </remarks>
|
||||
public sealed class FileSource : IFileSource
|
||||
{
|
||||
|
||||
private Func<string> _getMapsSkuToken;
|
||||
private readonly Dictionary<IAsyncRequest, int> _requests = new Dictionary<IAsyncRequest, int>();
|
||||
private readonly string _accessToken;
|
||||
private readonly object _lock = new object();
|
||||
|
||||
/// <summary>Length of rate-limiting interval in seconds. https://www.mapbox.com/api-documentation/#rate-limit-headers </summary>
|
||||
#pragma warning disable 0414
|
||||
private int? XRateLimitInterval;
|
||||
/// <summary>Maximum number of requests you may make in the current interval before reaching the limit. https://www.mapbox.com/api-documentation/#rate-limit-headers </summary>
|
||||
private long? XRateLimitLimit;
|
||||
/// <summary>Timestamp of when the current interval will end and the ratelimit counter is reset. https://www.mapbox.com/api-documentation/#rate-limit-headers </summary>
|
||||
private DateTime? XRateLimitReset;
|
||||
#pragma warning restore 0414
|
||||
|
||||
|
||||
public FileSource(Func<string> getMapsSkuToken, string acessToken = null)
|
||||
{
|
||||
_getMapsSkuToken = getMapsSkuToken;
|
||||
if (string.IsNullOrEmpty(acessToken))
|
||||
{
|
||||
_accessToken = Environment.GetEnvironmentVariable("MAPBOX_ACCESS_TOKEN");
|
||||
}
|
||||
else
|
||||
{
|
||||
_accessToken = acessToken;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Performs a request asynchronously. </summary>
|
||||
/// <param name="url"> The HTTP/HTTPS url. </param>
|
||||
/// <param name="callback"> Callback to be called after the request is completed. </param>
|
||||
/// <returns>
|
||||
/// Returns a <see cref="IAsyncRequest" /> that can be used for canceling a pending
|
||||
/// request. This handle can be completely ignored if there is no intention of ever
|
||||
/// canceling the request.
|
||||
/// </returns>
|
||||
public IAsyncRequest Request(
|
||||
string url
|
||||
, Action<Response> callback
|
||||
, int timeout = 10
|
||||
, CanonicalTileId tileId = new CanonicalTileId()
|
||||
, string tilesetId = null
|
||||
)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_accessToken))
|
||||
{
|
||||
var uriBuilder = new UriBuilder(url);
|
||||
string accessTokenQuery = "access_token=" + _accessToken;
|
||||
string skuToken = "sku=" + _getMapsSkuToken();
|
||||
if (uriBuilder.Query != null && uriBuilder.Query.Length > 1)
|
||||
{
|
||||
uriBuilder.Query = uriBuilder.Query.Substring(1) + "&" + accessTokenQuery + "&" + skuToken;;
|
||||
}
|
||||
else
|
||||
{
|
||||
uriBuilder.Query = accessTokenQuery + "&" + skuToken;
|
||||
}
|
||||
|
||||
url = uriBuilder.ToString();
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// * add queue for requests
|
||||
// * evaluate rate limits (headers and status code)
|
||||
// * throttle requests accordingly
|
||||
//var request = new HTTPRequest(url, callback);
|
||||
//IEnumerator<IAsyncRequest> proxy = proxyResponse(url, callback);
|
||||
//proxy.MoveNext();
|
||||
//IAsyncRequest request = proxy.Current;
|
||||
|
||||
//return request;
|
||||
|
||||
return proxyResponse(url, callback, timeout, tileId, tilesetId);
|
||||
}
|
||||
|
||||
|
||||
// TODO: look at requests and implement throttling if needed
|
||||
//private IEnumerator<IAsyncRequest> proxyResponse(string url, Action<Response> callback) {
|
||||
private IAsyncRequest proxyResponse(
|
||||
string url
|
||||
, Action<Response> callback
|
||||
, int timeout
|
||||
, CanonicalTileId tileId
|
||||
, string tilesetId
|
||||
)
|
||||
{
|
||||
|
||||
// TODO: plugin caching somewhere around here
|
||||
|
||||
var request = IAsyncRequestFactory.CreateRequest(
|
||||
url
|
||||
, (Response response) =>
|
||||
{
|
||||
if (response.XRateLimitInterval.HasValue) { XRateLimitInterval = response.XRateLimitInterval; }
|
||||
if (response.XRateLimitLimit.HasValue) { XRateLimitLimit = response.XRateLimitLimit; }
|
||||
if (response.XRateLimitReset.HasValue) { XRateLimitReset = response.XRateLimitReset; }
|
||||
callback(response);
|
||||
lock (_lock)
|
||||
{
|
||||
//another place to catch if request has been cancelled
|
||||
try
|
||||
{
|
||||
_requests.Remove(response.Request);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
, timeout
|
||||
);
|
||||
lock (_lock)
|
||||
{
|
||||
//sometimes we get here after the request has already finished
|
||||
if (!request.IsCompleted)
|
||||
{
|
||||
_requests.Add(request, 0);
|
||||
}
|
||||
}
|
||||
//yield return request;
|
||||
return request;
|
||||
}
|
||||
|
||||
|
||||
#if UNITY_5_3_OR_NEWER
|
||||
/// <summary>
|
||||
/// Block until all the requests are processed.
|
||||
/// </summary>
|
||||
public IEnumerator WaitForAllRequests()
|
||||
{
|
||||
while (_requests.Count > 0)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
List<IAsyncRequest> reqs = _requests.Keys.ToList();
|
||||
for (int i = reqs.Count - 1; i > -1; i--)
|
||||
{
|
||||
if (reqs[i].IsCompleted)
|
||||
{
|
||||
// another place to watch out if request has been cancelled
|
||||
try
|
||||
{
|
||||
_requests.Remove(reqs[i]);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
yield return new WaitForSeconds(0.2f);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if !UNITY_5_3_OR_NEWER
|
||||
/// <summary>
|
||||
/// Block until all the requests are processed.
|
||||
/// </summary>
|
||||
public void WaitForAllRequests()
|
||||
{
|
||||
int waitTimeMs = 200;
|
||||
while (_requests.Count > 0)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
List<IAsyncRequest> reqs = _requests.Keys.ToList();
|
||||
for (int i = reqs.Count - 1; i > -1; i--)
|
||||
{
|
||||
if (reqs[i].IsCompleted)
|
||||
{
|
||||
// another place to watch out if request has been cancelled
|
||||
try
|
||||
{
|
||||
_requests.Remove(reqs[i]);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if WINDOWS_UWP
|
||||
System.Threading.Tasks.Task.Delay(waitTimeMs).Wait();
|
||||
#else
|
||||
//Thread.Sleep(50);
|
||||
// TODO: get rid of DoEvents!!! and find non-blocking wait that works for Net3.5
|
||||
//System.Windows.Forms.Application.DoEvents();
|
||||
|
||||
var resetEvent = new ManualResetEvent(false);
|
||||
ThreadPool.QueueUserWorkItem(new WaitCallback(delegate
|
||||
{
|
||||
Thread.Sleep(waitTimeMs);
|
||||
resetEvent.Set();
|
||||
}), null);
|
||||
UnityEngine.Debug.Log("before waitOne " + DateTime.Now.Ticks);
|
||||
resetEvent.WaitOne();
|
||||
UnityEngine.Debug.Log("after waitOne " + DateTime.Now.Ticks);
|
||||
resetEvent.Close();
|
||||
resetEvent = null;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user