diff --git a/sdkproject/Assets/Mapbox/Core/mapbox-sdk-cs/Platform/Cache/CacheItem.cs b/sdkproject/Assets/Mapbox/Core/mapbox-sdk-cs/Platform/Cache/CacheItem.cs
index b3be547f5..7d26d7dd9 100644
--- a/sdkproject/Assets/Mapbox/Core/mapbox-sdk-cs/Platform/Cache/CacheItem.cs
+++ b/sdkproject/Assets/Mapbox/Core/mapbox-sdk-cs/Platform/Cache/CacheItem.cs
@@ -15,5 +15,7 @@ public class CacheItem
public string ETag;
/// Can be 'null' as not all APIs populated this value. Last-Modified value of API response in GMT: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Last-Modified
public DateTime? LastModified;
+
+ public DateTime ExpirationDate;
}
}
diff --git a/sdkproject/Assets/Mapbox/Core/mapbox-sdk-cs/Platform/Cache/CachingWebFileSource.cs b/sdkproject/Assets/Mapbox/Core/mapbox-sdk-cs/Platform/Cache/CachingWebFileSource.cs
index b881516ff..688b63802 100644
--- a/sdkproject/Assets/Mapbox/Core/mapbox-sdk-cs/Platform/Cache/CachingWebFileSource.cs
+++ b/sdkproject/Assets/Mapbox/Core/mapbox-sdk-cs/Platform/Cache/CachingWebFileSource.cs
@@ -1,4 +1,7 @@
-namespace Mapbox.Platform.Cache
+using Unity.UNetWeaver;
+using UnityEngine;
+
+namespace Mapbox.Platform.Cache
{
using System;
using Mapbox.Platform;
@@ -11,8 +14,6 @@
public class CachingWebFileSource : IFileSource, IDisposable
{
-
-
#if MAPBOX_DEBUG_CACHE
private string _className;
#endif
@@ -22,6 +23,9 @@ public class CachingWebFileSource : IFileSource, IDisposable
private Func _getMapsSkuToken;
private bool _autoRefreshCache;
+ private const string EtagHeaderName = "ETag";
+ private const string LastModifiedHeaderName = "Last-Modified";
+ private const string CacheControlHeaderName = "Cache-Control";
public CachingWebFileSource(string accessToken, Func getMapsSkuToken, bool autoRefreshCache)
{
@@ -34,8 +38,7 @@ public CachingWebFileSource(string accessToken, Func getMapsSkuToken, bo
}
-#region idisposable
-
+ #region idisposable
~CachingWebFileSource()
{
@@ -64,12 +67,12 @@ protected virtual void Dispose(bool disposeManagedResources)
}
}
}
+
_disposed = true;
}
}
-
-#endregion
+ #endregion
///
@@ -102,7 +105,8 @@ public void Clear()
}
- public void ReInit() {
+ public void ReInit()
+ {
foreach (var cache in _caches)
{
cache.ReInit();
@@ -118,7 +122,6 @@ string uri
, string tilesetId = null
)
{
-
if (string.IsNullOrEmpty(tilesetId))
{
throw new Exception("Cannot cache without a tileset id");
@@ -150,6 +153,7 @@ string uri
uriBuilder.Query = accessTokenQuery + "&" + mapsSkuToken;
}
}
+
string finalUrl = uriBuilder.ToString();
#if MAPBOX_DEBUG_CACHE
@@ -166,58 +170,52 @@ string uri
callback(Response.FromCache(cachedItem.Data));
// check for updated tiles online if this is enabled in the settings
- if (_autoRefreshCache)
+ if (cachedItem.ExpirationDate < DateTime.Now)
{
// check if tile on the web is newer than the one we already have locally
IAsyncRequestFactory.CreateRequest(
finalUrl,
- (Response headerOnly) =>
+ timeout,
+ "If-None-Match", cachedItem.ETag,
+ (Response response) =>
{
// on error getting information from API just return. tile we have locally has already been returned above
- if (headerOnly.HasError)
+ if (response.HasError || response.StatusCode == null)
{
return;
}
- // TODO: remove Debug.Log before PR
- //UnityEngine.Debug.LogFormat(
- // "{1}{0}cached:{2}{0}header:{3}"
- // , Environment.NewLine
- // , finalUrl
- // , cachedItem.ETag
- // , headerOnly.Headers["ETag"]
- //);
-
// data from cache is the same as on the web:
// * tile has already been returned above
// * make sure all all other caches have it too, but don't force insert via cache.add(false)
// additional ETag empty check: for backwards compability with old caches
- if (!string.IsNullOrEmpty(cachedItem.ETag) && cachedItem.ETag.Equals(headerOnly.Headers["ETag"]))
+ if (response.StatusCode == 304) // 304 NOT MODIFIED
{
- foreach (var cache in _caches)
- {
- cache.Add(tilesetId, tileId, cachedItem, false);
- }
+ cachedItem.ExpirationDate = GetExpirationDate(response);
+ }
+ else if (response.StatusCode == 200) // 200 OK, it means etag&data has changed so need to update cache
+ {
+ string eTag = ETag(response);
+
+ // not all APIs populate 'Last-Modified' header
+ // don't log error if it's missing
+ DateTime? lastModified = GetLastModified(response);
+
+ DateTime expirationDate = GetExpirationDate(response);
+
+ cachedItem.Data = response.Data;
+ cachedItem.ETag = eTag;
+ cachedItem.LastModified = lastModified;
+ cachedItem.ExpirationDate = expirationDate;
}
- else
+
+ foreach (var cache in _caches)
{
- // TODO: remove Debug.Log before PR
- UnityEngine.Debug.LogWarningFormat(
- "updating cached tile {1} tilesetId:{2}{0}cached etag:{3}{0}remote etag:{4}{0}{5}"
- , Environment.NewLine
- , tileId
- , tilesetId
- , cachedItem.ETag
- , headerOnly.Headers["ETag"]
- , finalUrl
- );
-
- // request updated tile and pass callback to return new data to subscribers
- requestTileAndCache(finalUrl, tilesetId, tileId, timeout, callback);
+ cache.Add(tilesetId, tileId, cachedItem, true);
}
+
+ callback(Response.FromCache(cachedItem.Data));
}
- , timeout
- , HttpRequestType.Head
);
}
@@ -233,34 +231,22 @@ string uri
}
}
-
private IAsyncRequest requestTileAndCache(string url, string tilesetId, CanonicalTileId tileId, int timeout, Action callback)
{
return IAsyncRequestFactory.CreateRequest(
url,
- (Response r) =>
+ (Response response) =>
{
// if the request was successful add tile to all caches
- if (!r.HasError && null != r.Data)
+ if (!response.HasError && null != response.Data)
{
- string eTag = string.Empty;
- DateTime? lastModified = null;
-
- if (!r.Headers.ContainsKey("ETag"))
- {
- UnityEngine.Debug.LogWarningFormat("no 'ETag' header present in response for {0}", url);
- }
- else
- {
- eTag = r.Headers["ETag"];
- }
+ string eTag = ETag(response);
// not all APIs populate 'Last-Modified' header
// don't log error if it's missing
- if (r.Headers.ContainsKey("Last-Modified"))
- {
- lastModified = DateTime.ParseExact(r.Headers["Last-Modified"], "r", null);
- }
+ DateTime? lastModified = GetLastModified(response);
+
+ DateTime expirationDate = GetExpirationDate(response);
// propagate to all caches forcing update
foreach (var cache in _caches)
@@ -270,27 +256,76 @@ private IAsyncRequest requestTileAndCache(string url, string tilesetId, Canonica
, tileId
, new CacheItem()
{
- Data = r.Data,
+ Data = response.Data,
ETag = eTag,
- LastModified = lastModified
+ LastModified = lastModified,
+ ExpirationDate = expirationDate
}
, true // force insert/update
);
}
}
+
if (null != callback)
{
- r.IsUpdate = true;
- callback(r);
+ response.IsUpdate = true;
+ callback(response);
}
}, timeout);
}
+ private string ETag(Response response)
+ {
+ string eTag = String.Empty;
+ if (!response.Headers.ContainsKey(EtagHeaderName))
+ {
+ Debug.LogWarning("no 'ETag' header present in response");
+ }
+ else
+ {
+ eTag = response.Headers[EtagHeaderName];
+ }
+
+ return eTag;
+ }
+
+ private DateTime? GetLastModified(Response response)
+ {
+ DateTime? lastModified = null;
+ if (response.Headers.ContainsKey(LastModifiedHeaderName))
+ {
+ lastModified = DateTime.ParseExact(response.Headers[LastModifiedHeaderName], "r", null);
+ }
- class MemoryCacheAsyncRequest : IAsyncRequest
+ return lastModified;
+ }
+
+ private DateTime GetExpirationDate(Response response)
{
+ DateTime expirationDate = DateTime.Now;
+ if (response.Headers.ContainsKey(CacheControlHeaderName))
+ {
+ var cacheEntries = response.Headers[CacheControlHeaderName].Split(',');
+ if (cacheEntries.Length > 0)
+ {
+ foreach (var entry in cacheEntries)
+ {
+ var value = entry.Split('=');
+ if (value[0] == "max-age")
+ {
+ expirationDate = expirationDate + TimeSpan.FromSeconds(int.Parse(value[1]));
+ return expirationDate;
+ }
+ }
+ }
+ }
+ return expirationDate;
+ }
+
+ class MemoryCacheAsyncRequest : IAsyncRequest
+ {
public string RequestUrl { get; private set; }
@@ -302,14 +337,14 @@ public MemoryCacheAsyncRequest(string requestUrl)
public bool IsCompleted
{
- get
- {
- return true;
- }
+ get { return true; }
}
- public HttpRequestType RequestType { get { return HttpRequestType.Get; } }
+ public HttpRequestType RequestType
+ {
+ get { return HttpRequestType.Get; }
+ }
public void Cancel()
@@ -318,4 +353,4 @@ public void Cancel()
}
}
}
-}
+}
\ No newline at end of file
diff --git a/sdkproject/Assets/Mapbox/Core/mapbox-sdk-cs/Platform/Cache/SQLiteCache/SQLiteCache.cs b/sdkproject/Assets/Mapbox/Core/mapbox-sdk-cs/Platform/Cache/SQLiteCache/SQLiteCache.cs
index a221ce117..6d1dccfcf 100644
--- a/sdkproject/Assets/Mapbox/Core/mapbox-sdk-cs/Platform/Cache/SQLiteCache/SQLiteCache.cs
+++ b/sdkproject/Assets/Mapbox/Core/mapbox-sdk-cs/Platform/Cache/SQLiteCache/SQLiteCache.cs
@@ -120,6 +120,7 @@ tile_set INTEGER REFERENCES tilesets (id) ON DELETE CASCADE ON UPDATE CASCAD
tile_row BIGINT NOT NULL,
tile_data BLOB NOT NULL,
timestamp INTEGER NOT NULL,
+expirationdate INTEGER NOT NULL,
etag TEXT,
lastmodified INTEGER,
PRIMARY KEY(
@@ -248,6 +249,7 @@ public void Add(string tilesetName, CanonicalTileId tileId, CacheItem item, bool
tile_row = tileId.Y,
tile_data = item.Data,
timestamp = (int)UnixTimestampUtils.To(DateTime.Now),
+ expirationdate = (int)UnixTimestampUtils.To(item.ExpirationDate),
etag = item.ETag
});
if (1 != rowsAffected)
diff --git a/sdkproject/Assets/Mapbox/Core/mapbox-sdk-cs/Platform/Cache/SQLiteCache/Tiles.cs b/sdkproject/Assets/Mapbox/Core/mapbox-sdk-cs/Platform/Cache/SQLiteCache/Tiles.cs
index 18629526b..411e35fe6 100644
--- a/sdkproject/Assets/Mapbox/Core/mapbox-sdk-cs/Platform/Cache/SQLiteCache/Tiles.cs
+++ b/sdkproject/Assets/Mapbox/Core/mapbox-sdk-cs/Platform/Cache/SQLiteCache/Tiles.cs
@@ -36,5 +36,8 @@ public class tiles
/// Last-Modified header value of API response. Not all APIs populate it, will be -1 in that case.
public int? lastmodified { get; set; }
+
+ /// Last-Modified header value of API response. Not all APIs populate it, will be -1 in that case.
+ public int expirationdate { get; set; }
}
}
diff --git a/sdkproject/Assets/Mapbox/Core/mapbox-sdk-cs/Platform/FileSource.cs b/sdkproject/Assets/Mapbox/Core/mapbox-sdk-cs/Platform/FileSource.cs
index 3225832c1..5070aac02 100644
--- a/sdkproject/Assets/Mapbox/Core/mapbox-sdk-cs/Platform/FileSource.cs
+++ b/sdkproject/Assets/Mapbox/Core/mapbox-sdk-cs/Platform/FileSource.cs
@@ -27,6 +27,7 @@ namespace Mapbox.Platform
#endif
#if UNITY_5_3_OR_NEWER
using UnityEngine;
+
#endif
///
@@ -40,7 +41,6 @@ namespace Mapbox.Platform
///
public sealed class FileSource : IFileSource
{
-
private Func _getMapsSkuToken;
private readonly Dictionary _requests = new Dictionary();
private readonly string _accessToken;
@@ -49,8 +49,10 @@ public sealed class FileSource : IFileSource
/// Length of rate-limiting interval in seconds. https://www.mapbox.com/api-documentation/#rate-limit-headers
#pragma warning disable 0414
private int? XRateLimitInterval;
+
/// Maximum number of requests you may make in the current interval before reaching the limit. https://www.mapbox.com/api-documentation/#rate-limit-headers
private long? XRateLimitLimit;
+
/// Timestamp of when the current interval will end and the ratelimit counter is reset. https://www.mapbox.com/api-documentation/#rate-limit-headers
private DateTime? XRateLimitReset;
#pragma warning restore 0414
@@ -59,14 +61,7 @@ public sealed class FileSource : IFileSource
public FileSource(Func getMapsSkuToken, string acessToken = null)
{
_getMapsSkuToken = getMapsSkuToken;
- if (string.IsNullOrEmpty(acessToken))
- {
- _accessToken = Environment.GetEnvironmentVariable("MAPBOX_ACCESS_TOKEN");
- }
- else
- {
- _accessToken = acessToken;
- }
+ _accessToken = acessToken;
}
/// Performs a request asynchronously.
@@ -92,7 +87,8 @@ string url
string skuToken = "sku=" + _getMapsSkuToken();
if (uriBuilder.Query != null && uriBuilder.Query.Length > 1)
{
- uriBuilder.Query = uriBuilder.Query.Substring(1) + "&" + accessTokenQuery + "&" + skuToken;;
+ uriBuilder.Query = uriBuilder.Query.Substring(1) + "&" + accessTokenQuery + "&" + skuToken;
+ ;
}
else
{
@@ -127,16 +123,27 @@ string url
, 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; }
+ 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)
{
@@ -161,6 +168,7 @@ string url
_requests.Add(request, 0);
}
}
+
//yield return request;
return request;
}
@@ -193,13 +201,13 @@ public IEnumerator WaitForAllRequests()
}
}
}
+
yield return new WaitForSeconds(0.2f);
}
}
#endif
-
#if !UNITY_5_3_OR_NEWER
///
/// Block until all the requests are processed.
@@ -252,4 +260,4 @@ public void WaitForAllRequests()
}
#endif
}
-}
+}
\ No newline at end of file
diff --git a/sdkproject/Assets/Mapbox/Core/mapbox-sdk-cs/Platform/IAsyncRequestFactory.cs b/sdkproject/Assets/Mapbox/Core/mapbox-sdk-cs/Platform/IAsyncRequestFactory.cs
index 195d1e428..01e6e72e2 100644
--- a/sdkproject/Assets/Mapbox/Core/mapbox-sdk-cs/Platform/IAsyncRequestFactory.cs
+++ b/sdkproject/Assets/Mapbox/Core/mapbox-sdk-cs/Platform/IAsyncRequestFactory.cs
@@ -34,6 +34,22 @@ string url
#endif
}
-
+ public static IAsyncRequest CreateRequest(
+ string url
+ , int timeout
+ , string headerName
+ , string headerValue
+ , Action callback
+ ) {
+#if !UNITY
+ if (Environment.ProcessorCount > 2) {
+ return new HTTPRequestThreaded(url, callback, timeout);
+ } else {
+ return new HTTPRequestNonThreaded(url, callback, timeout);
+ }
+#else
+ return new Mapbox.Unity.Utilities.HTTPRequest(url, callback, timeout, headerName, headerValue);
+#endif
+ }
}
}
\ No newline at end of file
diff --git a/sdkproject/Assets/Mapbox/Core/mapbox-sdk-cs/Platform/Response.cs b/sdkproject/Assets/Mapbox/Core/mapbox-sdk-cs/Platform/Response.cs
index 5735aa7ca..2c5ded836 100644
--- a/sdkproject/Assets/Mapbox/Core/mapbox-sdk-cs/Platform/Response.cs
+++ b/sdkproject/Assets/Mapbox/Core/mapbox-sdk-cs/Platform/Response.cs
@@ -315,7 +315,7 @@ public static Response FromWebResponse(IAsyncRequest request, UnityWebRequest ap
int statusCode = (int)apiResponse.responseCode;
response.StatusCode = statusCode;
- if (statusCode != 200)
+ if (statusCode != 200 && statusCode != 304)
{
response.AddException(new Exception(string.Format("Status Code {0}", apiResponse.responseCode)));
}
diff --git a/sdkproject/Assets/Mapbox/Unity/Utilities/HTTPRequest.cs b/sdkproject/Assets/Mapbox/Unity/Utilities/HTTPRequest.cs
index 12ad5936c..26282fd82 100644
--- a/sdkproject/Assets/Mapbox/Unity/Utilities/HTTPRequest.cs
+++ b/sdkproject/Assets/Mapbox/Unity/Utilities/HTTPRequest.cs
@@ -59,6 +59,25 @@ public HTTPRequest(string url, Action callback, int timeout, HttpReque
_request.timeout = timeout;
_callback = callback;
+#if UNITY_EDITOR
+ if (!EditorApplication.isPlaying)
+ {
+ Runnable.EnableRunnableInEditor();
+ }
+#endif
+ Runnable.Run(DoRequest());
+ }
+
+ public HTTPRequest(string url, Action callback, int timeout, string headerName, string headerValue)
+ {
+ IsCompleted = false;
+ _requestType = HttpRequestType.Get;
+ _request = UnityWebRequest.Get(url);
+ _request.SetRequestHeader(headerName, headerValue);
+
+ _request.timeout = timeout;
+ _callback = callback;
+
#if UNITY_EDITOR
if (!EditorApplication.isPlaying)
{