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
}
}