LargeFileDownloadSample.cs 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using BestHTTP;
  5. namespace BestHTTP.Examples
  6. {
  7. public sealed class LargeFileDownloadSample : MonoBehaviour
  8. {
  9. /// <summary>
  10. /// The url of the resource to download
  11. /// </summary>
  12. const string URL = "http://uk3.testmy.net/dl-102400";
  13. #region Private Fields
  14. /// <summary>
  15. /// Cached request to be able to abort it
  16. /// </summary>
  17. HTTPRequest request;
  18. /// <summary>
  19. /// Debug status of the request
  20. /// </summary>
  21. string status = string.Empty;
  22. /// <summary>
  23. /// Download(processing) progress. Its range is between [0..1]
  24. /// </summary>
  25. float progress;
  26. /// <summary>
  27. /// The fragment size that we will set to the request
  28. /// </summary>
  29. int fragmentSize = HTTPResponse.MinBufferSize;
  30. #endregion
  31. #region Unity Events
  32. void Awake()
  33. {
  34. // If we have a non-finished download, set the progress to the value where we left it
  35. if (PlayerPrefs.HasKey("DownloadLength"))
  36. progress = PlayerPrefs.GetInt("DownloadProgress") / (float)PlayerPrefs.GetInt("DownloadLength");
  37. }
  38. void OnDestroy()
  39. {
  40. // Stop the download if we are leaving this example
  41. if (request != null && request.State < HTTPRequestStates.Finished)
  42. {
  43. request.OnProgress = null;
  44. request.Callback = null;
  45. request.Abort();
  46. }
  47. }
  48. void OnGUI()
  49. {
  50. GUIHelper.DrawArea(GUIHelper.ClientArea, true, () =>
  51. {
  52. // Draw the current status
  53. GUILayout.Label("Request status: " + status);
  54. GUILayout.Space(5);
  55. // Draw the current progress
  56. GUILayout.Label(string.Format("Progress: {0:P2} of {1:N0}Mb", progress, PlayerPrefs.GetInt("DownloadLength") / 1048576 /*1 Mb*/));
  57. GUILayout.HorizontalSlider(progress, 0, 1);
  58. GUILayout.Space(50);
  59. if (request == null)
  60. {
  61. // Draw a slider to be able to change the fragment size
  62. GUILayout.Label(string.Format("Desired Fragment Size: {0:N} KBytes", fragmentSize / 1024f));
  63. fragmentSize = (int)GUILayout.HorizontalSlider(fragmentSize, HTTPResponse.MinBufferSize, 10 * 1024 * 1024);
  64. GUILayout.Space(5);
  65. string buttonStr = PlayerPrefs.HasKey("DownloadProgress") ? "Continue Download" : "Start Download";
  66. if (GUILayout.Button(buttonStr))
  67. StreamLargeFileTest();
  68. }
  69. else if (request.State == HTTPRequestStates.Processing && GUILayout.Button("Abort Download"))
  70. {
  71. // Simulate a connection lost
  72. request.Abort();
  73. }
  74. });
  75. }
  76. #endregion
  77. #region Private Helper Functions
  78. // Calling this function again when the "DownloadProgress" key in the PlayerPrefs present will
  79. // continue the download
  80. void StreamLargeFileTest()
  81. {
  82. request = new HTTPRequest(new Uri(URL), (req, resp) =>
  83. {
  84. switch (req.State)
  85. {
  86. // The request is currently processed. With UseStreaming == true, we can get the streamed fragments here
  87. case HTTPRequestStates.Processing:
  88. // SaveLocal the DownloadLength, so we can display the progress
  89. if (!PlayerPrefs.HasKey("DownloadLength"))
  90. {
  91. string value = resp.GetFirstHeaderValue("content-length");
  92. if (!string.IsNullOrEmpty(value))
  93. PlayerPrefs.SetInt("DownloadLength", int.Parse(value));
  94. }
  95. // Get the fragments, and save them
  96. ProcessFragments(resp.GetStreamedFragments());
  97. status = "Processing";
  98. break;
  99. // The request finished without any problem.
  100. case HTTPRequestStates.Finished:
  101. if (resp.IsSuccess)
  102. {
  103. // Save any remaining fragments
  104. ProcessFragments(resp.GetStreamedFragments());
  105. // Completely finished
  106. if (resp.IsStreamingFinished)
  107. {
  108. status = "Streaming finished!";
  109. // We are done, delete the progress key
  110. PlayerPrefs.DeleteKey("DownloadProgress");
  111. PlayerPrefs.Save();
  112. request = null;
  113. }
  114. else
  115. status = "Processing";
  116. }
  117. else
  118. {
  119. status = string.Format("Request finished Successfully, but the server sent an error. Status Code: {0}-{1} Message: {2}",
  120. resp.StatusCode,
  121. resp.Message,
  122. resp.DataAsText);
  123. Debug.LogWarning(status);
  124. request = null;
  125. }
  126. break;
  127. // The request finished with an unexpected error. The request's Exception property may contain more info about the error.
  128. case HTTPRequestStates.Error:
  129. status = "Request Finished with Error! " + (req.Exception != null ? (req.Exception.Message + "\n" + req.Exception.StackTrace) : "No Exception");
  130. Debug.LogError(status);
  131. request = null;
  132. break;
  133. // The request aborted, initiated by the user.
  134. case HTTPRequestStates.Aborted:
  135. status = "Request Aborted!";
  136. Debug.LogWarning(status);
  137. request = null;
  138. break;
  139. // Connecting to the server is timed out.
  140. case HTTPRequestStates.ConnectionTimedOut:
  141. status = "Connection Timed Out!";
  142. Debug.LogError(status);
  143. request = null;
  144. break;
  145. // The request didn't finished in the given time.
  146. case HTTPRequestStates.TimedOut:
  147. status = "Processing the request Timed Out!";
  148. Debug.LogError(status);
  149. request = null;
  150. break;
  151. }
  152. });
  153. // Are there any progress, that we can continue?
  154. if (PlayerPrefs.HasKey("DownloadProgress"))
  155. // SaveLocal the range header
  156. request.SetRangeHeader(PlayerPrefs.GetInt("DownloadProgress"));
  157. else
  158. // This is a new request
  159. PlayerPrefs.SetInt("DownloadProgress", 0);
  160. #if !BESTHTTP_DISABLE_CACHING && (!UNITY_WEBGL || UNITY_EDITOR)
  161. // If we are writing our own file set it true(disable), so don't duplicate it on the file-system
  162. request.DisableCache = true;
  163. #endif
  164. // We want to access the downloaded bytes while we are still downloading
  165. request.UseStreaming = true;
  166. // SaveLocal a reasonable high fragment size. Here it is 5 megabytes.
  167. request.StreamFragmentSize = fragmentSize;
  168. // Start Processing the request
  169. request.Send();
  170. }
  171. /// <summary>
  172. /// In this function we can do whatever we want with the downloaded bytes. In this sample we will do nothing, just set the metadata to display progress.
  173. /// </summary>
  174. void ProcessFragments(List<byte[]> fragments)
  175. {
  176. if (fragments != null && fragments.Count > 0)
  177. {
  178. /*string dir = "TODO!";
  179. string filename = "TODO!";
  180. using (System.IO.FileStream fs = new System.IO.FileStream(System.IO.Path.Combine(dir, filename), System.IO.FileMode.Append))
  181. for (int i = 0; i < fragments.Count; ++i)
  182. fs.Write(fragments[i], 0, fragments[i].Length);*/
  183. for (int i = 0; i < fragments.Count; ++i)
  184. {
  185. // Save how many bytes we wrote successfully
  186. int downloaded = PlayerPrefs.GetInt("DownloadProgress") + fragments[i].Length;
  187. PlayerPrefs.SetInt("DownloadProgress", downloaded);
  188. }
  189. PlayerPrefs.Save();
  190. // SaveLocal the progress to the actually processed bytes
  191. progress = PlayerPrefs.GetInt("DownloadProgress") / (float)PlayerPrefs.GetInt("DownloadLength");
  192. }
  193. }
  194. #endregion
  195. }
  196. }