You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
272 lines
9.1 KiB
272 lines
9.1 KiB
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 |
|
|
|
/// <summary> |
|
/// Cached request to be able to abort it |
|
/// </summary> |
|
protected HTTPRequest request; |
|
|
|
/// <summary> |
|
/// Download(processing) progress. Its range is between [0..1] |
|
/// </summary> |
|
protected float progress; |
|
|
|
/// <summary> |
|
/// The fragment size that we will set to the request |
|
/// </summary> |
|
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<string, List<string>> 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); |
|
} |
|
} |
|
}
|
|
|