You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
442 lines
17 KiB
442 lines
17 KiB
11 months ago
|
using System;
|
||
|
using System.Collections;
|
||
|
using UnityEngine;
|
||
|
|
||
|
#if !UniRxLibrary
|
||
|
using ObservableUnity = UniRx.Observable;
|
||
|
#endif
|
||
|
|
||
|
#if UNITY_2018_3_OR_NEWER
|
||
|
#pragma warning disable CS0618
|
||
|
#endif
|
||
|
|
||
|
namespace UniRx
|
||
|
{
|
||
|
using System.Threading;
|
||
|
#if !(UNITY_METRO || UNITY_WP8) && (UNITY_4_4 || UNITY_4_3 || UNITY_4_2 || UNITY_4_1 || UNITY_4_0_1 || UNITY_4_0 || UNITY_3_5 || UNITY_3_4 || UNITY_3_3 || UNITY_3_2 || UNITY_3_1 || UNITY_3_0_0 || UNITY_3_0 || UNITY_2_6_1 || UNITY_2_6)
|
||
|
// Fallback for Unity versions below 4.5
|
||
|
using Hash = System.Collections.Hashtable;
|
||
|
using HashEntry = System.Collections.DictionaryEntry;
|
||
|
#else
|
||
|
// Unity 4.5 release notes:
|
||
|
// WWW: deprecated 'WWW(string url, byte[] postData, Hashtable headers)',
|
||
|
// use 'public WWW(string url, byte[] postData, Dictionary<string, string> headers)' instead.
|
||
|
using Hash = System.Collections.Generic.Dictionary<string, string>;
|
||
|
using HashEntry = System.Collections.Generic.KeyValuePair<string, string>;
|
||
|
#endif
|
||
|
|
||
|
#if UNITY_2018_3_OR_NEWER
|
||
|
[Obsolete("Use UnityWebRequest, a fully featured replacement which is more efficient and has additional features")]
|
||
|
#endif
|
||
|
public static partial class ObservableWWW
|
||
|
{
|
||
|
public static IObservable<string> Get(string url, Hash headers = null, IProgress<float> progress = null)
|
||
|
{
|
||
|
return ObservableUnity.FromCoroutine<string>((observer, cancellation) => FetchText(new WWW(url, null, (headers ?? new Hash())), observer, progress, cancellation));
|
||
|
}
|
||
|
|
||
|
public static IObservable<byte[]> GetAndGetBytes(string url, Hash headers = null, IProgress<float> progress = null)
|
||
|
{
|
||
|
return ObservableUnity.FromCoroutine<byte[]>((observer, cancellation) => FetchBytes(new WWW(url, null, (headers ?? new Hash())), observer, progress, cancellation));
|
||
|
}
|
||
|
public static IObservable<WWW> GetWWW(string url, Hash headers = null, IProgress<float> progress = null)
|
||
|
{
|
||
|
return ObservableUnity.FromCoroutine<WWW>((observer, cancellation) => Fetch(new WWW(url, null, (headers ?? new Hash())), observer, progress, cancellation));
|
||
|
}
|
||
|
|
||
|
public static IObservable<string> Post(string url, byte[] postData, IProgress<float> progress = null)
|
||
|
{
|
||
|
return ObservableUnity.FromCoroutine<string>((observer, cancellation) => FetchText(new WWW(url, postData), observer, progress, cancellation));
|
||
|
}
|
||
|
|
||
|
public static IObservable<string> Post(string url, byte[] postData, Hash headers, IProgress<float> progress = null)
|
||
|
{
|
||
|
return ObservableUnity.FromCoroutine<string>((observer, cancellation) => FetchText(new WWW(url, postData, headers), observer, progress, cancellation));
|
||
|
}
|
||
|
|
||
|
public static IObservable<string> Post(string url, WWWForm content, IProgress<float> progress = null)
|
||
|
{
|
||
|
return ObservableUnity.FromCoroutine<string>((observer, cancellation) => FetchText(new WWW(url, content), observer, progress, cancellation));
|
||
|
}
|
||
|
|
||
|
public static IObservable<string> Post(string url, WWWForm content, Hash headers, IProgress<float> progress = null)
|
||
|
{
|
||
|
var contentHeaders = content.headers;
|
||
|
return ObservableUnity.FromCoroutine<string>((observer, cancellation) => FetchText(new WWW(url, content.data, MergeHash(contentHeaders, headers)), observer, progress, cancellation));
|
||
|
}
|
||
|
|
||
|
public static IObservable<byte[]> PostAndGetBytes(string url, byte[] postData, IProgress<float> progress = null)
|
||
|
{
|
||
|
return ObservableUnity.FromCoroutine<byte[]>((observer, cancellation) => FetchBytes(new WWW(url, postData), observer, progress, cancellation));
|
||
|
}
|
||
|
|
||
|
public static IObservable<byte[]> PostAndGetBytes(string url, byte[] postData, Hash headers, IProgress<float> progress = null)
|
||
|
{
|
||
|
return ObservableUnity.FromCoroutine<byte[]>((observer, cancellation) => FetchBytes(new WWW(url, postData, headers), observer, progress, cancellation));
|
||
|
}
|
||
|
|
||
|
public static IObservable<byte[]> PostAndGetBytes(string url, WWWForm content, IProgress<float> progress = null)
|
||
|
{
|
||
|
return ObservableUnity.FromCoroutine<byte[]>((observer, cancellation) => FetchBytes(new WWW(url, content), observer, progress, cancellation));
|
||
|
}
|
||
|
|
||
|
public static IObservable<byte[]> PostAndGetBytes(string url, WWWForm content, Hash headers, IProgress<float> progress = null)
|
||
|
{
|
||
|
var contentHeaders = content.headers;
|
||
|
return ObservableUnity.FromCoroutine<byte[]>((observer, cancellation) => FetchBytes(new WWW(url, content.data, MergeHash(contentHeaders, headers)), observer, progress, cancellation));
|
||
|
}
|
||
|
|
||
|
public static IObservable<WWW> PostWWW(string url, byte[] postData, IProgress<float> progress = null)
|
||
|
{
|
||
|
return ObservableUnity.FromCoroutine<WWW>((observer, cancellation) => Fetch(new WWW(url, postData), observer, progress, cancellation));
|
||
|
}
|
||
|
|
||
|
public static IObservable<WWW> PostWWW(string url, byte[] postData, Hash headers, IProgress<float> progress = null)
|
||
|
{
|
||
|
return ObservableUnity.FromCoroutine<WWW>((observer, cancellation) => Fetch(new WWW(url, postData, headers), observer, progress, cancellation));
|
||
|
}
|
||
|
|
||
|
public static IObservable<WWW> PostWWW(string url, WWWForm content, IProgress<float> progress = null)
|
||
|
{
|
||
|
return ObservableUnity.FromCoroutine<WWW>((observer, cancellation) => Fetch(new WWW(url, content), observer, progress, cancellation));
|
||
|
}
|
||
|
|
||
|
public static IObservable<WWW> PostWWW(string url, WWWForm content, Hash headers, IProgress<float> progress = null)
|
||
|
{
|
||
|
var contentHeaders = content.headers;
|
||
|
return ObservableUnity.FromCoroutine<WWW>((observer, cancellation) => Fetch(new WWW(url, content.data, MergeHash(contentHeaders, headers)), observer, progress, cancellation));
|
||
|
}
|
||
|
|
||
|
public static IObservable<AssetBundle> LoadFromCacheOrDownload(string url, int version, IProgress<float> progress = null)
|
||
|
{
|
||
|
return ObservableUnity.FromCoroutine<AssetBundle>((observer, cancellation) => FetchAssetBundle(WWW.LoadFromCacheOrDownload(url, version), observer, progress, cancellation));
|
||
|
}
|
||
|
|
||
|
public static IObservable<AssetBundle> LoadFromCacheOrDownload(string url, int version, uint crc, IProgress<float> progress = null)
|
||
|
{
|
||
|
return ObservableUnity.FromCoroutine<AssetBundle>((observer, cancellation) => FetchAssetBundle(WWW.LoadFromCacheOrDownload(url, version, crc), observer, progress, cancellation));
|
||
|
}
|
||
|
|
||
|
// over Unity5 supports Hash128
|
||
|
#if !(UNITY_4_7 || UNITY_4_6 || UNITY_4_5 || UNITY_4_4 || UNITY_4_3 || UNITY_4_2 || UNITY_4_1 || UNITY_4_0_1 || UNITY_4_0 || UNITY_3_5 || UNITY_3_4 || UNITY_3_3 || UNITY_3_2 || UNITY_3_1 || UNITY_3_0_0 || UNITY_3_0 || UNITY_2_6_1 || UNITY_2_6)
|
||
|
public static IObservable<AssetBundle> LoadFromCacheOrDownload(string url, Hash128 hash128, IProgress<float> progress = null)
|
||
|
{
|
||
|
return ObservableUnity.FromCoroutine<AssetBundle>((observer, cancellation) => FetchAssetBundle(WWW.LoadFromCacheOrDownload(url, hash128), observer, progress, cancellation));
|
||
|
}
|
||
|
|
||
|
public static IObservable<AssetBundle> LoadFromCacheOrDownload(string url, Hash128 hash128, uint crc, IProgress<float> progress = null)
|
||
|
{
|
||
|
return ObservableUnity.FromCoroutine<AssetBundle>((observer, cancellation) => FetchAssetBundle(WWW.LoadFromCacheOrDownload(url, hash128, crc), observer, progress, cancellation));
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// over 4.5, Hash define is Dictionary.
|
||
|
// below Unity 4.5, WWW only supports Hashtable.
|
||
|
// Unity 4.5, 4.6 WWW supports Dictionary and [Obsolete]Hashtable but WWWForm.content is Hashtable.
|
||
|
// Unity 5.0 WWW only supports Dictionary and WWWForm.content is also Dictionary.
|
||
|
#if !(UNITY_METRO || UNITY_WP8) && (UNITY_4_5 || UNITY_4_6 || UNITY_4_7)
|
||
|
static Hash MergeHash(Hashtable wwwFormHeaders, Hash externalHeaders)
|
||
|
{
|
||
|
var newHeaders = new Hash();
|
||
|
foreach (DictionaryEntry item in wwwFormHeaders)
|
||
|
{
|
||
|
newHeaders[item.Key.ToString()] = item.Value.ToString();
|
||
|
}
|
||
|
foreach (HashEntry item in externalHeaders)
|
||
|
{
|
||
|
newHeaders[item.Key] = item.Value;
|
||
|
}
|
||
|
return newHeaders;
|
||
|
}
|
||
|
#else
|
||
|
static Hash MergeHash(Hash wwwFormHeaders, Hash externalHeaders)
|
||
|
{
|
||
|
foreach (HashEntry item in externalHeaders)
|
||
|
{
|
||
|
wwwFormHeaders[item.Key] = item.Value;
|
||
|
}
|
||
|
return wwwFormHeaders;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
static IEnumerator Fetch(WWW www, IObserver<WWW> observer, IProgress<float> reportProgress, CancellationToken cancel)
|
||
|
{
|
||
|
using (www)
|
||
|
{
|
||
|
if (reportProgress != null)
|
||
|
{
|
||
|
while (!www.isDone && !cancel.IsCancellationRequested)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
reportProgress.Report(www.progress);
|
||
|
}
|
||
|
catch (Exception ex)
|
||
|
{
|
||
|
observer.OnError(ex);
|
||
|
yield break;
|
||
|
}
|
||
|
yield return null;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (!www.isDone)
|
||
|
{
|
||
|
yield return www;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (cancel.IsCancellationRequested)
|
||
|
{
|
||
|
yield break;
|
||
|
}
|
||
|
|
||
|
if (reportProgress != null)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
reportProgress.Report(www.progress);
|
||
|
}
|
||
|
catch (Exception ex)
|
||
|
{
|
||
|
observer.OnError(ex);
|
||
|
yield break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!string.IsNullOrEmpty(www.error))
|
||
|
{
|
||
|
observer.OnError(new WWWErrorException(www, www.text));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
observer.OnNext(www);
|
||
|
observer.OnCompleted();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static IEnumerator FetchText(WWW www, IObserver<string> observer, IProgress<float> reportProgress, CancellationToken cancel)
|
||
|
{
|
||
|
using (www)
|
||
|
{
|
||
|
if (reportProgress != null)
|
||
|
{
|
||
|
while (!www.isDone && !cancel.IsCancellationRequested)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
reportProgress.Report(www.progress);
|
||
|
}
|
||
|
catch (Exception ex)
|
||
|
{
|
||
|
observer.OnError(ex);
|
||
|
yield break;
|
||
|
}
|
||
|
yield return null;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (!www.isDone)
|
||
|
{
|
||
|
yield return www;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (cancel.IsCancellationRequested)
|
||
|
{
|
||
|
yield break;
|
||
|
}
|
||
|
|
||
|
if (reportProgress != null)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
reportProgress.Report(www.progress);
|
||
|
}
|
||
|
catch (Exception ex)
|
||
|
{
|
||
|
observer.OnError(ex);
|
||
|
yield break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!string.IsNullOrEmpty(www.error))
|
||
|
{
|
||
|
observer.OnError(new WWWErrorException(www, www.text));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
observer.OnNext(www.text);
|
||
|
observer.OnCompleted();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static IEnumerator FetchBytes(WWW www, IObserver<byte[]> observer, IProgress<float> reportProgress, CancellationToken cancel)
|
||
|
{
|
||
|
using (www)
|
||
|
{
|
||
|
if (reportProgress != null)
|
||
|
{
|
||
|
while (!www.isDone && !cancel.IsCancellationRequested)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
reportProgress.Report(www.progress);
|
||
|
}
|
||
|
catch (Exception ex)
|
||
|
{
|
||
|
observer.OnError(ex);
|
||
|
yield break;
|
||
|
}
|
||
|
yield return null;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (!www.isDone)
|
||
|
{
|
||
|
yield return www;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (cancel.IsCancellationRequested)
|
||
|
{
|
||
|
yield break;
|
||
|
}
|
||
|
|
||
|
if (reportProgress != null)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
reportProgress.Report(www.progress);
|
||
|
}
|
||
|
catch (Exception ex)
|
||
|
{
|
||
|
observer.OnError(ex);
|
||
|
yield break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!string.IsNullOrEmpty(www.error))
|
||
|
{
|
||
|
observer.OnError(new WWWErrorException(www, www.text));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
observer.OnNext(www.bytes);
|
||
|
observer.OnCompleted();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static IEnumerator FetchAssetBundle(WWW www, IObserver<AssetBundle> observer, IProgress<float> reportProgress, CancellationToken cancel)
|
||
|
{
|
||
|
using (www)
|
||
|
{
|
||
|
if (reportProgress != null)
|
||
|
{
|
||
|
while (!www.isDone && !cancel.IsCancellationRequested)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
reportProgress.Report(www.progress);
|
||
|
}
|
||
|
catch (Exception ex)
|
||
|
{
|
||
|
observer.OnError(ex);
|
||
|
yield break;
|
||
|
}
|
||
|
yield return null;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (!www.isDone)
|
||
|
{
|
||
|
yield return www;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (cancel.IsCancellationRequested)
|
||
|
{
|
||
|
yield break;
|
||
|
}
|
||
|
|
||
|
if (reportProgress != null)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
reportProgress.Report(www.progress);
|
||
|
}
|
||
|
catch (Exception ex)
|
||
|
{
|
||
|
observer.OnError(ex);
|
||
|
yield break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!string.IsNullOrEmpty(www.error))
|
||
|
{
|
||
|
observer.OnError(new WWWErrorException(www, ""));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
observer.OnNext(www.assetBundle);
|
||
|
observer.OnCompleted();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public class WWWErrorException : Exception
|
||
|
{
|
||
|
public string RawErrorMessage { get; private set; }
|
||
|
public bool HasResponse { get; private set; }
|
||
|
public string Text { get; private set; }
|
||
|
public System.Net.HttpStatusCode StatusCode { get; private set; }
|
||
|
public System.Collections.Generic.Dictionary<string, string> ResponseHeaders { get; private set; }
|
||
|
public WWW WWW { get; private set; }
|
||
|
|
||
|
// cache the text because if www was disposed, can't access it.
|
||
|
public WWWErrorException(WWW www, string text)
|
||
|
{
|
||
|
this.WWW = www;
|
||
|
this.RawErrorMessage = www.error;
|
||
|
this.ResponseHeaders = www.responseHeaders;
|
||
|
this.HasResponse = false;
|
||
|
this.Text = text;
|
||
|
|
||
|
var splitted = RawErrorMessage.Split(' ', ':');
|
||
|
if (splitted.Length != 0)
|
||
|
{
|
||
|
int statusCode;
|
||
|
if (int.TryParse(splitted[0], out statusCode))
|
||
|
{
|
||
|
this.HasResponse = true;
|
||
|
this.StatusCode = (System.Net.HttpStatusCode)statusCode;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override string ToString()
|
||
|
{
|
||
|
var text = this.Text;
|
||
|
if (string.IsNullOrEmpty(text))
|
||
|
{
|
||
|
return RawErrorMessage;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return RawErrorMessage + " " + text;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#if UNITY_2018_3_OR_NEWER
|
||
|
#pragma warning restore CS0618
|
||
|
#endif
|