mirror of
https://gitee.com/jisol/jisol-game/
synced 2025-09-27 02:36:14 +00:00
提交帧同步案例
This commit is contained in:
@@ -0,0 +1,195 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using UnityEngine;
|
||||
using BestHTTP;
|
||||
|
||||
namespace BestHTTP.Examples
|
||||
{
|
||||
public sealed class AssetBundleSample : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// The url of the resource to download
|
||||
/// </summary>
|
||||
private Uri URI = new Uri(GUIHelper.BaseURL + "/AssetBundles/WebGL/demobundle.assetbundle");
|
||||
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Debug status text
|
||||
/// </summary>
|
||||
string status = "Waiting for user interaction";
|
||||
|
||||
/// <summary>
|
||||
/// The downloaded and cached AssetBundle
|
||||
/// </summary>
|
||||
AssetBundle cachedBundle;
|
||||
|
||||
/// <summary>
|
||||
/// The loaded texture from the AssetBundle
|
||||
/// </summary>
|
||||
Texture2D texture;
|
||||
|
||||
/// <summary>
|
||||
/// A flag that indicates that we are processing the request/bundle to hide the "Start Download" button.
|
||||
/// </summary>
|
||||
bool downloading;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unity Events
|
||||
|
||||
void OnGUI()
|
||||
{
|
||||
GUIHelper.DrawArea(GUIHelper.ClientArea, true, () =>
|
||||
{
|
||||
GUILayout.Label("Status: " + status);
|
||||
|
||||
// Draw the texture from the downloaded bundle
|
||||
if (texture != null)
|
||||
GUILayout.Box(texture, GUILayout.MaxHeight(256));
|
||||
|
||||
if (!downloading && GUILayout.Button("Start Download"))
|
||||
{
|
||||
UnloadBundle();
|
||||
|
||||
StartCoroutine(DownloadAssetBundle());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
UnloadBundle();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Helper Functions
|
||||
|
||||
IEnumerator DownloadAssetBundle()
|
||||
{
|
||||
downloading = true;
|
||||
|
||||
// Create and send our request
|
||||
var request = new HTTPRequest(URI).Send();
|
||||
|
||||
status = "Download started";
|
||||
|
||||
// Wait while it's finishes and add some fancy dots to display something while the user waits for it.
|
||||
// A simple "yield return StartCoroutine(request);" would do the job too.
|
||||
while (request.State < HTTPRequestStates.Finished)
|
||||
{
|
||||
yield return new WaitForSeconds(0.1f);
|
||||
|
||||
status += ".";
|
||||
}
|
||||
|
||||
// Check the outcome of our request.
|
||||
switch (request.State)
|
||||
{
|
||||
// The request finished without any problem.
|
||||
case HTTPRequestStates.Finished:
|
||||
|
||||
if (request.Response.IsSuccess)
|
||||
{
|
||||
#if !BESTHTTP_DISABLE_CACHING
|
||||
status = string.Format("AssetBundle downloaded! Loaded from local cache: {0}", request.Response.IsFromCache.ToString());
|
||||
#else
|
||||
status = "AssetBundle downloaded!";
|
||||
#endif
|
||||
|
||||
// Start creating the downloaded asset bundle
|
||||
AssetBundleCreateRequest async =
|
||||
#if UNITY_5_3_OR_NEWER
|
||||
AssetBundle.LoadFromMemoryAsync(request.Response.Data);
|
||||
#else
|
||||
AssetBundle.CreateFromMemory(request.Response.Data);
|
||||
#endif
|
||||
|
||||
// wait for it
|
||||
yield return async;
|
||||
|
||||
// And process the bundle
|
||||
yield return StartCoroutine(ProcessAssetBundle(async.assetBundle));
|
||||
}
|
||||
else
|
||||
{
|
||||
status = string.Format("Request finished Successfully, but the server sent an error. Status Code: {0}-{1} Message: {2}",
|
||||
request.Response.StatusCode,
|
||||
request.Response.Message,
|
||||
request.Response.DataAsText);
|
||||
Debug.LogWarning(status);
|
||||
}
|
||||
|
||||
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! " + (request.Exception != null ? (request.Exception.Message + "\n" + request.Exception.StackTrace) : "No Exception");
|
||||
Debug.LogError(status);
|
||||
break;
|
||||
|
||||
// The request aborted, initiated by the user.
|
||||
case HTTPRequestStates.Aborted:
|
||||
status = "Request Aborted!";
|
||||
Debug.LogWarning(status);
|
||||
break;
|
||||
|
||||
// Connecting to the server is timed out.
|
||||
case HTTPRequestStates.ConnectionTimedOut:
|
||||
status = "Connection Timed Out!";
|
||||
Debug.LogError(status);
|
||||
break;
|
||||
|
||||
// The request didn't finished in the given time.
|
||||
case HTTPRequestStates.TimedOut:
|
||||
status = "Processing the request Timed Out!";
|
||||
Debug.LogError(status);
|
||||
break;
|
||||
}
|
||||
|
||||
downloading = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// In this function we can do whatever we want with the freshly downloaded bundle.
|
||||
/// In this example we will cache it for later use, and we will load a texture from it.
|
||||
/// </summary>
|
||||
IEnumerator ProcessAssetBundle(AssetBundle bundle)
|
||||
{
|
||||
if (bundle == null)
|
||||
yield break;
|
||||
|
||||
// Save the bundle for future use
|
||||
cachedBundle = bundle;
|
||||
|
||||
// Start loading the asset from the bundle
|
||||
var asyncAsset =
|
||||
#if UNITY_5_1 || UNITY_5_2 || UNITY_5_3_OR_NEWER
|
||||
cachedBundle.LoadAssetAsync("9443182_orig", typeof(Texture2D));
|
||||
#else
|
||||
|
||||
cachedBundle.LoadAsync("9443182_orig", typeof(Texture2D));
|
||||
#endif
|
||||
|
||||
// wait til load
|
||||
yield return asyncAsset;
|
||||
|
||||
// get the texture
|
||||
texture = asyncAsset.asset as Texture2D;
|
||||
}
|
||||
|
||||
void UnloadBundle()
|
||||
{
|
||||
if (cachedBundle != null)
|
||||
{
|
||||
cachedBundle.Unload(true);
|
||||
cachedBundle = null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 03eab9c6191c5cd4c9613084e817bd29
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,244 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using UnityEngine;
|
||||
using BestHTTP;
|
||||
|
||||
namespace BestHTTP.Examples
|
||||
{
|
||||
public sealed class LargeFileDownloadSample : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// The url of the resource to download
|
||||
/// </summary>
|
||||
const string URL = "https://uk3.testmy.net/dl-102400";
|
||||
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Cached request to be able to abort it
|
||||
/// </summary>
|
||||
HTTPRequest request;
|
||||
|
||||
/// <summary>
|
||||
/// Debug status of the request
|
||||
/// </summary>
|
||||
string status = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Download(processing) progress. Its range is between [0..1]
|
||||
/// </summary>
|
||||
float progress;
|
||||
|
||||
/// <summary>
|
||||
/// The fragment size that we will set to the request
|
||||
/// </summary>
|
||||
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:
|
||||
|
||||
// Set 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"))
|
||||
// Set the range header
|
||||
request.SetRangeHeader(PlayerPrefs.GetInt("DownloadProgress"));
|
||||
else
|
||||
// This is a new request
|
||||
PlayerPrefs.SetInt("DownloadProgress", 0);
|
||||
|
||||
#if !BESTHTTP_DISABLE_CACHING
|
||||
// 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;
|
||||
|
||||
// Set a reasonable high fragment size. Here it is 5 megabytes.
|
||||
request.StreamFragmentSize = fragmentSize;
|
||||
|
||||
// Start Processing the request
|
||||
request.Send();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
void ProcessFragments(List<byte[]> 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();
|
||||
|
||||
// Set the progress to the actually processed bytes
|
||||
progress = PlayerPrefs.GetInt("DownloadProgress") / (float)PlayerPrefs.GetInt("DownloadLength");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 972fc2301f87c9e46bfb5523f2bc5090
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,181 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using UnityEngine;
|
||||
using BestHTTP;
|
||||
|
||||
namespace BestHTTP.Examples
|
||||
{
|
||||
public sealed class TextureDownloadSample : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// The URL of the server that will serve the image resources
|
||||
/// </summary>
|
||||
string BaseURL = GUIHelper.BaseURL + "/images/Demo/";
|
||||
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// The downloadable images
|
||||
/// </summary>
|
||||
string[] Images = new string[9] { "One.png", "Two.png", "Three.png", "Four.png", "Five.png", "Six.png", "Seven.png", "Eight.png", "Nine.png" };
|
||||
|
||||
/// <summary>
|
||||
/// The downloaded images will be stored as textures in this array
|
||||
/// </summary>
|
||||
Texture2D[] Textures = new Texture2D[9];
|
||||
|
||||
#if !BESTHTTP_DISABLE_CACHING
|
||||
/// <summary>
|
||||
/// True if all images are loaded from the local cache instead of the server
|
||||
/// </summary>
|
||||
bool allDownloadedFromLocalCache;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// How many sent requests are finished
|
||||
/// </summary>
|
||||
int finishedCount;
|
||||
|
||||
/// <summary>
|
||||
/// GUI scroll position
|
||||
/// </summary>
|
||||
Vector2 scrollPos;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unity Events
|
||||
|
||||
void Awake()
|
||||
{
|
||||
// Set a well observable value
|
||||
// This is how many concurrent requests can be made to a server
|
||||
HTTPManager.MaxConnectionPerServer = 1;
|
||||
|
||||
// Create placeholder textures
|
||||
for (int i = 0; i < Images.Length; ++i)
|
||||
Textures[i] = new Texture2D(100, 150);
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
// Set back to its defualt value.
|
||||
HTTPManager.MaxConnectionPerServer = 4;
|
||||
}
|
||||
|
||||
void OnGUI()
|
||||
{
|
||||
GUIHelper.DrawArea(GUIHelper.ClientArea, true, () =>
|
||||
{
|
||||
scrollPos = GUILayout.BeginScrollView(scrollPos);
|
||||
|
||||
// Draw out the textures
|
||||
GUILayout.SelectionGrid(0, Textures, 3);
|
||||
|
||||
#if !BESTHTTP_DISABLE_CACHING
|
||||
if (finishedCount == Images.Length && allDownloadedFromLocalCache)
|
||||
GUIHelper.DrawCenteredText("All images loaded from the local cache!");
|
||||
#endif
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Label("Max Connection/Server: ", GUILayout.Width(150));
|
||||
GUILayout.Label(HTTPManager.MaxConnectionPerServer.ToString(), GUILayout.Width(20));
|
||||
HTTPManager.MaxConnectionPerServer = (byte)GUILayout.HorizontalSlider(HTTPManager.MaxConnectionPerServer, 1, 10);
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
if (GUILayout.Button("Start Download"))
|
||||
DownloadImages();
|
||||
|
||||
GUILayout.EndScrollView();
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Helper Functions
|
||||
|
||||
void DownloadImages()
|
||||
{
|
||||
// Set these metadatas to its initial values
|
||||
#if !BESTHTTP_DISABLE_CACHING
|
||||
allDownloadedFromLocalCache = true;
|
||||
#endif
|
||||
finishedCount = 0;
|
||||
|
||||
for (int i = 0; i < Images.Length; ++i)
|
||||
{
|
||||
// Set a blank placeholder texture, overriding previously downloaded texture
|
||||
Textures[i] = new Texture2D(100, 150);
|
||||
|
||||
// Construct the request
|
||||
var request = new HTTPRequest(new Uri(BaseURL + Images[i]), ImageDownloaded);
|
||||
|
||||
// Set the Tag property, we can use it as a general storage bound to the request
|
||||
request.Tag = Textures[i];
|
||||
|
||||
// Send out the request
|
||||
request.Send();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Callback function of the image download http requests
|
||||
/// </summary>
|
||||
void ImageDownloaded(HTTPRequest req, HTTPResponse resp)
|
||||
{
|
||||
// Increase the finished count regardless of the state of our request
|
||||
finishedCount++;
|
||||
|
||||
switch (req.State)
|
||||
{
|
||||
// The request finished without any problem.
|
||||
case HTTPRequestStates.Finished:
|
||||
if (resp.IsSuccess)
|
||||
{
|
||||
// Get the Texture from the Tag property
|
||||
Texture2D tex = req.Tag as Texture2D;
|
||||
|
||||
// Load the texture
|
||||
tex.LoadImage(resp.Data);
|
||||
|
||||
#if !BESTHTTP_DISABLE_CACHING
|
||||
// Update the cache-info variable
|
||||
allDownloadedFromLocalCache = allDownloadedFromLocalCache && resp.IsFromCache;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning(string.Format("Request finished Successfully, but the server sent an error. Status Code: {0}-{1} Message: {2}",
|
||||
resp.StatusCode,
|
||||
resp.Message,
|
||||
resp.DataAsText));
|
||||
}
|
||||
break;
|
||||
|
||||
// The request finished with an unexpected error. The request's Exception property may contain more info about the error.
|
||||
case HTTPRequestStates.Error:
|
||||
Debug.LogError("Request Finished with Error! " + (req.Exception != null ? (req.Exception.Message + "\n" + req.Exception.StackTrace) : "No Exception"));
|
||||
break;
|
||||
|
||||
// The request aborted, initiated by the user.
|
||||
case HTTPRequestStates.Aborted:
|
||||
Debug.LogWarning("Request Aborted!");
|
||||
break;
|
||||
|
||||
// Connecting to the server is timed out.
|
||||
case HTTPRequestStates.ConnectionTimedOut:
|
||||
Debug.LogError("Connection Timed Out!");
|
||||
break;
|
||||
|
||||
// The request didn't finished in the given time.
|
||||
case HTTPRequestStates.TimedOut:
|
||||
Debug.LogError("Processing the request Timed Out!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: af6ffe2bbf96d2b49ba3ef0713511d45
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
222
JNFrame/Assets/Plugins/BestHTTP/Examples/HTTP/UploadStream.cs
Normal file
222
JNFrame/Assets/Plugins/BestHTTP/Examples/HTTP/UploadStream.cs
Normal file
@@ -0,0 +1,222 @@
|
||||
using BestHTTP;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
|
||||
namespace BestHTTP.Examples
|
||||
{
|
||||
public sealed class UploadStream : Stream
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Buffer for reads
|
||||
/// </summary>
|
||||
MemoryStream ReadBuffer = new MemoryStream();
|
||||
|
||||
/// <summary>
|
||||
/// Buffer for writes
|
||||
/// </summary>
|
||||
MemoryStream WriteBuffer = new MemoryStream();
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that we will not write more data to this stream
|
||||
/// </summary>
|
||||
bool noMoreData;
|
||||
|
||||
/// <summary>
|
||||
/// For thread synchronization
|
||||
/// </summary>
|
||||
AutoResetEvent ARE = new AutoResetEvent(false);
|
||||
|
||||
/// <summary>
|
||||
/// For thread synchronization
|
||||
/// </summary>
|
||||
object locker = new object();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Name of this stream for easier debugging
|
||||
/// </summary>
|
||||
public string Name { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// true if we are read all data from the read buffer
|
||||
/// </summary>
|
||||
private bool IsReadBufferEmpty { get { lock (locker) return ReadBuffer.Position == ReadBuffer.Length; } }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public UploadStream(string name)
|
||||
: this()
|
||||
{
|
||||
this.Name = name;
|
||||
}
|
||||
|
||||
public UploadStream()
|
||||
{
|
||||
this.ReadBuffer = new MemoryStream();
|
||||
this.WriteBuffer = new MemoryStream();
|
||||
this.Name = string.Empty;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Stream Implementation
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
// We will not push more data to the write buffer
|
||||
if (noMoreData)
|
||||
{
|
||||
// No data left in the read buffer
|
||||
if (ReadBuffer.Position == ReadBuffer.Length)
|
||||
{
|
||||
// Is there any data in the write buffer? If so, switch the buffers
|
||||
if (WriteBuffer.Length > 0)
|
||||
SwitchBuffers();
|
||||
else
|
||||
{
|
||||
HTTPManager.Logger.Information("UploadStream", string.Format("{0} - Read - End Of Stream", this.Name));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
return ReadBuffer.Read(buffer, offset, count);
|
||||
}
|
||||
|
||||
// There are no more data in the read buffer? Wait for it.
|
||||
if (IsReadBufferEmpty)
|
||||
{
|
||||
ARE.WaitOne();
|
||||
|
||||
lock (locker)
|
||||
if (IsReadBufferEmpty && WriteBuffer.Length > 0)
|
||||
SwitchBuffers();
|
||||
}
|
||||
|
||||
int read = -1;
|
||||
|
||||
lock (locker)
|
||||
read = ReadBuffer.Read(buffer, offset, count);
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (noMoreData)
|
||||
throw new System.ArgumentException("noMoreData already set!");
|
||||
|
||||
lock (locker)
|
||||
{
|
||||
WriteBuffer.Write(buffer, offset, count);
|
||||
|
||||
SwitchBuffers();
|
||||
}
|
||||
|
||||
ARE.Set();
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
Finish();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Dispose Implementation
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
HTTPManager.Logger.Information("UploadStream", string.Format("{0} - Dispose", this.Name));
|
||||
|
||||
ReadBuffer.Dispose();
|
||||
ReadBuffer = null;
|
||||
|
||||
WriteBuffer.Dispose();
|
||||
WriteBuffer = null;
|
||||
|
||||
#if NETFX_CORE
|
||||
ARE.Dispose();
|
||||
#else
|
||||
ARE.Close();
|
||||
#endif
|
||||
ARE = null;
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helper Functions
|
||||
|
||||
public void Finish()
|
||||
{
|
||||
if (noMoreData)
|
||||
throw new System.ArgumentException("noMoreData already set!");
|
||||
|
||||
HTTPManager.Logger.Information("UploadStream", string.Format("{0} - Finish", this.Name));
|
||||
|
||||
noMoreData = true;
|
||||
|
||||
ARE.Set();
|
||||
}
|
||||
|
||||
private bool SwitchBuffers()
|
||||
{
|
||||
// Switch the buffers only when all data are consumed from our read buffer
|
||||
lock (locker)
|
||||
{
|
||||
if (ReadBuffer.Position == ReadBuffer.Length)
|
||||
{
|
||||
// This buffer will be the read buffer, we need to seek back to the beginning
|
||||
WriteBuffer.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
// This will be the write buffer, set the length to zero
|
||||
ReadBuffer.SetLength(0);
|
||||
|
||||
// switch the two buffers
|
||||
MemoryStream tmp = WriteBuffer;
|
||||
WriteBuffer = ReadBuffer;
|
||||
ReadBuffer = tmp;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Not Implemented Functions and Properties
|
||||
|
||||
public override bool CanRead { get { throw new NotImplementedException(); } }
|
||||
public override bool CanSeek { get { throw new NotImplementedException(); } }
|
||||
public override bool CanWrite { get { throw new NotImplementedException(); } }
|
||||
|
||||
public override long Length { get { throw new NotImplementedException(); } }
|
||||
public override long Position { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } }
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a2ab021301a7baf45a80b5a46275a140
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Reference in New Issue
Block a user