using System; using System.Collections.Generic; using UnityEngine; using BestHTTP; namespace BestHTTP.Examples { public sealed class LargeFileDownloadSample : MonoBehaviour { /// /// The url of the resource to download /// const string URL = "http://uk3.testmy.net/dl-102400"; #region Private Fields /// /// Cached request to be able to abort it /// HTTPRequest request; /// /// Debug status of the request /// string status = string.Empty; /// /// Download(processing) progress. Its range is between [0..1] /// float progress; /// /// The fragment size that we will set to the request /// int fragmentSize = HTTPResponse.MinBufferSize; #endregion #region Unity Events void Awake() { // If we have a non-finished download, set the progress to the value where we left it if (PlayerPrefs.HasKey("DownloadLength")) progress = PlayerPrefs.GetInt("DownloadProgress") / (float)PlayerPrefs.GetInt("DownloadLength"); } void OnDestroy() { // Stop the download if we are leaving this example if (request != null && request.State < HTTPRequestStates.Finished) { request.OnProgress = null; request.Callback = null; request.Abort(); } } void OnGUI() { GUIHelper.DrawArea(GUIHelper.ClientArea, true, () => { // Draw the current status GUILayout.Label("Request status: " + status); GUILayout.Space(5); // Draw the current progress GUILayout.Label(string.Format("Progress: {0:P2} of {1:N0}Mb", progress, PlayerPrefs.GetInt("DownloadLength") / 1048576 /*1 Mb*/)); GUILayout.HorizontalSlider(progress, 0, 1); GUILayout.Space(50); if (request == null) { // Draw a slider to be able to change the fragment size GUILayout.Label(string.Format("Desired Fragment Size: {0:N} KBytes", fragmentSize / 1024f)); fragmentSize = (int)GUILayout.HorizontalSlider(fragmentSize, HTTPResponse.MinBufferSize, 10 * 1024 * 1024); GUILayout.Space(5); string buttonStr = PlayerPrefs.HasKey("DownloadProgress") ? "Continue Download" : "Start Download"; if (GUILayout.Button(buttonStr)) StreamLargeFileTest(); } else if (request.State == HTTPRequestStates.Processing && GUILayout.Button("Abort Download")) { // Simulate a connection lost request.Abort(); } }); } #endregion #region Private Helper Functions // Calling this function again when the "DownloadProgress" key in the PlayerPrefs present will // continue the download void StreamLargeFileTest() { request = new HTTPRequest(new Uri(URL), (req, resp) => { switch (req.State) { // The request is currently processed. With UseStreaming == true, we can get the streamed fragments here case HTTPRequestStates.Processing: // SaveLocal the DownloadLength, so we can display the progress if (!PlayerPrefs.HasKey("DownloadLength")) { string value = resp.GetFirstHeaderValue("content-length"); if (!string.IsNullOrEmpty(value)) PlayerPrefs.SetInt("DownloadLength", int.Parse(value)); } // Get the fragments, and save them ProcessFragments(resp.GetStreamedFragments()); status = "Processing"; break; // The request finished without any problem. case HTTPRequestStates.Finished: if (resp.IsSuccess) { // Save any remaining fragments ProcessFragments(resp.GetStreamedFragments()); // Completely finished if (resp.IsStreamingFinished) { status = "Streaming finished!"; // We are done, delete the progress key PlayerPrefs.DeleteKey("DownloadProgress"); PlayerPrefs.Save(); request = null; } else status = "Processing"; } else { status = 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(status); 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: status = "Request Finished with Error! " + (req.Exception != null ? (req.Exception.Message + "\n" + req.Exception.StackTrace) : "No Exception"); Debug.LogError(status); request = null; break; // The request aborted, initiated by the user. case HTTPRequestStates.Aborted: status = "Request Aborted!"; Debug.LogWarning(status); request = null; break; // Connecting to the server is timed out. case HTTPRequestStates.ConnectionTimedOut: status = "Connection Timed Out!"; Debug.LogError(status); request = null; break; // The request didn't finished in the given time. case HTTPRequestStates.TimedOut: status = "Processing the request Timed Out!"; Debug.LogError(status); request = null; break; } }); // Are there any progress, that we can continue? if (PlayerPrefs.HasKey("DownloadProgress")) // SaveLocal the range header request.SetRangeHeader(PlayerPrefs.GetInt("DownloadProgress")); else // This is a new request PlayerPrefs.SetInt("DownloadProgress", 0); #if !BESTHTTP_DISABLE_CACHING && (!UNITY_WEBGL || UNITY_EDITOR) // If we are writing our own file set it true(disable), so don't duplicate it on the file-system request.DisableCache = true; #endif // We want to access the downloaded bytes while we are still downloading request.UseStreaming = true; // SaveLocal a reasonable high fragment size. Here it is 5 megabytes. request.StreamFragmentSize = fragmentSize; // Start Processing the request request.Send(); } /// /// 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. /// void ProcessFragments(List fragments) { if (fragments != null && fragments.Count > 0) { /*string dir = "TODO!"; string filename = "TODO!"; using (System.IO.FileStream fs = new System.IO.FileStream(System.IO.Path.Combine(dir, filename), System.IO.FileMode.Append)) for (int i = 0; i < fragments.Count; ++i) fs.Write(fragments[i], 0, fragments[i].Length);*/ for (int i = 0; i < fragments.Count; ++i) { // Save how many bytes we wrote successfully int downloaded = PlayerPrefs.GetInt("DownloadProgress") + fragments[i].Length; PlayerPrefs.SetInt("DownloadProgress", downloaded); } PlayerPrefs.Save(); // SaveLocal the progress to the actually processed bytes progress = PlayerPrefs.GetInt("DownloadProgress") / (float)PlayerPrefs.GetInt("DownloadLength"); } } #endregion } }