123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184 |
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Threading.Tasks;
- using Best.HTTP.Examples.Helpers;
- using Best.HTTP.Response;
- using Best.HTTP.Shared;
- using Best.HTTP.Shared.Extensions;
- using Best.HTTP.Shared.PlatformSupport.Memory;
- using UnityEngine;
- using UnityEngine.Scripting;
- namespace Best.HTTP.Examples
- {
- /// <summary>
- /// Example demonstrating usage of BeginCache, EndCache functions and HTTPCacheContentWriter class to manually store content for an url.
- /// </summary>
- class PopulateCacheManuallySample : SampleBase
- {
- // Constants passed to the API endpoint stored in _baseAddress
- const int FromUserId = 1;
- const int ToUserId = 10;
- /// <summary>
- /// String template used for generating unique uris for every user stored individually in the local cache.
- /// </summary>
- const string LocalCacheUserURLTemplate = "httpcache://userapi/user/{0}";
- #pragma warning disable 0649, 0169
- [Header("Sample Fields")]
- /// <summary>
- /// GameObject that will be used as a root for new UI objects.
- /// </summary>
- [SerializeField]
- private RectTransform _contentRoot;
- /// <summary>
- /// Prefab of a UI object with two Text fields.
- /// </summary>
- [SerializeField]
- private MultiTextListItem _listItemPrefab;
- #pragma warning restore
- /// <summary>
- /// Address of the used end point.
- /// </summary>
- private string _baseAddress = "https://besthttpwebgldemo.azurewebsites.net/users/{0}/{1}";
- protected override async void Start()
- {
- base.Start();
- CreateUIItem("Loading users...");
- await PopulateLocalCache();
- await LoadUsersFromLocalCache();
- }
- async Task PopulateLocalCache()
- {
- try
- {
- // Load a list of users from the server
- var users = await HTTPRequest.CreateGet(string.Format(_baseAddress, FromUserId, ToUserId))
- .GetFromJsonResultAsync<List<User>>();
- CreateUIItem($"Received {users.Count} users from /users/{FromUserId}/{ToUserId}");
- StoreUsersInLocalCache(users);
- }
- catch (AsyncHTTPException ex)
- {
- CreateUIItem($"/Users request failed: {ex.Message}");
- }
- }
- void StoreUsersInLocalCache(List<User> users)
- {
- // Go over all the users and save them to the local cache with a custom uri
- foreach (var user in users)
- {
- var userUri = new Uri(string.Format(LocalCacheUserURLTemplate, user.Id));
- // convert the user object to json string and get the string's bytes
- var content = UserToByteArray(user);
- // BeginCache expects at least one caching header ("cache-control" with "max-age" directive, "etag", "expires" or "last-modified").
- // A cache-control with a max-age directive is a good choice for fabricated urls as the plugin will not try to valide the content's freshness.
- var headers = new Dictionary<string, List<string>> { { "cache-control", new List<string> { $"max-age={TimeSpan.FromDays(360).TotalSeconds}" } } };
- // Start the caching procedure by calling BeginCache and pass all the required parameters.
- var cacheWriter = HTTPManager.LocalCache.BeginCache(HTTPMethods.Get, userUri, HTTPStatusCodes.OK, headers, null);
- // If the writer is null, something prevents caching, these can be one of the following:
- // - caching itself isn't supported
- // - userUri doesn't start with 'http'
- // - can't acquire a write lock on the resource (a request currently reading or writing the same uri)
- // - IO error
- // - If the headers passed to BeginCache has a "content-length" header too, BeginCache checks whether it's in the limits of the cache. If it can make enough room to fit a null value will be returned.
- if (cacheWriter == null)
- {
- CreateUIItem($"Can't cache user('{user.Id}')!");
- continue;
- }
- try
- {
- // Write content to the cache.
- // Under the hood this writes to a file, if presumably it will take a long time (large content and/or slow media) it's advised to use a Thread.
- cacheWriter.Write(content);
- // Finish the caching process by calling EndCache.
- // This call will do all housekeeping, like disposing internal streams and releasing the write lock on the uri.
- // After this call, requests to this very same uri will load and serve from the local cache.
- HTTPManager.LocalCache.EndCache(cacheWriter, true, null);
- CreateUIItem($"User cached as '{userUri}'");
- }
- catch (Exception ex)
- {
- Debug.LogException(ex);
- // We must call EndCache even if there's an error, otherwise not all resources are disposed and
- // new attempts to write to this cache entry will fail!
- HTTPManager.LocalCache.EndCache(cacheWriter, false, null);
- CreateUIItem($"Writing to cache failed with user '{user.Id}'");
- }
- finally
- {
- // content's byte[] is borrowed from the BufferPool, it's a nice thing to return it!
- BufferPool.Release(content);
- }
- }
- }
- /// <summary>
- /// This function will test/emulate requests loading cached individual users
- /// </summary>
- async Task LoadUsersFromLocalCache()
- {
- for (int id = FromUserId; id < ToUserId; id++)
- {
- // Create and execute a HTTP request to get one individual user's data from the local cache
- var user = await HTTPRequest.CreateGet(string.Format(LocalCacheUserURLTemplate, id))
- .GetFromJsonResultAsync<User>();
- CreateUIItem($"User '{user.Id}' loaded from local cache (uri: '{string.Format(LocalCacheUserURLTemplate, id)}')!");
- }
- }
- /// <summary>
- /// Converts a User object to JSon string and returns with the byte representation of the string
- /// </summary>
- BufferSegment UserToByteArray(User user)
- {
- string json = JSON.LitJson.JsonMapper.ToJson(user);
- int length = Encoding.UTF8.GetByteCount(json);
- byte[] result = BufferPool.Get(length, true);
- Encoding.UTF8.GetBytes(json, 0, json.Length, result, 0);
- return result.AsBuffer(length);
- }
- MultiTextListItem CreateUIItem(string str)
- => Instantiate<MultiTextListItem>(this._listItemPrefab, this._contentRoot)
- .SetText(str) as MultiTextListItem;
- }
- [Preserve]
- class User
- {
- [Preserve] public string Id { get; set; }
- [Preserve] public string Name { get; set; }
- [Preserve] public DateTime Joined { get; set; }
- }
- }
|