using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using BestHTTP; namespace BestHTTP.Examples.HTTP { public class StreamingSample : BestHTTP.Examples.Helpers.SampleBase { #pragma warning disable 0649 [Tooltip("The url of the resource to download")] [SerializeField] protected string _downloadPath = "/test100mb.dat"; [Header("Streaming Setup")] [SerializeField] protected RectTransform _streamingSetupRoot; [SerializeField] protected Slider _fragmentSizeSlider; [SerializeField] protected Text _fragmentSizeText; [SerializeField] protected Toggle _disableCacheToggle; [Header("Reporting")] [SerializeField] protected RectTransform _reportingRoot; [SerializeField] protected Slider _downloadProgressSlider; [SerializeField] protected Text _downloadProgressText; [SerializeField] protected Slider _processedDataSlider; [SerializeField] protected Text _processedDataText; [SerializeField] protected Text _statusText; [SerializeField] protected Button _startDownload; [SerializeField] protected Button _cancelDownload; #pragma warning restore /// /// Cached request to be able to abort it /// protected HTTPRequest request; /// /// Download(processing) progress. Its range is between [0..1] /// protected float progress; /// /// The fragment size that we will set to the request /// protected int fragmentSize = HTTPResponse.MinReadBufferSize; protected virtual long DownloadLength { get; set; } protected virtual long ProcessedBytes { get; set; } protected override void Start() { base.Start(); this._streamingSetupRoot.gameObject.SetActive(true); this._reportingRoot.gameObject.SetActive(false); this._startDownload.interactable = true; this._cancelDownload.interactable = false; this._fragmentSizeSlider.value = (1024 * 1024 - HTTPResponse.MinReadBufferSize) / 1024; this._fragmentSizeText.text = GUIHelper.GetBytesStr(1024 * 1024, 1); } protected void OnDestroy() { // Stop the download if we are leaving this example if (request != null && request.State < HTTPRequestStates.Finished) { request.OnDownloadProgress = null; request.Callback = null; request.Abort(); } } public void OnFragmentSizeSliderChanged(float value) { this.fragmentSize = HTTPResponse.MinReadBufferSize + (int)value * 1024; this._fragmentSizeText.text = GUIHelper.GetBytesStr(this.fragmentSize, 1); } public void Cancel() { if (this.request != null) this.request.Abort(); } protected virtual void SetupRequest() { request = new HTTPRequest(new Uri(base.sampleSelector.BaseURL + this._downloadPath), OnRequestFinished); #if !BESTHTTP_DISABLE_CACHING // If we are writing our own file set it to true(disable), so don't duplicate it on the file-system request.DisableCache = this._disableCacheToggle.isOn; #endif request.StreamFragmentSize = fragmentSize; request.Tag = DateTime.Now; request.OnHeadersReceived += OnHeadersReceived; request.OnDownloadProgress += OnDownloadProgress; request.OnStreamingData += OnDataDownloaded; } public virtual void StartStreaming() { SetupRequest(); // Start Processing the request request.Send(); this._statusText.text = "Download started!"; // UI this._streamingSetupRoot.gameObject.SetActive(false); this._reportingRoot.gameObject.SetActive(true); this._startDownload.interactable = false; this._cancelDownload.interactable = true; ResetProcessedValues(); } private void OnHeadersReceived(HTTPRequest req, HTTPResponse resp, Dictionary> newHeaders) { var range = resp.GetRange(); if (range != null) this.DownloadLength = range.ContentLength; else { var contentLength = resp.GetFirstHeaderValue("content-length"); if (contentLength != null) { long length = 0; if (long.TryParse(contentLength, out length)) this.DownloadLength = length; } } } protected virtual void OnRequestFinished(HTTPRequest req, HTTPResponse resp) { switch (req.State) { // The request finished without any problem. case HTTPRequestStates.Finished: if (resp.IsSuccess) { DateTime downloadStarted = (DateTime)req.Tag; TimeSpan diff = DateTime.Now - downloadStarted; this._statusText.text = string.Format("Streaming finished in {0:N0}ms", diff.TotalMilliseconds); } else { this._statusText.text = string.Format("Request finished Successfully, but the server sent an error. Status Code: {0}-{1} Message: {2}", resp.StatusCode, resp.Message, resp.DataAsText); Debug.LogWarning(this._statusText.text); request = null; } break; // The request finished with an unexpected error. The request's Exception property may contain more info about the error. case HTTPRequestStates.Error: this._statusText.text = "Request Finished with Error! " + (req.Exception != null ? (req.Exception.Message + "\n" + req.Exception.StackTrace) : "No Exception"); Debug.LogError(this._statusText.text); request = null; break; // The request aborted, initiated by the user. case HTTPRequestStates.Aborted: this._statusText.text = "Request Aborted!"; Debug.LogWarning(this._statusText.text); request = null; break; // Connecting to the server is timed out. case HTTPRequestStates.ConnectionTimedOut: this._statusText.text = "Connection Timed Out!"; Debug.LogError(this._statusText.text); request = null; break; // The request didn't finished in the given time. case HTTPRequestStates.TimedOut: this._statusText.text = "Processing the request Timed Out!"; Debug.LogError(this._statusText.text); request = null; break; } // UI this._streamingSetupRoot.gameObject.SetActive(true); this._reportingRoot.gameObject.SetActive(false); this._startDownload.interactable = true; this._cancelDownload.interactable = false; request = null; } protected virtual void OnDownloadProgress(HTTPRequest originalRequest, long downloaded, long downloadLength) { double downloadPercent = (downloaded / (double)downloadLength) * 100; this._downloadProgressSlider.value = (float)downloadPercent; this._downloadProgressText.text = string.Format("{0:F1}%", downloadPercent); } protected virtual bool OnDataDownloaded(HTTPRequest request, HTTPResponse response, byte[] dataFragment, int dataFragmentLength) { this.ProcessedBytes += dataFragmentLength; SetDataProcessedUI(this.ProcessedBytes, this.DownloadLength); // Use downloaded data // Return true if dataFrament is processed so the plugin can recycle the byte[] return true; } protected void SetDataProcessedUI(long processed, long length) { float processedPercent = (processed / (float)length) * 100f; this._processedDataSlider.value = processedPercent; this._processedDataText.text = GUIHelper.GetBytesStr(processed, 0); } protected virtual void ResetProcessedValues() { this.ProcessedBytes = 0; this.DownloadLength = 0; SetDataProcessedUI(this.ProcessedBytes, this.DownloadLength); } } }