StreamingSample.cs 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEngine.UI;
  5. using BestHTTP;
  6. namespace BestHTTP.Examples.HTTP
  7. {
  8. public class StreamingSample : BestHTTP.Examples.Helpers.SampleBase
  9. {
  10. #pragma warning disable 0649
  11. [Tooltip("The url of the resource to download")]
  12. [SerializeField]
  13. protected string _downloadPath = "/test100mb.dat";
  14. [Header("Streaming Setup")]
  15. [SerializeField]
  16. protected RectTransform _streamingSetupRoot;
  17. [SerializeField]
  18. protected Slider _fragmentSizeSlider;
  19. [SerializeField]
  20. protected Text _fragmentSizeText;
  21. [SerializeField]
  22. protected Toggle _disableCacheToggle;
  23. [Header("Reporting")]
  24. [SerializeField]
  25. protected RectTransform _reportingRoot;
  26. [SerializeField]
  27. protected Slider _downloadProgressSlider;
  28. [SerializeField]
  29. protected Text _downloadProgressText;
  30. [SerializeField]
  31. protected Slider _processedDataSlider;
  32. [SerializeField]
  33. protected Text _processedDataText;
  34. [SerializeField]
  35. protected Text _statusText;
  36. [SerializeField]
  37. protected Button _startDownload;
  38. [SerializeField]
  39. protected Button _cancelDownload;
  40. #pragma warning restore
  41. /// <summary>
  42. /// Cached request to be able to abort it
  43. /// </summary>
  44. protected HTTPRequest request;
  45. /// <summary>
  46. /// Download(processing) progress. Its range is between [0..1]
  47. /// </summary>
  48. protected float progress;
  49. /// <summary>
  50. /// The fragment size that we will set to the request
  51. /// </summary>
  52. protected int fragmentSize = HTTPResponse.MinReadBufferSize;
  53. protected virtual long DownloadLength { get; set; }
  54. protected virtual long ProcessedBytes { get; set; }
  55. protected override void Start()
  56. {
  57. base.Start();
  58. this._streamingSetupRoot.gameObject.SetActive(true);
  59. this._reportingRoot.gameObject.SetActive(false);
  60. this._startDownload.interactable = true;
  61. this._cancelDownload.interactable = false;
  62. this._fragmentSizeSlider.value = (1024 * 1024 - HTTPResponse.MinReadBufferSize) / 1024;
  63. this._fragmentSizeText.text = GUIHelper.GetBytesStr(1024 * 1024, 1);
  64. }
  65. protected void OnDestroy()
  66. {
  67. // Stop the download if we are leaving this example
  68. if (request != null && request.State < HTTPRequestStates.Finished)
  69. {
  70. request.OnDownloadProgress = null;
  71. request.Callback = null;
  72. request.Abort();
  73. }
  74. }
  75. public void OnFragmentSizeSliderChanged(float value)
  76. {
  77. this.fragmentSize = HTTPResponse.MinReadBufferSize + (int)value * 1024;
  78. this._fragmentSizeText.text = GUIHelper.GetBytesStr(this.fragmentSize, 1);
  79. }
  80. public void Cancel()
  81. {
  82. if (this.request != null)
  83. this.request.Abort();
  84. }
  85. protected virtual void SetupRequest()
  86. {
  87. request = new HTTPRequest(new Uri(base.sampleSelector.BaseURL + this._downloadPath), OnRequestFinished);
  88. #if !BESTHTTP_DISABLE_CACHING
  89. // If we are writing our own file set it to true(disable), so don't duplicate it on the file-system
  90. request.DisableCache = this._disableCacheToggle.isOn;
  91. #endif
  92. request.StreamFragmentSize = fragmentSize;
  93. request.Tag = DateTime.Now;
  94. request.OnHeadersReceived += OnHeadersReceived;
  95. request.OnDownloadProgress += OnDownloadProgress;
  96. request.OnStreamingData += OnDataDownloaded;
  97. }
  98. public virtual void StartStreaming()
  99. {
  100. SetupRequest();
  101. // Start Processing the request
  102. request.Send();
  103. this._statusText.text = "Download started!";
  104. // UI
  105. this._streamingSetupRoot.gameObject.SetActive(false);
  106. this._reportingRoot.gameObject.SetActive(true);
  107. this._startDownload.interactable = false;
  108. this._cancelDownload.interactable = true;
  109. ResetProcessedValues();
  110. }
  111. private void OnHeadersReceived(HTTPRequest req, HTTPResponse resp, Dictionary<string, List<string>> newHeaders)
  112. {
  113. var range = resp.GetRange();
  114. if (range != null)
  115. this.DownloadLength = range.ContentLength;
  116. else
  117. {
  118. var contentLength = resp.GetFirstHeaderValue("content-length");
  119. if (contentLength != null)
  120. {
  121. long length = 0;
  122. if (long.TryParse(contentLength, out length))
  123. this.DownloadLength = length;
  124. }
  125. }
  126. }
  127. protected virtual void OnRequestFinished(HTTPRequest req, HTTPResponse resp)
  128. {
  129. switch (req.State)
  130. {
  131. // The request finished without any problem.
  132. case HTTPRequestStates.Finished:
  133. if (resp.IsSuccess)
  134. {
  135. DateTime downloadStarted = (DateTime)req.Tag;
  136. TimeSpan diff = DateTime.Now - downloadStarted;
  137. this._statusText.text = string.Format("Streaming finished in {0:N0}ms", diff.TotalMilliseconds);
  138. }
  139. else
  140. {
  141. this._statusText.text = string.Format("Request finished Successfully, but the server sent an error. Status Code: {0}-{1} Message: {2}",
  142. resp.StatusCode,
  143. resp.Message,
  144. resp.DataAsText);
  145. Debug.LogWarning(this._statusText.text);
  146. request = null;
  147. }
  148. break;
  149. // The request finished with an unexpected error. The request's Exception property may contain more info about the error.
  150. case HTTPRequestStates.Error:
  151. this._statusText.text = "Request Finished with Error! " + (req.Exception != null ? (req.Exception.Message + "\n" + req.Exception.StackTrace) : "No Exception");
  152. Debug.LogError(this._statusText.text);
  153. request = null;
  154. break;
  155. // The request aborted, initiated by the user.
  156. case HTTPRequestStates.Aborted:
  157. this._statusText.text = "Request Aborted!";
  158. Debug.LogWarning(this._statusText.text);
  159. request = null;
  160. break;
  161. // Connecting to the server is timed out.
  162. case HTTPRequestStates.ConnectionTimedOut:
  163. this._statusText.text = "Connection Timed Out!";
  164. Debug.LogError(this._statusText.text);
  165. request = null;
  166. break;
  167. // The request didn't finished in the given time.
  168. case HTTPRequestStates.TimedOut:
  169. this._statusText.text = "Processing the request Timed Out!";
  170. Debug.LogError(this._statusText.text);
  171. request = null;
  172. break;
  173. }
  174. // UI
  175. this._streamingSetupRoot.gameObject.SetActive(true);
  176. this._reportingRoot.gameObject.SetActive(false);
  177. this._startDownload.interactable = true;
  178. this._cancelDownload.interactable = false;
  179. request = null;
  180. }
  181. protected virtual void OnDownloadProgress(HTTPRequest originalRequest, long downloaded, long downloadLength)
  182. {
  183. double downloadPercent = (downloaded / (double)downloadLength) * 100;
  184. this._downloadProgressSlider.value = (float)downloadPercent;
  185. this._downloadProgressText.text = string.Format("{0:F1}%", downloadPercent);
  186. }
  187. protected virtual bool OnDataDownloaded(HTTPRequest request, HTTPResponse response, byte[] dataFragment, int dataFragmentLength)
  188. {
  189. this.ProcessedBytes += dataFragmentLength;
  190. SetDataProcessedUI(this.ProcessedBytes, this.DownloadLength);
  191. // Use downloaded data
  192. // Return true if dataFrament is processed so the plugin can recycle the byte[]
  193. return true;
  194. }
  195. protected void SetDataProcessedUI(long processed, long length)
  196. {
  197. float processedPercent = (processed / (float)length) * 100f;
  198. this._processedDataSlider.value = processedPercent;
  199. this._processedDataText.text = GUIHelper.GetBytesStr(processed, 0);
  200. }
  201. protected virtual void ResetProcessedValues()
  202. {
  203. this.ProcessedBytes = 0;
  204. this.DownloadLength = 0;
  205. SetDataProcessedUI(this.ProcessedBytes, this.DownloadLength);
  206. }
  207. }
  208. }