提交帧同步案例

This commit is contained in:
PC-20230316NUNE\Administrator
2024-01-26 19:15:07 +08:00
parent 3a345ab966
commit 68c4d5e811
3928 changed files with 463020 additions and 1 deletions

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 56badbd91a344cf49b819809ce60c94a
folderAsset: yes
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

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

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 03eab9c6191c5cd4c9613084e817bd29
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

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

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 972fc2301f87c9e46bfb5523f2bc5090
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

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

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: af6ffe2bbf96d2b49ba3ef0713511d45
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

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

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: a2ab021301a7baf45a80b5a46275a140
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 61ccf02e2b33b974b9bc1bfd84f2610c
folderAsset: yes
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,101 @@
using System;
using UnityEngine;
namespace BestHTTP.Examples
{
public static class GUIHelper
{
public static string BaseURL = "https://besthttpdemosite.azurewebsites.net";
private static GUIStyle centerAlignedLabel;
private static GUIStyle rightAlignedLabel;
public static Rect ClientArea;
private static void Setup()
{
// These has to be called from OnGUI
if (centerAlignedLabel == null)
{
centerAlignedLabel = new GUIStyle(GUI.skin.label);
centerAlignedLabel.alignment = TextAnchor.MiddleCenter;
rightAlignedLabel = new GUIStyle(GUI.skin.label);
rightAlignedLabel.alignment = TextAnchor.MiddleRight;
}
}
public static void DrawArea(Rect area, bool drawHeader, Action action)
{
Setup();
// Draw background
GUI.Box(area, string.Empty);
GUILayout.BeginArea(area);
if (drawHeader)
{
GUIHelper.DrawCenteredText(SampleSelector.SelectedSample.DisplayName);
GUILayout.Space(5);
}
if (action != null)
action();
GUILayout.EndArea();
}
public static void DrawCenteredText(string msg)
{
Setup();
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
GUILayout.Label(msg, centerAlignedLabel);
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
}
public static void DrawRow(string key, string value)
{
Setup();
GUILayout.BeginHorizontal();
GUILayout.Label(key);
GUILayout.FlexibleSpace();
GUILayout.Label(value, rightAlignedLabel);
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
}
}
public class GUIMessageList
{
System.Collections.Generic.List<string> messages = new System.Collections.Generic.List<string>();
Vector2 scrollPos;
public void Draw()
{
Draw(Screen.width, 0);
}
public void Draw(float minWidth, float minHeight)
{
scrollPos = GUILayout.BeginScrollView(scrollPos, false, false, GUILayout.MinHeight(minHeight));
for (int i = 0; i < messages.Count; ++i)
GUILayout.Label(messages[i], GUILayout.MinWidth(minWidth));
GUILayout.EndScrollView();
}
public void Add(string msg)
{
messages.Add(msg);
scrollPos = new Vector2(scrollPos.x, float.MaxValue);
}
public void Clear()
{
messages.Clear();
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: fd560ff6f0fa60844a43a82db1ad03be
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: e1e93ac0ec69bb948b0485b8ae204cee
folderAsset: yes
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,73 @@
#region Header
/**
* IJsonWrapper.cs
* Interface that represents a type capable of handling all kinds of JSON
* data. This is mainly used when mapping objects through JsonMapper, and
* it's implemented by JsonData.
*
* The authors disclaim copyright to this source code. For more details, see
* the COPYING file included with this distribution.
**/
#endregion
using System.Collections;
using System.Collections.Specialized;
namespace LitJson
{
public enum JsonType
{
None,
Object,
Array,
String,
Int,
Long,
Double,
Boolean
}
public interface IOrderedDictionary : IDictionary
{
new IDictionaryEnumerator GetEnumerator();
void Insert(int index, object key, object value);
void RemoveAt(int index);
object this[int index]
{
get;
set;
}
}
public interface IJsonWrapper : IList, IOrderedDictionary
{
bool IsArray { get; }
bool IsBoolean { get; }
bool IsDouble { get; }
bool IsInt { get; }
bool IsLong { get; }
bool IsObject { get; }
bool IsString { get; }
bool GetBoolean ();
double GetDouble ();
int GetInt ();
JsonType GetJsonType ();
long GetLong ();
string GetString ();
void SetBoolean (bool val);
void SetDouble (double val);
void SetInt (int val);
void SetJsonType (JsonType type);
void SetLong (long val);
void SetString (string val);
string ToJson ();
void ToJson (JsonWriter writer);
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: db4954c0960d19d4996b2ad47fdc364d
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: d992e71a7032d1c458a25f6effb6e03d
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,60 @@
#region Header
/**
* JsonException.cs
* Base class throwed by LitJSON when a parsing error occurs.
*
* The authors disclaim copyright to this source code. For more details, see
* the COPYING file included with this distribution.
**/
#endregion
using System;
namespace LitJson
{
public class JsonException : Exception
{
public JsonException () : base ()
{
}
internal JsonException (ParserToken token) :
base (String.Format (
"Invalid token '{0}' in input string", token))
{
}
internal JsonException (ParserToken token,
Exception inner_exception) :
base (String.Format (
"Invalid token '{0}' in input string", token),
inner_exception)
{
}
internal JsonException (int c) :
base (String.Format (
"Invalid character '{0}' in input string", (char) c))
{
}
internal JsonException (int c, Exception inner_exception) :
base (String.Format (
"Invalid character '{0}' in input string", (char) c),
inner_exception)
{
}
public JsonException (string message) : base (message)
{
}
public JsonException (string message, Exception inner_exception) :
base (message, inner_exception)
{
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 2d8be66110036ea4782540091a745448
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: cd3700150c3fb4d4aa8f68e160243328
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,105 @@
#region Header
/**
* JsonMockWrapper.cs
* Mock object implementing IJsonWrapper, to facilitate actions like
* skipping data more efficiently.
*
* The authors disclaim copyright to this source code. For more details, see
* the COPYING file included with this distribution.
**/
#endregion
using System;
using System.Collections;
using System.Collections.Specialized;
namespace LitJson
{
public sealed class JsonMockWrapper : IJsonWrapper
{
public bool IsArray { get { return false; } }
public bool IsBoolean { get { return false; } }
public bool IsDouble { get { return false; } }
public bool IsInt { get { return false; } }
public bool IsLong { get { return false; } }
public bool IsObject { get { return false; } }
public bool IsString { get { return false; } }
public bool GetBoolean () { return false; }
public double GetDouble () { return 0.0; }
public int GetInt () { return 0; }
public JsonType GetJsonType () { return JsonType.None; }
public long GetLong () { return 0L; }
public string GetString () { return ""; }
public void SetBoolean (bool val) {}
public void SetDouble (double val) {}
public void SetInt (int val) {}
public void SetJsonType (JsonType type) {}
public void SetLong (long val) {}
public void SetString (string val) {}
public string ToJson () { return ""; }
public void ToJson (JsonWriter writer) {}
bool IList.IsFixedSize { get { return true; } }
bool IList.IsReadOnly { get { return true; } }
object IList.this[int index] {
get { return null; }
set {}
}
int IList.Add (object value) { return 0; }
void IList.Clear () {}
bool IList.Contains (object value) { return false; }
int IList.IndexOf (object value) { return -1; }
void IList.Insert (int i, object v) {}
void IList.Remove (object value) {}
void IList.RemoveAt (int index) {}
int ICollection.Count { get { return 0; } }
bool ICollection.IsSynchronized { get { return false; } }
object ICollection.SyncRoot { get { return null; } }
void ICollection.CopyTo (Array array, int index) {}
IEnumerator IEnumerable.GetEnumerator () { return null; }
bool IDictionary.IsFixedSize { get { return true; } }
bool IDictionary.IsReadOnly { get { return true; } }
ICollection IDictionary.Keys { get { return null; } }
ICollection IDictionary.Values { get { return null; } }
object IDictionary.this[object key] {
get { return null; }
set {}
}
void IDictionary.Add (object k, object v) {}
void IDictionary.Clear () {}
bool IDictionary.Contains (object key) { return false; }
void IDictionary.Remove (object key) {}
IDictionaryEnumerator IDictionary.GetEnumerator () { return null; }
object IOrderedDictionary.this[int idx] {
get { return null; }
set {}
}
IDictionaryEnumerator IOrderedDictionary.GetEnumerator () {
return null;
}
void IOrderedDictionary.Insert (int i, object k, object v) {}
void IOrderedDictionary.RemoveAt (int i) {}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 21c195443705c59408ba7baf2d2b3175
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,464 @@
#region Header
/**
* JsonReader.cs
* Stream-like access to JSON text.
*
* The authors disclaim copyright to this source code. For more details, see
* the COPYING file included with this distribution.
**/
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace LitJson
{
public enum JsonToken
{
None,
ObjectStart,
PropertyName,
ObjectEnd,
ArrayStart,
ArrayEnd,
Int,
Long,
Double,
String,
Boolean,
Null
}
public sealed class JsonReader
{
#region Fields
private static IDictionary<int, IDictionary<int, int[]>> parse_table;
private Stack<int> automaton_stack;
private int current_input;
private int current_symbol;
private bool end_of_json;
private bool end_of_input;
private Lexer lexer;
private bool parser_in_string;
private bool parser_return;
private bool read_started;
private TextReader reader;
private bool reader_is_owned;
private bool skip_non_members;
private object token_value;
private JsonToken token;
#endregion
#region Public Properties
public bool AllowComments {
get { return lexer.AllowComments; }
set { lexer.AllowComments = value; }
}
public bool AllowSingleQuotedStrings {
get { return lexer.AllowSingleQuotedStrings; }
set { lexer.AllowSingleQuotedStrings = value; }
}
public bool SkipNonMembers {
get { return skip_non_members; }
set { skip_non_members = value; }
}
public bool EndOfInput {
get { return end_of_input; }
}
public bool EndOfJson {
get { return end_of_json; }
}
public JsonToken Token {
get { return token; }
}
public object Value {
get { return token_value; }
}
#endregion
#region Constructors
static JsonReader ()
{
PopulateParseTable ();
}
public JsonReader (string json_text) :
this (new StringReader (json_text), true)
{
}
public JsonReader (TextReader reader) :
this (reader, false)
{
}
private JsonReader (TextReader reader, bool owned)
{
if (reader == null)
throw new ArgumentNullException ("reader");
parser_in_string = false;
parser_return = false;
read_started = false;
automaton_stack = new Stack<int> ();
automaton_stack.Push ((int) ParserToken.End);
automaton_stack.Push ((int) ParserToken.Text);
lexer = new Lexer (reader);
end_of_input = false;
end_of_json = false;
skip_non_members = true;
this.reader = reader;
reader_is_owned = owned;
}
#endregion
#region Static Methods
private static void PopulateParseTable ()
{
// See section A.2. of the manual for details
parse_table = new Dictionary<int, IDictionary<int, int[]>> ();
TableAddRow (ParserToken.Array);
TableAddCol (ParserToken.Array, '[',
'[',
(int) ParserToken.ArrayPrime);
TableAddRow (ParserToken.ArrayPrime);
TableAddCol (ParserToken.ArrayPrime, '"',
(int) ParserToken.Value,
(int) ParserToken.ValueRest,
']');
TableAddCol (ParserToken.ArrayPrime, '[',
(int) ParserToken.Value,
(int) ParserToken.ValueRest,
']');
TableAddCol (ParserToken.ArrayPrime, ']',
']');
TableAddCol (ParserToken.ArrayPrime, '{',
(int) ParserToken.Value,
(int) ParserToken.ValueRest,
']');
TableAddCol (ParserToken.ArrayPrime, (int) ParserToken.Number,
(int) ParserToken.Value,
(int) ParserToken.ValueRest,
']');
TableAddCol (ParserToken.ArrayPrime, (int) ParserToken.True,
(int) ParserToken.Value,
(int) ParserToken.ValueRest,
']');
TableAddCol (ParserToken.ArrayPrime, (int) ParserToken.False,
(int) ParserToken.Value,
(int) ParserToken.ValueRest,
']');
TableAddCol (ParserToken.ArrayPrime, (int) ParserToken.Null,
(int) ParserToken.Value,
(int) ParserToken.ValueRest,
']');
TableAddRow (ParserToken.Object);
TableAddCol (ParserToken.Object, '{',
'{',
(int) ParserToken.ObjectPrime);
TableAddRow (ParserToken.ObjectPrime);
TableAddCol (ParserToken.ObjectPrime, '"',
(int) ParserToken.Pair,
(int) ParserToken.PairRest,
'}');
TableAddCol (ParserToken.ObjectPrime, '}',
'}');
TableAddRow (ParserToken.Pair);
TableAddCol (ParserToken.Pair, '"',
(int) ParserToken.String,
':',
(int) ParserToken.Value);
TableAddRow (ParserToken.PairRest);
TableAddCol (ParserToken.PairRest, ',',
',',
(int) ParserToken.Pair,
(int) ParserToken.PairRest);
TableAddCol (ParserToken.PairRest, '}',
(int) ParserToken.Epsilon);
TableAddRow (ParserToken.String);
TableAddCol (ParserToken.String, '"',
'"',
(int) ParserToken.CharSeq,
'"');
TableAddRow (ParserToken.Text);
TableAddCol (ParserToken.Text, '[',
(int) ParserToken.Array);
TableAddCol (ParserToken.Text, '{',
(int) ParserToken.Object);
TableAddRow (ParserToken.Value);
TableAddCol (ParserToken.Value, '"',
(int) ParserToken.String);
TableAddCol (ParserToken.Value, '[',
(int) ParserToken.Array);
TableAddCol (ParserToken.Value, '{',
(int) ParserToken.Object);
TableAddCol (ParserToken.Value, (int) ParserToken.Number,
(int) ParserToken.Number);
TableAddCol (ParserToken.Value, (int) ParserToken.True,
(int) ParserToken.True);
TableAddCol (ParserToken.Value, (int) ParserToken.False,
(int) ParserToken.False);
TableAddCol (ParserToken.Value, (int) ParserToken.Null,
(int) ParserToken.Null);
TableAddRow (ParserToken.ValueRest);
TableAddCol (ParserToken.ValueRest, ',',
',',
(int) ParserToken.Value,
(int) ParserToken.ValueRest);
TableAddCol (ParserToken.ValueRest, ']',
(int) ParserToken.Epsilon);
}
private static void TableAddCol (ParserToken row, int col,
params int[] symbols)
{
parse_table[(int) row].Add (col, symbols);
}
private static void TableAddRow (ParserToken rule)
{
parse_table.Add ((int) rule, new Dictionary<int, int[]> ());
}
#endregion
#region Private Methods
private void ProcessNumber (string number)
{
if (number.IndexOf ('.') != -1 ||
number.IndexOf ('e') != -1 ||
number.IndexOf ('E') != -1) {
double n_double;
if (Double.TryParse (number, out n_double)) {
token = JsonToken.Double;
token_value = n_double;
return;
}
}
int n_int32;
if (Int32.TryParse (number, out n_int32)) {
token = JsonToken.Int;
token_value = n_int32;
return;
}
long n_int64;
if (Int64.TryParse (number, out n_int64)) {
token = JsonToken.Long;
token_value = n_int64;
return;
}
// Shouldn't happen, but just in case, return something
token = JsonToken.Int;
token_value = 0;
}
private void ProcessSymbol ()
{
if (current_symbol == '[') {
token = JsonToken.ArrayStart;
parser_return = true;
} else if (current_symbol == ']') {
token = JsonToken.ArrayEnd;
parser_return = true;
} else if (current_symbol == '{') {
token = JsonToken.ObjectStart;
parser_return = true;
} else if (current_symbol == '}') {
token = JsonToken.ObjectEnd;
parser_return = true;
} else if (current_symbol == '"') {
if (parser_in_string) {
parser_in_string = false;
parser_return = true;
} else {
if (token == JsonToken.None)
token = JsonToken.String;
parser_in_string = true;
}
} else if (current_symbol == (int) ParserToken.CharSeq) {
token_value = lexer.StringValue;
} else if (current_symbol == (int) ParserToken.False) {
token = JsonToken.Boolean;
token_value = false;
parser_return = true;
} else if (current_symbol == (int) ParserToken.Null) {
token = JsonToken.Null;
parser_return = true;
} else if (current_symbol == (int) ParserToken.Number) {
ProcessNumber (lexer.StringValue);
parser_return = true;
} else if (current_symbol == (int) ParserToken.Pair) {
token = JsonToken.PropertyName;
} else if (current_symbol == (int) ParserToken.True) {
token = JsonToken.Boolean;
token_value = true;
parser_return = true;
}
}
private bool ReadToken ()
{
if (end_of_input)
return false;
lexer.NextToken ();
if (lexer.EndOfInput) {
Close ();
return false;
}
current_input = lexer.Token;
return true;
}
#endregion
public void Close ()
{
if (end_of_input)
return;
end_of_input = true;
end_of_json = true;
if (reader_is_owned)
reader.Dispose();
reader = null;
}
public bool Read ()
{
if (end_of_input)
return false;
if (end_of_json) {
end_of_json = false;
automaton_stack.Clear ();
automaton_stack.Push ((int) ParserToken.End);
automaton_stack.Push ((int) ParserToken.Text);
}
parser_in_string = false;
parser_return = false;
token = JsonToken.None;
token_value = null;
if (! read_started) {
read_started = true;
if (! ReadToken ())
return false;
}
int[] entity_symbols;
while (true) {
if (parser_return) {
if (automaton_stack.Peek () == (int) ParserToken.End)
end_of_json = true;
return true;
}
current_symbol = automaton_stack.Pop ();
ProcessSymbol ();
if (current_symbol == current_input) {
if (! ReadToken ()) {
if (automaton_stack.Peek () != (int) ParserToken.End)
throw new JsonException (
"Input doesn't evaluate to proper JSON text");
if (parser_return)
return true;
return false;
}
continue;
}
try {
entity_symbols =
parse_table[current_symbol][current_input];
} catch (KeyNotFoundException e) {
throw new JsonException ((ParserToken) current_input, e);
}
if (entity_symbols[0] == (int) ParserToken.Epsilon)
continue;
for (int i = entity_symbols.Length - 1; i >= 0; i--)
automaton_stack.Push (entity_symbols[i]);
}
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: f93d78475ddbea54e9f40b76a8813968
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,463 @@
#region Header
/**
* JsonWriter.cs
* Stream-like facility to output JSON text.
*
* The authors disclaim copyright to this source code. For more details, see
* the COPYING file included with this distribution.
**/
#endregion
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;
namespace LitJson
{
internal enum Condition
{
InArray,
InObject,
NotAProperty,
Property,
Value
}
internal class WriterContext
{
public int Count;
public bool InArray;
public bool InObject;
public bool ExpectingValue;
public int Padding;
}
public sealed class JsonWriter
{
#region Fields
private static NumberFormatInfo number_format;
private WriterContext context;
private Stack<WriterContext> ctx_stack;
private bool has_reached_end;
private char[] hex_seq;
private int indentation;
private int indent_value;
private StringBuilder inst_string_builder;
private bool pretty_print;
private bool validate;
private TextWriter writer;
#endregion
#region Properties
public int IndentValue {
get { return indent_value; }
set {
indentation = (indentation / indent_value) * value;
indent_value = value;
}
}
public bool PrettyPrint {
get { return pretty_print; }
set { pretty_print = value; }
}
public TextWriter TextWriter {
get { return writer; }
}
public bool Validate {
get { return validate; }
set { validate = value; }
}
#endregion
#region Constructors
static JsonWriter ()
{
number_format = NumberFormatInfo.InvariantInfo;
}
public JsonWriter ()
{
inst_string_builder = new StringBuilder ();
writer = new StringWriter (inst_string_builder);
Init ();
}
public JsonWriter (StringBuilder sb) :
this (new StringWriter (sb))
{
}
public JsonWriter (TextWriter writer)
{
if (writer == null)
throw new ArgumentNullException ("writer");
this.writer = writer;
Init ();
}
#endregion
#region Private Methods
private void DoValidation (Condition cond)
{
if (! context.ExpectingValue)
context.Count++;
if (! validate)
return;
if (has_reached_end)
throw new JsonException (
"A complete JSON symbol has already been written");
switch (cond) {
case Condition.InArray:
if (! context.InArray)
throw new JsonException (
"Can't close an array here");
break;
case Condition.InObject:
if (! context.InObject || context.ExpectingValue)
throw new JsonException (
"Can't close an object here");
break;
case Condition.NotAProperty:
if (context.InObject && ! context.ExpectingValue)
throw new JsonException (
"Expected a property");
break;
case Condition.Property:
if (! context.InObject || context.ExpectingValue)
throw new JsonException (
"Can't add a property here");
break;
case Condition.Value:
if (! context.InArray &&
(! context.InObject || ! context.ExpectingValue))
throw new JsonException (
"Can't add a value here");
break;
}
}
private void Init ()
{
has_reached_end = false;
hex_seq = new char[4];
indentation = 0;
indent_value = 4;
pretty_print = false;
validate = true;
ctx_stack = new Stack<WriterContext> ();
context = new WriterContext ();
ctx_stack.Push (context);
}
private static void IntToHex (int n, char[] hex)
{
int num;
for (int i = 0; i < 4; i++) {
num = n % 16;
if (num < 10)
hex[3 - i] = (char) ('0' + num);
else
hex[3 - i] = (char) ('A' + (num - 10));
n >>= 4;
}
}
private void Indent ()
{
if (pretty_print)
indentation += indent_value;
}
private void Put (string str)
{
if (pretty_print && ! context.ExpectingValue)
for (int i = 0; i < indentation; i++)
writer.Write (' ');
writer.Write (str);
}
private void PutNewline ()
{
PutNewline (true);
}
private void PutNewline (bool add_comma)
{
if (add_comma && ! context.ExpectingValue &&
context.Count > 1)
writer.Write (',');
if (pretty_print && ! context.ExpectingValue)
writer.Write ('\n');
}
private void PutString (string str)
{
Put (String.Empty);
writer.Write ('"');
int n = str.Length;
for (int i = 0; i < n; i++) {
switch (str[i]) {
case '\n':
writer.Write ("\\n");
continue;
case '\r':
writer.Write ("\\r");
continue;
case '\t':
writer.Write ("\\t");
continue;
case '"':
case '\\':
writer.Write ('\\');
writer.Write (str[i]);
continue;
case '\f':
writer.Write ("\\f");
continue;
case '\b':
writer.Write ("\\b");
continue;
}
if ((int) str[i] >= 32 && (int) str[i] <= 126) {
writer.Write (str[i]);
continue;
}
// Default, turn into a \uXXXX sequence
IntToHex ((int) str[i], hex_seq);
writer.Write ("\\u");
writer.Write (hex_seq);
}
writer.Write ('"');
}
private void Unindent ()
{
if (pretty_print)
indentation -= indent_value;
}
#endregion
public override string ToString ()
{
if (inst_string_builder == null)
return String.Empty;
return inst_string_builder.ToString ();
}
public void Reset ()
{
has_reached_end = false;
ctx_stack.Clear ();
context = new WriterContext ();
ctx_stack.Push (context);
if (inst_string_builder != null)
inst_string_builder.Remove (0, inst_string_builder.Length);
}
public void Write (bool boolean)
{
DoValidation (Condition.Value);
PutNewline ();
Put (boolean ? "true" : "false");
context.ExpectingValue = false;
}
public void Write (decimal number)
{
DoValidation (Condition.Value);
PutNewline ();
Put (Convert.ToString (number, number_format));
context.ExpectingValue = false;
}
public void Write (double number)
{
DoValidation (Condition.Value);
PutNewline ();
string str = Convert.ToString (number, number_format);
Put (str);
if (str.IndexOf ('.') == -1 &&
str.IndexOf ('E') == -1)
writer.Write (".0");
context.ExpectingValue = false;
}
public void Write (int number)
{
DoValidation (Condition.Value);
PutNewline ();
Put (Convert.ToString (number, number_format));
context.ExpectingValue = false;
}
public void Write (long number)
{
DoValidation (Condition.Value);
PutNewline ();
Put (Convert.ToString (number, number_format));
context.ExpectingValue = false;
}
public void Write (string str)
{
DoValidation (Condition.Value);
PutNewline ();
if (str == null)
Put ("null");
else
PutString (str);
context.ExpectingValue = false;
}
//[CLSCompliant(false)]
public void Write (ulong number)
{
DoValidation (Condition.Value);
PutNewline ();
Put (Convert.ToString (number, number_format));
context.ExpectingValue = false;
}
public void WriteArrayEnd ()
{
DoValidation (Condition.InArray);
PutNewline (false);
ctx_stack.Pop ();
if (ctx_stack.Count == 1)
has_reached_end = true;
else {
context = ctx_stack.Peek ();
context.ExpectingValue = false;
}
Unindent ();
Put ("]");
}
public void WriteArrayStart ()
{
DoValidation (Condition.NotAProperty);
PutNewline ();
Put ("[");
context = new WriterContext ();
context.InArray = true;
ctx_stack.Push (context);
Indent ();
}
public void WriteObjectEnd ()
{
DoValidation (Condition.InObject);
PutNewline (false);
ctx_stack.Pop ();
if (ctx_stack.Count == 1)
has_reached_end = true;
else {
context = ctx_stack.Peek ();
context.ExpectingValue = false;
}
Unindent ();
Put ("}");
}
public void WriteObjectStart ()
{
DoValidation (Condition.NotAProperty);
PutNewline ();
Put ("{");
context = new WriterContext ();
context.InObject = true;
ctx_stack.Push (context);
Indent ();
}
public void WritePropertyName (string property_name)
{
DoValidation (Condition.Property);
PutNewline ();
PutString (property_name);
if (pretty_print) {
if (property_name.Length > context.Padding)
context.Padding = property_name.Length;
for (int i = context.Padding - property_name.Length;
i >= 0; i--)
writer.Write (' ');
writer.Write (": ");
} else
writer.Write (':');
context.ExpectingValue = true;
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 902e614ca1244e2478d32eef3bd0d68e
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,912 @@
#region Header
/**
* Lexer.cs
* JSON lexer implementation based on a finite state machine.
*
* The authors disclaim copyright to this source code. For more details, see
* the COPYING file included with this distribution.
**/
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace LitJson
{
internal sealed class FsmContext
{
public bool Return;
public int NextState;
public Lexer L;
public int StateStack;
}
internal sealed class Lexer
{
#region Fields
private delegate bool StateHandler (FsmContext ctx);
private static int[] fsm_return_table;
private static StateHandler[] fsm_handler_table;
private bool allow_comments;
private bool allow_single_quoted_strings;
private bool end_of_input;
private FsmContext fsm_context;
private int input_buffer;
private int input_char;
private TextReader reader;
private int state;
private StringBuilder string_buffer;
private string string_value;
private int token;
private int unichar;
#endregion
#region Properties
public bool AllowComments {
get { return allow_comments; }
set { allow_comments = value; }
}
public bool AllowSingleQuotedStrings {
get { return allow_single_quoted_strings; }
set { allow_single_quoted_strings = value; }
}
public bool EndOfInput {
get { return end_of_input; }
}
public int Token {
get { return token; }
}
public string StringValue {
get { return string_value; }
}
#endregion
#region Constructors
static Lexer ()
{
PopulateFsmTables ();
}
public Lexer (TextReader reader)
{
allow_comments = true;
allow_single_quoted_strings = true;
input_buffer = 0;
string_buffer = new StringBuilder (128);
state = 1;
end_of_input = false;
this.reader = reader;
fsm_context = new FsmContext ();
fsm_context.L = this;
}
#endregion
#region Static Methods
private static int HexValue (int digit)
{
switch (digit) {
case 'a':
case 'A':
return 10;
case 'b':
case 'B':
return 11;
case 'c':
case 'C':
return 12;
case 'd':
case 'D':
return 13;
case 'e':
case 'E':
return 14;
case 'f':
case 'F':
return 15;
default:
return digit - '0';
}
}
private static void PopulateFsmTables ()
{
// See section A.1. of the manual for details of the finite
// state machine.
fsm_handler_table = new StateHandler[28] {
State1,
State2,
State3,
State4,
State5,
State6,
State7,
State8,
State9,
State10,
State11,
State12,
State13,
State14,
State15,
State16,
State17,
State18,
State19,
State20,
State21,
State22,
State23,
State24,
State25,
State26,
State27,
State28
};
fsm_return_table = new int[28] {
(int) ParserToken.Char,
0,
(int) ParserToken.Number,
(int) ParserToken.Number,
0,
(int) ParserToken.Number,
0,
(int) ParserToken.Number,
0,
0,
(int) ParserToken.True,
0,
0,
0,
(int) ParserToken.False,
0,
0,
(int) ParserToken.Null,
(int) ParserToken.CharSeq,
(int) ParserToken.Char,
0,
0,
(int) ParserToken.CharSeq,
(int) ParserToken.Char,
0,
0,
0,
0
};
}
private static char ProcessEscChar (int esc_char)
{
switch (esc_char) {
case '"':
case '\'':
case '\\':
case '/':
return Convert.ToChar (esc_char);
case 'n':
return '\n';
case 't':
return '\t';
case 'r':
return '\r';
case 'b':
return '\b';
case 'f':
return '\f';
default:
// Unreachable
return '?';
}
}
private static bool State1 (FsmContext ctx)
{
while (ctx.L.GetChar ()) {
if (ctx.L.input_char == ' ' ||
ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r')
continue;
if (ctx.L.input_char >= '1' && ctx.L.input_char <= '9') {
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
ctx.NextState = 3;
return true;
}
switch (ctx.L.input_char) {
case '"':
ctx.NextState = 19;
ctx.Return = true;
return true;
case ',':
case ':':
case '[':
case ']':
case '{':
case '}':
ctx.NextState = 1;
ctx.Return = true;
return true;
case '-':
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
ctx.NextState = 2;
return true;
case '0':
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
ctx.NextState = 4;
return true;
case 'f':
ctx.NextState = 12;
return true;
case 'n':
ctx.NextState = 16;
return true;
case 't':
ctx.NextState = 9;
return true;
case '\'':
if (! ctx.L.allow_single_quoted_strings)
return false;
ctx.L.input_char = '"';
ctx.NextState = 23;
ctx.Return = true;
return true;
case '/':
if (! ctx.L.allow_comments)
return false;
ctx.NextState = 25;
return true;
default:
return false;
}
}
return true;
}
private static bool State2 (FsmContext ctx)
{
ctx.L.GetChar ();
if (ctx.L.input_char >= '1' && ctx.L.input_char<= '9') {
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
ctx.NextState = 3;
return true;
}
switch (ctx.L.input_char) {
case '0':
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
ctx.NextState = 4;
return true;
default:
return false;
}
}
private static bool State3 (FsmContext ctx)
{
while (ctx.L.GetChar ()) {
if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9') {
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
continue;
}
if (ctx.L.input_char == ' ' ||
ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r') {
ctx.Return = true;
ctx.NextState = 1;
return true;
}
switch (ctx.L.input_char) {
case ',':
case ']':
case '}':
ctx.L.UngetChar ();
ctx.Return = true;
ctx.NextState = 1;
return true;
case '.':
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
ctx.NextState = 5;
return true;
case 'e':
case 'E':
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
ctx.NextState = 7;
return true;
default:
return false;
}
}
return true;
}
private static bool State4 (FsmContext ctx)
{
ctx.L.GetChar ();
if (ctx.L.input_char == ' ' ||
ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r') {
ctx.Return = true;
ctx.NextState = 1;
return true;
}
switch (ctx.L.input_char) {
case ',':
case ']':
case '}':
ctx.L.UngetChar ();
ctx.Return = true;
ctx.NextState = 1;
return true;
case '.':
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
ctx.NextState = 5;
return true;
case 'e':
case 'E':
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
ctx.NextState = 7;
return true;
default:
return false;
}
}
private static bool State5 (FsmContext ctx)
{
ctx.L.GetChar ();
if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9') {
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
ctx.NextState = 6;
return true;
}
return false;
}
private static bool State6 (FsmContext ctx)
{
while (ctx.L.GetChar ()) {
if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9') {
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
continue;
}
if (ctx.L.input_char == ' ' ||
ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r') {
ctx.Return = true;
ctx.NextState = 1;
return true;
}
switch (ctx.L.input_char) {
case ',':
case ']':
case '}':
ctx.L.UngetChar ();
ctx.Return = true;
ctx.NextState = 1;
return true;
case 'e':
case 'E':
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
ctx.NextState = 7;
return true;
default:
return false;
}
}
return true;
}
private static bool State7 (FsmContext ctx)
{
ctx.L.GetChar ();
if (ctx.L.input_char >= '0' && ctx.L.input_char<= '9') {
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
ctx.NextState = 8;
return true;
}
switch (ctx.L.input_char) {
case '+':
case '-':
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
ctx.NextState = 8;
return true;
default:
return false;
}
}
private static bool State8 (FsmContext ctx)
{
while (ctx.L.GetChar ()) {
if (ctx.L.input_char >= '0' && ctx.L.input_char<= '9') {
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
continue;
}
if (ctx.L.input_char == ' ' ||
ctx.L.input_char >= '\t' && ctx.L.input_char<= '\r') {
ctx.Return = true;
ctx.NextState = 1;
return true;
}
switch (ctx.L.input_char) {
case ',':
case ']':
case '}':
ctx.L.UngetChar ();
ctx.Return = true;
ctx.NextState = 1;
return true;
default:
return false;
}
}
return true;
}
private static bool State9 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case 'r':
ctx.NextState = 10;
return true;
default:
return false;
}
}
private static bool State10 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case 'u':
ctx.NextState = 11;
return true;
default:
return false;
}
}
private static bool State11 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case 'e':
ctx.Return = true;
ctx.NextState = 1;
return true;
default:
return false;
}
}
private static bool State12 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case 'a':
ctx.NextState = 13;
return true;
default:
return false;
}
}
private static bool State13 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case 'l':
ctx.NextState = 14;
return true;
default:
return false;
}
}
private static bool State14 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case 's':
ctx.NextState = 15;
return true;
default:
return false;
}
}
private static bool State15 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case 'e':
ctx.Return = true;
ctx.NextState = 1;
return true;
default:
return false;
}
}
private static bool State16 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case 'u':
ctx.NextState = 17;
return true;
default:
return false;
}
}
private static bool State17 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case 'l':
ctx.NextState = 18;
return true;
default:
return false;
}
}
private static bool State18 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case 'l':
ctx.Return = true;
ctx.NextState = 1;
return true;
default:
return false;
}
}
private static bool State19 (FsmContext ctx)
{
while (ctx.L.GetChar ()) {
switch (ctx.L.input_char) {
case '"':
ctx.L.UngetChar ();
ctx.Return = true;
ctx.NextState = 20;
return true;
case '\\':
ctx.StateStack = 19;
ctx.NextState = 21;
return true;
default:
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
continue;
}
}
return true;
}
private static bool State20 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case '"':
ctx.Return = true;
ctx.NextState = 1;
return true;
default:
return false;
}
}
private static bool State21 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case 'u':
ctx.NextState = 22;
return true;
case '"':
case '\'':
case '/':
case '\\':
case 'b':
case 'f':
case 'n':
case 'r':
case 't':
ctx.L.string_buffer.Append (
ProcessEscChar (ctx.L.input_char));
ctx.NextState = ctx.StateStack;
return true;
default:
return false;
}
}
private static bool State22 (FsmContext ctx)
{
int counter = 0;
int mult = 4096;
ctx.L.unichar = 0;
while (ctx.L.GetChar ()) {
if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9' ||
ctx.L.input_char >= 'A' && ctx.L.input_char <= 'F' ||
ctx.L.input_char >= 'a' && ctx.L.input_char <= 'f') {
ctx.L.unichar += HexValue (ctx.L.input_char) * mult;
counter++;
mult /= 16;
if (counter == 4) {
ctx.L.string_buffer.Append (
Convert.ToChar (ctx.L.unichar));
ctx.NextState = ctx.StateStack;
return true;
}
continue;
}
return false;
}
return true;
}
private static bool State23 (FsmContext ctx)
{
while (ctx.L.GetChar ()) {
switch (ctx.L.input_char) {
case '\'':
ctx.L.UngetChar ();
ctx.Return = true;
ctx.NextState = 24;
return true;
case '\\':
ctx.StateStack = 23;
ctx.NextState = 21;
return true;
default:
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
continue;
}
}
return true;
}
private static bool State24 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case '\'':
ctx.L.input_char = '"';
ctx.Return = true;
ctx.NextState = 1;
return true;
default:
return false;
}
}
private static bool State25 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case '*':
ctx.NextState = 27;
return true;
case '/':
ctx.NextState = 26;
return true;
default:
return false;
}
}
private static bool State26 (FsmContext ctx)
{
while (ctx.L.GetChar ()) {
if (ctx.L.input_char == '\n') {
ctx.NextState = 1;
return true;
}
}
return true;
}
private static bool State27 (FsmContext ctx)
{
while (ctx.L.GetChar ()) {
if (ctx.L.input_char == '*') {
ctx.NextState = 28;
return true;
}
}
return true;
}
private static bool State28 (FsmContext ctx)
{
while (ctx.L.GetChar ()) {
if (ctx.L.input_char == '*')
continue;
if (ctx.L.input_char == '/') {
ctx.NextState = 1;
return true;
}
ctx.NextState = 27;
return true;
}
return true;
}
#endregion
private bool GetChar ()
{
if ((input_char = NextChar ()) != -1)
return true;
end_of_input = true;
return false;
}
private int NextChar ()
{
if (input_buffer != 0) {
int tmp = input_buffer;
input_buffer = 0;
return tmp;
}
return reader.Read ();
}
public bool NextToken ()
{
StateHandler handler;
fsm_context.Return = false;
while (true) {
handler = fsm_handler_table[state - 1];
if (! handler (fsm_context))
throw new JsonException (input_char);
if (end_of_input)
return false;
if (fsm_context.Return) {
string_value = string_buffer.ToString ();
string_buffer.Remove (0, string_buffer.Length);
token = fsm_return_table[state - 1];
if (token == (int) ParserToken.Char)
token = input_char;
state = fsm_context.NextState;
return true;
}
state = fsm_context.NextState;
}
}
private void UngetChar ()
{
input_buffer = input_char;
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 906778e065bdcac499e4d8a01871e594
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,44 @@
#region Header
/**
* ParserToken.cs
* Internal representation of the tokens used by the lexer and the parser.
*
* The authors disclaim copyright to this source code. For more details, see
* the COPYING file included with this distribution.
**/
#endregion
namespace LitJson
{
internal enum ParserToken
{
// Lexer tokens (see section A.1.1. of the manual)
None = System.Char.MaxValue + 1,
Number,
True,
False,
Null,
CharSeq,
// Single char
Char,
// Parser Rules (see section A.2.1 of the manual)
Text,
Object,
ObjectPrime,
Pair,
PairRest,
Array,
ArrayPrime,
Value,
ValueRest,
String,
// End of input
End,
// The empty rule
Epsilon
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: e0f6927815038254080d13c1ab81506b
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: e4b189b8db53fae40b63e2563cc658ba
folderAsset: yes
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,98 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using BestHTTP;
#if !BESTHTTP_DISABLE_CACHING
using BestHTTP.Caching;
#endif
namespace BestHTTP.Examples
{
public sealed class CacheMaintenanceSample : MonoBehaviour
{
/// <summary>
/// An enum for better readability
/// </summary>
enum DeleteOlderTypes
{
Days,
Hours,
Mins,
Secs
};
#region Private Fields
#if !BESTHTTP_DISABLE_CACHING
/// <summary>
/// What methode to call on the TimeSpan
/// </summary>
DeleteOlderTypes deleteOlderType = DeleteOlderTypes.Secs;
/// <summary>
/// The value for the TimeSpan.
/// </summary>
int value = 10;
/// <summary>
/// What's our maximum cache size
/// </summary>
int maxCacheSize = 5 * 1024 * 1024;
#endif
#endregion
#region Unity Events
void OnGUI()
{
GUIHelper.DrawArea(GUIHelper.ClientArea, true, () =>
{
#if !BESTHTTP_DISABLE_CACHING
GUILayout.BeginHorizontal();
GUILayout.Label("Delete cached entities older then");
GUILayout.Label(value.ToString(), GUILayout.MinWidth(50));
value = (int)GUILayout.HorizontalSlider(value, 1, 60, GUILayout.MinWidth(100));
GUILayout.Space(10);
deleteOlderType = (DeleteOlderTypes)(int)GUILayout.SelectionGrid((int)deleteOlderType, new string[] { "Days", "Hours", "Mins", "Secs" }, 4);
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
GUILayout.Space(10);
GUILayout.BeginHorizontal();
GUILayout.Label("Max Cache Size (bytes): ", GUILayout.Width(150));
GUILayout.Label(maxCacheSize.ToString("N0"), GUILayout.Width(70));
maxCacheSize = (int)GUILayout.HorizontalSlider(maxCacheSize, 1024, 10 * 1024 * 1024);
GUILayout.EndHorizontal();
GUILayout.Space(10);
if (GUILayout.Button("Maintenance"))
{
TimeSpan deleteOlder = TimeSpan.FromDays(14);
switch (deleteOlderType)
{
case DeleteOlderTypes.Days: deleteOlder = TimeSpan.FromDays(value); break;
case DeleteOlderTypes.Hours: deleteOlder = TimeSpan.FromHours(value); break;
case DeleteOlderTypes.Mins: deleteOlder = TimeSpan.FromMinutes(value); break;
case DeleteOlderTypes.Secs: deleteOlder = TimeSpan.FromSeconds(value); break;
}
// Call the BeginMaintainence function. It will run on a thread to do not block the main thread.
HTTPCacheService.BeginMaintainence(new HTTPCacheMaintananceParams(deleteOlder, (ulong)maxCacheSize));
}
#endif
});
}
#endregion
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 502d4f4ff21e26a4d8d19e12ba63e376
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,298 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using BestHTTP;
using BestHTTP.Statistics;
using BestHTTP.Examples;
namespace BestHTTP.Examples
{
/// <summary>
/// A class to describe an Example and store it's metadata.
/// </summary>
public sealed class SampleDescriptor
{
public bool IsLabel { get; set; }
public Type Type { get; set; }
public string DisplayName { get; set; }
public string Description { get; set; }
public bool IsSelected { get; set; }
public GameObject UnityObject { get; set; }
public bool IsRunning { get { return UnityObject != null; } }
public SampleDescriptor(Type type, string displayName, string description)
{
this.Type = type;
this.DisplayName = displayName;
this.Description = description;
}
public void CreateUnityObject()
{
if (UnityObject != null)
return;
UnityObject = new GameObject(DisplayName);
UnityObject.AddComponent(Type);
}
public void DestroyUnityObject()
{
if (UnityObject != null)
{
UnityEngine.Object.Destroy(UnityObject);
UnityObject = null;
}
}
}
public class SampleSelector : MonoBehaviour
{
public const int statisticsHeight = 160;
List<SampleDescriptor> Samples = new List<SampleDescriptor>();
public static SampleDescriptor SelectedSample;
Vector2 scrollPos;
void Awake()
{
Application.runInBackground = true;
HTTPManager.Logger.Level = BestHTTP.Logger.Loglevels.All;
#if UNITY_SAMSUNGTV
SamsungTV.touchPadMode = SamsungTV.TouchPadMode.Mouse;
// Create a red 'cursor' to see where we are pointing to
Texture2D tex = new Texture2D(8, 8, TextureFormat.RGB24, false);
for (int i = 0; i < tex.width; ++i)
for (int cv = 0; cv < tex.height; ++cv)
tex.SetPixel(i, cv, Color.red);
tex.Apply(false, true);
Cursor.SetCursor(tex, Vector2.zero, CursorMode.Auto);
#endif
Samples.Add(new SampleDescriptor(null, "HTTP Samples", string.Empty) { IsLabel = true });
Samples.Add(new SampleDescriptor(typeof(TextureDownloadSample), "Texture Download", "With HTTPManager.MaxConnectionPerServer you can control how many requests can be processed per server parallel.\n\nFeatures demoed in this example:\n-Parallel requests to the same server\n-Controlling the parallelization\n-Automatic Caching\n-Create a Texture2D from the downloaded data"));
Samples.Add(new SampleDescriptor(typeof(AssetBundleSample), "AssetBundle Download", "A small example that shows a possible way to download an AssetBundle and load a resource from it.\n\nFeatures demoed in this example:\n-Using HTTPRequest without a callback\n-Using HTTPRequest in a Coroutine\n-Loading an AssetBundle from the downloaded bytes\n-Automatic Caching"));
#if !UNITY_WEBGL || UNITY_EDITOR
Samples.Add(new SampleDescriptor(typeof(LargeFileDownloadSample), "Large File Download", "This example demonstrates how you can download a (large) file and continue the download after the connection is aborted.\n\nFeatures demoed in this example:\n-Setting up a streamed download\n-How to access the downloaded data while the download is in progress\n-Setting the HTTPRequest's StreamFragmentSize to controll the frequency and size of the fragments\n-How to use the SetRangeHeader to continue a previously disconnected download\n-How to disable the local, automatic caching"));
#endif
#if !BESTHTTP_DISABLE_WEBSOCKET
Samples.Add(new SampleDescriptor(null, "WebSocket Samples", string.Empty) { IsLabel = true });
Samples.Add(new SampleDescriptor(typeof(WebSocketSample), "Echo", "A WebSocket demonstration that connects to a WebSocket echo service.\n\nFeatures demoed in this example:\n-Basic usage of the WebSocket class"));
#endif
#if !BESTHTTP_DISABLE_SOCKETIO
Samples.Add(new SampleDescriptor(null, "Socket.IO Samples", string.Empty) { IsLabel = true });
Samples.Add(new SampleDescriptor(typeof(SocketIOChatSample), "Chat", "This example uses the Socket.IO implementation to connect to the official Chat demo server(http://chat.socket.io/).\n\nFeatures demoed in this example:\n-Instantiating and setting up a SocketManager to connect to a Socket.IO server\n-Changing SocketOptions property\n-Subscribing to Socket.IO events\n-Sending custom events to the server"));
#if !UNITY_WEBGL || UNITY_EDITOR
Samples.Add(new SampleDescriptor(typeof(SocketIOWePlaySample), "WePlay", "This example uses the Socket.IO implementation to connect to the official WePlay demo server(http://weplay.io/).\n\nFeatures demoed in this example:\n-Instantiating and setting up a SocketManager to connect to a Socket.IO server\n-Subscribing to Socket.IO events\n-Receiving binary data\n-How to load a texture from the received binary data\n-How to disable payload decoding for fine tune for some speed\n-Sending custom events to the server"));
#endif
#endif
#if !BESTHTTP_DISABLE_SIGNALR_CORE
Samples.Add(new SampleDescriptor(null, "SignalR Core Samples", string.Empty) { IsLabel = true });
Samples.Add(new SampleDescriptor(typeof(TestHubExample), "Hub Sample", "This sample demonstrates most of the functionalities of the SignalR protocol:\n-How to set up HubConnection to connect to the server\n-Subscribing to server-callable function\n-Calling client-callable function on the server\n-Calling and handling streaming\n"));
Samples.Add(new SampleDescriptor(typeof(HubWithAuthorizationSample), "Hub Authentication Sample", "This sample demonstrates the default access token authentication. The server sends a JWT token to the client with a new url. The client will connect to that new url and sends the JWT token.\n"));
Samples.Add(new SampleDescriptor(typeof(HubWithPreAuthorizationSample), "Hub Pre-Authentication Sample", "This sample demonstrates manual authentication.\n"));
Samples.Add(new SampleDescriptor(typeof(RedirectSample), "Hub Redirect Sample", "This sample demonstrates how the plugin handles redirection through the SignalR Core negotiation data.\n"));
#endif
#if (!BESTHTTP_DISABLE_SIGNALR && !UNITY_WEBGL) || UNITY_EDITOR
Samples.Add(new SampleDescriptor(null, "SignalR Samples", string.Empty) { IsLabel = true });
Samples.Add(new SampleDescriptor(typeof(SimpleStreamingSample), "Simple Streaming", "A very simple example of a background thread that broadcasts the server time to all connected clients every two seconds.\n\nFeatures demoed in this example:\n-Subscribing and handling non-hub messages"));
Samples.Add(new SampleDescriptor(typeof(ConnectionAPISample), "Connection API", "Demonstrates all features of the lower-level connection API including starting and stopping, sending and receiving messages, and managing groups.\n\nFeatures demoed in this example:\n-Instantiating and setting up a SignalR Connection to connect to a SignalR server\n-Changing the default Json encoder\n-Subscribing to state changes\n-Receiving and handling of non-hub messages\n-Sending non-hub messages\n-Managing groups"));
Samples.Add(new SampleDescriptor(typeof(ConnectionStatusSample), "Connection Status", "Demonstrates how to handle the events that are raised when connections connect, reconnect and disconnect from the Hub API.\n\nFeatures demoed in this example:\n-Connecting to a Hub\n-Setting up a callback for Hub events\n-Handling server-sent method call requests\n-Calling a Hub-method on the server-side\n-Opening and closing the SignalR Connection"));
Samples.Add(new SampleDescriptor(typeof(DemoHubSample), "Demo Hub", "A contrived example that exploits every feature of the Hub API.\n\nFeatures demoed in this example:\n-Creating and using wrapper Hub classes to encapsulate hub functions and events\n-Handling long running server-side functions by handling progress messages\n-Groups\n-Handling server-side functions with return value\n-Handling server-side functions throwing Exceptions\n-Calling server-side functions with complex type parameters\n-Calling server-side functions with array parameters\n-Calling overloaded server-side functions\n-Changing Hub states\n-Receiving and handling hub state changes\n-Calling server-side functions implemented in VB .NET"));
#if !UNITY_WEBGL || UNITY_EDITOR
Samples.Add(new SampleDescriptor(typeof(AuthenticationSample), "Authentication", "Demonstrates how to use the authorization features of the Hub API to restrict certain Hubs and methods to specific users.\n\nFeatures demoed in this example:\n-Creating and using wrapper Hub classes to encapsulate hub functions and events\n-Create and use a Header-based authenticator to access protected APIs\n-SignalR over HTTPS"));
#endif
#endif
#if !BESTHTTP_DISABLE_CACHING
Samples.Add(new SampleDescriptor(null, "Plugin Samples", string.Empty) { IsLabel = true });
Samples.Add(new SampleDescriptor(typeof(CacheMaintenanceSample), "Cache Maintenance", "With this demo you can see how you can use the HTTPCacheService's BeginMaintainence function to delete too old cached entities and keep the cache size under a specified value.\n\nFeatures demoed in this example:\n-How to set up a HTTPCacheMaintananceParams\n-How to call the BeginMaintainence function"));
#endif
SelectedSample = Samples[1];
}
void Update()
{
GUIHelper.ClientArea = new Rect(0, SampleSelector.statisticsHeight + 5, Screen.width, Screen.height - SampleSelector.statisticsHeight - 50);
if (Input.GetKeyDown(KeyCode.Escape))
{
if (SelectedSample != null && SelectedSample.IsRunning)
SelectedSample.DestroyUnityObject();
else
Application.Quit();
}
if (Input.GetKeyDown(KeyCode.KeypadEnter) || Input.GetKeyDown(KeyCode.Return))
{
if (SelectedSample != null && !SelectedSample.IsRunning)
SelectedSample.CreateUnityObject();
}
}
void OnGUI()
{
var stats = HTTPManager.GetGeneralStatistics(StatisticsQueryFlags.All);
// Connection statistics
GUIHelper.DrawArea(new Rect(0, 0, Screen.width / 3, statisticsHeight), false, () =>
{
// Header
GUIHelper.DrawCenteredText("Connections");
GUILayout.Space(5);
GUIHelper.DrawRow("Sum:", stats.Connections.ToString());
GUIHelper.DrawRow("Active:", stats.ActiveConnections.ToString());
GUIHelper.DrawRow("Free:", stats.FreeConnections.ToString());
GUIHelper.DrawRow("Recycled:", stats.RecycledConnections.ToString());
GUIHelper.DrawRow("Requests in queue:", stats.RequestsInQueue.ToString());
});
// Cache statistics
GUIHelper.DrawArea(new Rect(Screen.width / 3, 0, Screen.width / 3, statisticsHeight), false, () =>
{
GUIHelper.DrawCenteredText("Cache");
#if !BESTHTTP_DISABLE_CACHING
if (!BestHTTP.Caching.HTTPCacheService.IsSupported)
{
#endif
GUI.color = Color.yellow;
GUIHelper.DrawCenteredText("Disabled in WebPlayer, WebGL & Samsung Smart TV Builds!");
GUI.color = Color.white;
#if !BESTHTTP_DISABLE_CACHING
}
else
{
GUILayout.Space(5);
GUIHelper.DrawRow("Cached entities:", stats.CacheEntityCount.ToString());
GUIHelper.DrawRow("Sum Size (bytes): ", stats.CacheSize.ToString("N0"));
GUILayout.BeginVertical();
GUILayout.FlexibleSpace();
if (GUILayout.Button("Clear Cache"))
BestHTTP.Caching.HTTPCacheService.BeginClear();
GUILayout.EndVertical();
}
#endif
});
// Cookie statistics
GUIHelper.DrawArea(new Rect((Screen.width / 3) * 2, 0, Screen.width / 3, statisticsHeight), false, () =>
{
GUIHelper.DrawCenteredText("Cookies");
#if !BESTHTTP_DISABLE_COOKIES
if (!BestHTTP.Cookies.CookieJar.IsSavingSupported)
{
#endif
GUI.color = Color.yellow;
GUIHelper.DrawCenteredText("Saving and loading from disk is disabled in WebPlayer, WebGL & Samsung Smart TV Builds!");
GUI.color = Color.white;
#if !BESTHTTP_DISABLE_COOKIES
}
else
{
GUILayout.Space(5);
GUIHelper.DrawRow("Cookies:", stats.CookieCount.ToString());
GUIHelper.DrawRow("Estimated size (bytes):", stats.CookieJarSize.ToString("N0"));
GUILayout.BeginVertical();
GUILayout.FlexibleSpace();
if (GUILayout.Button("Clear Cookies"))
BestHTTP.Cookies.CookieJar.Clear();
GUILayout.EndVertical();
}
#endif
});
if (SelectedSample == null || (SelectedSample != null && !SelectedSample.IsRunning))
{
// Draw the list of samples
GUIHelper.DrawArea(new Rect(0, statisticsHeight + 5, SelectedSample == null ? Screen.width : Screen.width / 3, Screen.height - statisticsHeight - 5), false, () =>
{
scrollPos = GUILayout.BeginScrollView(scrollPos);
for (int i = 0; i < Samples.Count; ++i)
DrawSample(Samples[i]);
GUILayout.EndScrollView();
});
if (SelectedSample != null)
DrawSampleDetails(SelectedSample);
}
else if (SelectedSample != null && SelectedSample.IsRunning)
{
GUILayout.BeginArea(new Rect(0, Screen.height - 50, Screen.width, 50), string.Empty);
GUILayout.FlexibleSpace();
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
GUILayout.BeginVertical();
GUILayout.FlexibleSpace();
if (GUILayout.Button("Back", GUILayout.MinWidth(100)))
SelectedSample.DestroyUnityObject();
GUILayout.FlexibleSpace();
GUILayout.EndVertical();
GUILayout.EndHorizontal();
GUILayout.EndArea();
}
}
private void DrawSample(SampleDescriptor sample)
{
if (sample.IsLabel)
{
GUILayout.Space(15);
GUIHelper.DrawCenteredText(sample.DisplayName);
GUILayout.Space(5);
}
else if (GUILayout.Button(sample.DisplayName))
{
sample.IsSelected = true;
if (SelectedSample != null)
SelectedSample.IsSelected = false;
SelectedSample = sample;
}
}
private void DrawSampleDetails(SampleDescriptor sample)
{
Rect area = new Rect(Screen.width / 3, statisticsHeight + 5, (Screen.width / 3) * 2, Screen.height - statisticsHeight - 5);
GUI.Box(area, string.Empty);
GUILayout.BeginArea(area);
GUILayout.BeginVertical();
GUIHelper.DrawCenteredText(sample.DisplayName);
GUILayout.Space(5);
GUILayout.Label(sample.Description);
GUILayout.FlexibleSpace();
if (GUILayout.Button("Start Sample"))
sample.CreateUnityObject();
GUILayout.EndVertical();
GUILayout.EndArea();
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 8265be5da926116458a8948712d2eddb
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,286 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!29 &1
OcclusionCullingSettings:
m_ObjectHideFlags: 0
serializedVersion: 2
m_OcclusionBakeSettings:
smallestOccluder: 5
smallestHole: 0.25
backfaceThreshold: 100
m_SceneGUID: 00000000000000000000000000000000
m_OcclusionCullingData: {fileID: 0}
--- !u!104 &2
RenderSettings:
m_ObjectHideFlags: 0
serializedVersion: 9
m_Fog: 0
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
m_FogMode: 3
m_FogDensity: 0.01
m_LinearFogStart: 0
m_LinearFogEnd: 300
m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
m_AmbientIntensity: 1
m_AmbientMode: 0
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
m_HaloStrength: 0.5
m_FlareStrength: 1
m_FlareFadeSpeed: 3
m_HaloTexture: {fileID: 0}
m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
m_DefaultReflectionMode: 0
m_DefaultReflectionResolution: 128
m_ReflectionBounces: 1
m_ReflectionIntensity: 1
m_CustomReflection: {fileID: 0}
m_Sun: {fileID: 0}
m_IndirectSpecularColor: {r: 0.44657874, g: 0.49641258, b: 0.574817, a: 1}
m_UseRadianceAmbientProbe: 0
--- !u!157 &4
LightmapSettings:
m_ObjectHideFlags: 0
serializedVersion: 11
m_GIWorkflowMode: 0
m_GISettings:
serializedVersion: 2
m_BounceScale: 1
m_IndirectOutputScale: 1
m_AlbedoBoost: 1
m_TemporalCoherenceThreshold: 1
m_EnvironmentLightingMode: 0
m_EnableBakedLightmaps: 1
m_EnableRealtimeLightmaps: 1
m_LightmapEditorSettings:
serializedVersion: 10
m_Resolution: 2
m_BakeResolution: 40
m_AtlasSize: 1024
m_AO: 0
m_AOMaxDistance: 1
m_CompAOExponent: 0
m_CompAOExponentDirect: 0
m_Padding: 2
m_LightmapParameters: {fileID: 0}
m_LightmapsBakeMode: 1
m_TextureCompression: 1
m_FinalGather: 0
m_FinalGatherFiltering: 1
m_FinalGatherRayCount: 1024
m_ReflectionCompression: 2
m_MixedBakeMode: 1
m_BakeBackend: 0
m_PVRSampling: 1
m_PVRDirectSampleCount: 32
m_PVRSampleCount: 500
m_PVRBounces: 2
m_PVRFilterTypeDirect: 0
m_PVRFilterTypeIndirect: 0
m_PVRFilterTypeAO: 0
m_PVRFilteringMode: 0
m_PVRCulling: 1
m_PVRFilteringGaussRadiusDirect: 1
m_PVRFilteringGaussRadiusIndirect: 5
m_PVRFilteringGaussRadiusAO: 2
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
m_PVRFilteringAtrousPositionSigmaIndirect: 2
m_PVRFilteringAtrousPositionSigmaAO: 1
m_ShowResolutionOverlay: 1
m_LightingDataAsset: {fileID: 0}
m_UseShadowmask: 0
--- !u!196 &5
NavMeshSettings:
serializedVersion: 2
m_ObjectHideFlags: 0
m_BuildSettings:
serializedVersion: 2
agentTypeID: 0
agentRadius: 0.5
agentHeight: 2
agentSlope: 45
agentClimb: 0.4
ledgeDropHeight: 0
maxJumpAcrossDistance: 0
minRegionArea: 2
manualCellSize: 0
cellSize: 0.16666667
manualTileSize: 0
tileSize: 256
accuratePlacement: 0
debug:
m_Flags: 0
m_NavMeshData: {fileID: 0}
--- !u!1 &1787359519
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1787359521}
- component: {fileID: 1787359520}
m_Layer: 0
m_Name: Directional Light
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!108 &1787359520
Light:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 1787359519}
m_Enabled: 1
serializedVersion: 8
m_Type: 1
m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1}
m_Intensity: 1
m_Range: 10
m_SpotAngle: 30
m_CookieSize: 10
m_Shadows:
m_Type: 2
m_Resolution: -1
m_CustomResolution: -1
m_Strength: 1
m_Bias: 0.05
m_NormalBias: 0.4
m_NearPlane: 0.2
m_Cookie: {fileID: 0}
m_DrawHalo: 0
m_Flare: {fileID: 0}
m_RenderMode: 0
m_CullingMask:
serializedVersion: 2
m_Bits: 4294967295
m_Lightmapping: 4
m_LightShadowCasterMode: 0
m_AreaSize: {x: 1, y: 1}
m_BounceIntensity: 1
m_ColorTemperature: 6570
m_UseColorTemperature: 0
m_ShadowRadius: 0
m_ShadowAngle: 0
--- !u!4 &1787359521
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 1787359519}
m_LocalRotation: {x: 0.40821794, y: -0.23456973, z: 0.109381676, w: 0.87542605}
m_LocalPosition: {x: 0, y: 3, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 1
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1927127934
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1927127940}
- component: {fileID: 1927127939}
- component: {fileID: 1927127938}
- component: {fileID: 1927127937}
- component: {fileID: 1927127936}
- component: {fileID: 1927127935}
m_Layer: 0
m_Name: Main Camera
m_TagString: MainCamera
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &1927127935
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 1927127934}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 8265be5da926116458a8948712d2eddb, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!81 &1927127936
AudioListener:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 1927127934}
m_Enabled: 1
--- !u!124 &1927127937
Behaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 1927127934}
m_Enabled: 1
--- !u!92 &1927127938
Behaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 1927127934}
m_Enabled: 1
--- !u!20 &1927127939
Camera:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 1927127934}
m_Enabled: 1
serializedVersion: 2
m_ClearFlags: 2
m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0.019607844}
m_projectionMatrixMode: 1
m_SensorSize: {x: 36, y: 24}
m_LensShift: {x: 0, y: 0}
m_FocalLength: 50
m_NormalizedViewPortRect:
serializedVersion: 2
x: 0
y: 0
width: 1
height: 1
near clip plane: 0.3
far clip plane: 1000
field of view: 60
orthographic: 0
orthographic size: 5
m_Depth: -1
m_CullingMask:
serializedVersion: 2
m_Bits: 4294967295
m_RenderingPath: -1
m_TargetTexture: {fileID: 0}
m_TargetDisplay: 0
m_TargetEye: 3
m_HDR: 0
m_AllowMSAA: 1
m_AllowDynamicResolution: 0
m_ForceIntoRT: 0
m_OcclusionCulling: 1
m_StereoConvergence: 10
m_StereoSeparation: 0.022
--- !u!4 &1927127940
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 1927127934}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 1, z: -10}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}

View File

@@ -0,0 +1,6 @@
fileFormatVersion: 2
guid: 5ed13563a809f06489c3e97e4da02176
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: d69707652d0d406448aedf33b807bf6d
folderAsset: yes
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 9286baa677f488b4bb493dd5436147c6
folderAsset: yes
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,135 @@
#if !BESTHTTP_DISABLE_SIGNALR
#if !BESTHTTP_DISABLE_COOKIES && (!UNITY_WEBGL || UNITY_EDITOR)
using System;
using BestHTTP.Cookies;
using BestHTTP.SignalR.Transports;
namespace BestHTTP.SignalR.Authentication
{
public sealed class SampleCookieAuthentication : IAuthenticationProvider
{
#region Public Properties
public Uri AuthUri { get; private set; }
public string UserName { get; private set; }
public string Password { get; private set; }
public string UserRoles { get; private set; }
#endregion
#region IAuthenticationProvider properties
public bool IsPreAuthRequired { get; private set; }
public event OnAuthenticationSuccededDelegate OnAuthenticationSucceded;
public event OnAuthenticationFailedDelegate OnAuthenticationFailed;
#endregion
#region Privates
private HTTPRequest AuthRequest;
private Cookie Cookie;
#endregion
public SampleCookieAuthentication(Uri authUri, string user, string passwd, string roles)
{
this.AuthUri = authUri;
this.UserName = user;
this.Password = passwd;
this.UserRoles = roles;
this.IsPreAuthRequired = true;
}
#region IAuthenticationProvider Implementation
public void StartAuthentication()
{
AuthRequest = new HTTPRequest(AuthUri, HTTPMethods.Post, OnAuthRequestFinished);
// Setup the form
AuthRequest.AddField("userName", UserName);
AuthRequest.AddField("Password", Password); // not used in the sample
AuthRequest.AddField("roles", UserRoles);
AuthRequest.Send();
}
public void PrepareRequest(HTTPRequest request, RequestTypes type)
{
// Adding the cookie to the request is not required, as it's managed by the plugin automatically,
// but for now, we want to be really sure that it's added
request.Cookies.Add(Cookie);
}
#endregion
#region Request Handler
void OnAuthRequestFinished(HTTPRequest req, HTTPResponse resp)
{
AuthRequest = null;
string failReason = string.Empty;
switch (req.State)
{
// The request finished without any problem.
case HTTPRequestStates.Finished:
if (resp.IsSuccess)
{
Cookie = resp.Cookies != null ? resp.Cookies.Find(c => c.Name.Equals(".ASPXAUTH")) : null;
if (Cookie != null)
{
HTTPManager.Logger.Information("CookieAuthentication", "Auth. Cookie found!");
if (OnAuthenticationSucceded != null)
OnAuthenticationSucceded(this);
// return now, all other paths are authentication failures
return;
}
else
HTTPManager.Logger.Warning("CookieAuthentication", failReason = "Auth. Cookie NOT found!");
}
else
HTTPManager.Logger.Warning("CookieAuthentication", failReason = 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:
HTTPManager.Logger.Warning("CookieAuthentication", failReason = "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:
HTTPManager.Logger.Warning("CookieAuthentication", failReason = "Request Aborted!");
break;
// Connecting to the server is timed out.
case HTTPRequestStates.ConnectionTimedOut:
HTTPManager.Logger.Error("CookieAuthentication", failReason = "Connection Timed Out!");
break;
// The request didn't finished in the given time.
case HTTPRequestStates.TimedOut:
HTTPManager.Logger.Error("CookieAuthentication", failReason = "Processing the request Timed Out!");
break;
}
if (OnAuthenticationFailed != null)
OnAuthenticationFailed(this, failReason);
}
#endregion
}
}
#endif
#endif

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 48a74a50eeb07bb4ea649a902e9d487a
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,97 @@
#if !BESTHTTP_DISABLE_SIGNALR
namespace BestHTTP.SignalR.Authentication
{
/// <summary>
/// Custom http-header based authenticator.
/// <example>
/// <code>
/// // Server side implementation of the Header-based authenticator
/// // Use it by adding the app.Use(typeof(HeaderBasedAuthenticationMiddleware)); line to the Startup class' Configuration function.
/// private class HeaderBasedAuthenticationMiddleware : OwinMiddleware
/// {
/// public HeaderBasedAuthenticationMiddleware(OwinMiddleware next)
/// : base(next)
/// {
/// }
///
/// public override Task Invoke(IOwinContext context)
/// {
/// string username = context.Request.Headers.Get("username");
/// string roles = context.Request.Headers.Get("roles");
///
/// if (!String.IsNullOrEmpty(username) && !String.IsNullOrEmpty(roles))
/// {
/// var identity = new System.Security.Principal.GenericIdentity(username);
///
/// var principal = new System.Security.Principal.GenericPrincipal(identity, SplitString(roles));
///
/// context.Request.User = principal;
/// }
///
/// return Next.Invoke(context);
/// }
///
/// private static string[] SplitString(string original)
/// {
/// if (String.IsNullOrEmpty(original))
/// return new string[0];
///
/// var split = from piece in original.Split(',') let trimmed = piece.Trim() where !String.IsNullOrEmpty(trimmed) select trimmed;
///
/// return split.ToArray();
/// }
/// }
/// </code>
/// </example>
/// </summary>
class HeaderAuthenticator : IAuthenticationProvider
{
public string User { get; private set; }
public string Roles { get; private set; }
/// <summary>
/// No pre-auth step required for this type of authentication
/// </summary>
public bool IsPreAuthRequired { get { return false; } }
#pragma warning disable 0067
/// <summary>
/// Not used event as IsPreAuthRequired is false
/// </summary>
public event OnAuthenticationSuccededDelegate OnAuthenticationSucceded;
/// <summary>
/// Not used event as IsPreAuthRequired is false
/// </summary>
public event OnAuthenticationFailedDelegate OnAuthenticationFailed;
#pragma warning restore 0067
/// <summary>
/// Constructor to initialise the authenticator with username and roles.
/// </summary>
public HeaderAuthenticator(string user, string roles)
{
this.User = user;
this.Roles = roles;
}
/// <summary>
/// Not used as IsPreAuthRequired is false
/// </summary>
public void StartAuthentication()
{ }
/// <summary>
/// Prepares the request by adding two headers to it
/// </summary>
public void PrepareRequest(BestHTTP.HTTPRequest request, RequestTypes type)
{
request.SetHeader("username", this.User);
request.SetHeader("roles", this.Roles);
}
}
}
#endif

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 5ebd4ce02d369a6498f9be6bb7141ac3
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,210 @@
#if !BESTHTTP_DISABLE_SIGNALR
using System;
using System.Collections.Generic;
using UnityEngine;
using BestHTTP.SignalR;
using BestHTTP.SignalR.Hubs;
using BestHTTP.SignalR.Messages;
using BestHTTP.SignalR.Authentication;
namespace BestHTTP.Examples
{
public class AuthenticationSample : MonoBehaviour
{
readonly Uri URI = new Uri(GUIHelper.BaseURL + "/signalr");
#region Private Fields
/// <summary>
/// Reference to the SignalR Connection
/// </summary>
Connection signalRConnection;
string userName = string.Empty;
string role = string.Empty;
Vector2 scrollPos;
#endregion
#region Unity Events
void Start()
{
// Create the SignalR connection, and pass the hubs that we want to connect to
signalRConnection = new Connection(URI, new BaseHub("noauthhub", "Messages"),
new BaseHub("invokeauthhub", "Messages Invoked By Admin or Invoker"),
new BaseHub("authhub", "Messages Requiring Authentication to Send or Receive"),
new BaseHub("inheritauthhub", "Messages Requiring Authentication to Send or Receive Because of Inheritance"),
new BaseHub("incomingauthhub", "Messages Requiring Authentication to Send"),
new BaseHub("adminauthhub", "Messages Requiring Admin Membership to Send or Receive"),
new BaseHub("userandroleauthhub", "Messages Requiring Name to be \"User\" and Role to be \"Admin\" to Send or Receive"));
// Set the authenticator if we have valid fields
if (!string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(role))
signalRConnection.AuthenticationProvider = new HeaderAuthenticator(userName, role);
// Set up event handler
signalRConnection.OnConnected += signalRConnection_OnConnected;
// Start to connect to the server.
signalRConnection.Open();
}
void OnDestroy()
{
// Close the connection when we are closing the sample
signalRConnection.Close();
}
void OnGUI()
{
GUIHelper.DrawArea(GUIHelper.ClientArea, true, () =>
{
scrollPos = GUILayout.BeginScrollView(scrollPos, false, false);
GUILayout.BeginVertical();
if (signalRConnection.AuthenticationProvider == null)
{
GUILayout.BeginHorizontal();
GUILayout.Label("Username (Enter 'User'):");
userName = GUILayout.TextField(userName, GUILayout.MinWidth(100));
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.Label("Roles (Enter 'Invoker' or 'Admin'):");
role = GUILayout.TextField(role, GUILayout.MinWidth(100));
GUILayout.EndHorizontal();
if (GUILayout.Button("Log in"))
Restart();
}
for (int i = 0; i < signalRConnection.Hubs.Length; ++i)
(signalRConnection.Hubs[i] as BaseHub).Draw();
GUILayout.EndVertical();
GUILayout.EndScrollView();
});
}
#endregion
/// <summary>
/// Called when we successfully connected to the server.
/// </summary>
void signalRConnection_OnConnected(Connection manager)
{
// call 'InvokedFromClient' on all hubs
for (int i = 0; i < signalRConnection.Hubs.Length; ++i)
(signalRConnection.Hubs[i] as BaseHub).InvokedFromClient();
}
/// <summary>
/// Helper function to do a hard-restart to the server.
/// </summary>
void Restart()
{
// Clean up
signalRConnection.OnConnected -= signalRConnection_OnConnected;
// Close current connection
signalRConnection.Close();
signalRConnection = null;
// start again, with authentication if we filled in all input fields
Start();
}
}
/// <summary>
/// Hub implementation for the authentication demo. All hubs that we connect to has the same server and client side functions.
/// </summary>
class BaseHub : Hub
{
#region Private Fields
/// <summary>
/// Hub specific title
/// </summary>
private string Title;
private GUIMessageList messages = new GUIMessageList();
#endregion
public BaseHub(string name, string title)
: base(name)
{
this.Title = title;
// Map the server-callable method names to the real functions.
On("joined", Joined);
On("rejoined", Rejoined);
On("left", Left);
On("invoked", Invoked);
}
#region Server Called Functions
private void Joined(Hub hub, MethodCallMessage methodCall)
{
Dictionary<string, object> AuthInfo = methodCall.Arguments[2] as Dictionary<string, object>;
messages.Add(string.Format("{0} joined at {1}\n\tIsAuthenticated: {2} IsAdmin: {3} UserName: {4}", methodCall.Arguments[0], methodCall.Arguments[1], AuthInfo["IsAuthenticated"], AuthInfo["IsAdmin"], AuthInfo["UserName"]));
}
private void Rejoined(Hub hub, MethodCallMessage methodCall)
{
messages.Add(string.Format("{0} reconnected at {1}", methodCall.Arguments[0], methodCall.Arguments[1]));
}
private void Left(Hub hub, MethodCallMessage methodCall)
{
messages.Add(string.Format("{0} left at {1}", methodCall.Arguments[0], methodCall.Arguments[1]));
}
private void Invoked(Hub hub, MethodCallMessage methodCall)
{
messages.Add(string.Format("{0} invoked hub method at {1}", methodCall.Arguments[0], methodCall.Arguments[1]));
}
#endregion
#region Client callable function implementation
public void InvokedFromClient()
{
base.Call("invokedFromClient", OnInvoked, OnInvokeFailed);
}
private void OnInvoked(Hub hub, ClientMessage originalMessage, ResultMessage result)
{
Debug.Log(hub.Name + " invokedFromClient success!");
}
/// <summary>
/// This callback function will be called every time we try to access a protected API while we are using an non-authenticated connection.
/// </summary>
private void OnInvokeFailed(Hub hub, ClientMessage originalMessage, FailureMessage result)
{
Debug.LogWarning(hub.Name + " " + result.ErrorMessage);
}
#endregion
public void Draw()
{
GUILayout.Label(this.Title);
GUILayout.BeginHorizontal();
GUILayout.Space(20);
messages.Draw(Screen.width - 20, 100);
GUILayout.EndHorizontal();
}
}
}
#endif

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 02921d1602244e44cbd5103f972bf1fb
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,275 @@
#if !BESTHTTP_DISABLE_SIGNALR
using System;
using UnityEngine;
using BestHTTP.SignalR;
#if !BESTHTTP_DISABLE_COOKIES && (!UNITY_WEBGL || UNITY_EDITOR)
using BestHTTP.Cookies;
#endif
namespace BestHTTP.Examples
{
public sealed class ConnectionAPISample : MonoBehaviour
{
readonly Uri URI = new Uri(GUIHelper.BaseURL + "/raw-connection/");
/// <summary>
/// Possible message types that the client can send to the server
/// </summary>
enum MessageTypes
{
Send, // 0
Broadcast, // 1
Join, // 2
PrivateMessage, // 3
AddToGroup, // 4
RemoveFromGroup, // 5
SendToGroup, // 6
BroadcastExceptMe, // 7
}
#region Private Fields
/// <summary>
/// Reference to the SignalR Connection
/// </summary>
Connection signalRConnection;
// Input strings
string ToEveryBodyText = string.Empty;
string ToMeText = string.Empty;
string PrivateMessageText = string.Empty;
string PrivateMessageUserOrGroupName = string.Empty;
GUIMessageList messages = new GUIMessageList();
#endregion
#region Unity Events
void Start()
{
#if !BESTHTTP_DISABLE_COOKIES && (!UNITY_WEBGL || UNITY_EDITOR)
// Set a "user" cookie if we previously used the 'Enter Name' button.
// The server will set this username to the new connection.
if (PlayerPrefs.HasKey("userName"))
CookieJar.Set(URI, new Cookie("user", PlayerPrefs.GetString("userName")));
#endif
signalRConnection = new Connection(URI);
// to serialize the Message class, set a more advanced json encoder
signalRConnection.JsonEncoder = new BestHTTP.SignalR.JsonEncoders.LitJsonEncoder();
// set up event handlers
signalRConnection.OnStateChanged += signalRConnection_OnStateChanged;
signalRConnection.OnNonHubMessage += signalRConnection_OnGeneralMessage;
// Start to connect to the server.
signalRConnection.Open();
}
/// <summary>
/// Draw the gui.
/// Get input strings.
/// Handle function calls.
/// </summary>
void OnGUI()
{
GUIHelper.DrawArea(GUIHelper.ClientArea, true, () =>
{
GUILayout.BeginVertical();
#region To Everybody
GUILayout.Label("To Everybody");
GUILayout.BeginHorizontal();
ToEveryBodyText = GUILayout.TextField(ToEveryBodyText, GUILayout.MinWidth(100));
if (GUILayout.Button("Broadcast"))
Broadcast(ToEveryBodyText);
if (GUILayout.Button("Broadcast (All Except Me)"))
BroadcastExceptMe(ToEveryBodyText);
if (GUILayout.Button("Enter Name"))
EnterName(ToEveryBodyText);
if (GUILayout.Button("Join Group"))
JoinGroup(ToEveryBodyText);
if (GUILayout.Button("Leave Group"))
LeaveGroup(ToEveryBodyText);
GUILayout.EndHorizontal();
#endregion
#region To Me
GUILayout.Label("To Me");
GUILayout.BeginHorizontal();
ToMeText = GUILayout.TextField(ToMeText, GUILayout.MinWidth(100));
if (GUILayout.Button("Send to me"))
SendToMe(ToMeText);
GUILayout.EndHorizontal();
#endregion
#region Private Message
GUILayout.Label("Private Message");
GUILayout.BeginHorizontal();
GUILayout.Label("Message:");
PrivateMessageText = GUILayout.TextField(PrivateMessageText, GUILayout.MinWidth(100));
GUILayout.Label("User or Group name:");
PrivateMessageUserOrGroupName = GUILayout.TextField(PrivateMessageUserOrGroupName, GUILayout.MinWidth(100));
if (GUILayout.Button("Send to user"))
SendToUser(PrivateMessageUserOrGroupName, PrivateMessageText);
if (GUILayout.Button("Send to group"))
SendToGroup(PrivateMessageUserOrGroupName, PrivateMessageText);
GUILayout.EndHorizontal();
#endregion
GUILayout.Space(20);
if (signalRConnection.State == ConnectionStates.Closed)
{
if (GUILayout.Button("Start Connection"))
signalRConnection.Open();
}
else if (GUILayout.Button("Stop Connection"))
signalRConnection.Close();
GUILayout.Space(20);
// Draw the messages
GUILayout.Label("Messages");
GUILayout.BeginHorizontal();
GUILayout.Space(20);
messages.Draw(Screen.width - 20, 0);
GUILayout.EndHorizontal();
GUILayout.EndVertical();
});
}
void OnDestroy()
{
// Close the connection when the sample is closed
signalRConnection.Close();
}
#endregion
#region SignalR Events
/// <summary>
/// Handle non-hub messages
/// </summary>
void signalRConnection_OnGeneralMessage(Connection manager, object data)
{
// For now, just create a Json string from the sent data again
string reencoded = BestHTTP.JSON.Json.Encode(data);
// and display it
messages.Add("[Server Message] " + reencoded);
}
void signalRConnection_OnStateChanged(Connection manager, ConnectionStates oldState, ConnectionStates newState)
{
// display state changes
messages.Add(string.Format("[State Change] {0} => {1}", oldState.ToString(), newState.ToString()));
}
#endregion
#region To EveryBody Functions
/// <summary>
/// Broadcast a message to all connected clients
/// </summary>
private void Broadcast(string text)
{
signalRConnection.Send(new { Type = MessageTypes.Broadcast, Value = text });
}
/// <summary>
/// Broadcast a message to all connected clients, except this client
/// </summary>
private void BroadcastExceptMe(string text)
{
signalRConnection.Send(new { Type = MessageTypes.BroadcastExceptMe, Value = text });
}
/// <summary>
/// Set a name for this connection.
/// </summary>
private void EnterName(string name)
{
signalRConnection.Send(new { Type = MessageTypes.Join, Value = name });
}
/// <summary>
/// Join to a group
/// </summary>
private void JoinGroup(string groupName)
{
signalRConnection.Send(new { Type = MessageTypes.AddToGroup, Value = groupName });
}
/// <summary>
/// Leave a group
/// </summary>
private void LeaveGroup(string groupName)
{
signalRConnection.Send(new { Type = MessageTypes.RemoveFromGroup, Value = groupName });
}
#endregion
#region To Me Functions
/// <summary>
/// Send a message to the very same client through the server
/// </summary>
void SendToMe(string text)
{
signalRConnection.Send(new { Type = MessageTypes.Send, Value = text });
}
#endregion
#region Private Message Functions
/// <summary>
/// Send a private message to a user
/// </summary>
void SendToUser(string userOrGroupName, string text)
{
signalRConnection.Send(new { Type = MessageTypes.PrivateMessage, Value = string.Format("{0}|{1}", userOrGroupName, text) });
}
/// <summary>
/// Send a message to a group
/// </summary>
void SendToGroup(string userOrGroupName, string text)
{
signalRConnection.Send(new { Type = MessageTypes.SendToGroup, Value = string.Format("{0}|{1}", userOrGroupName, text) });
}
#endregion
}
}
#endif

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 872d6dfdac0e67f4d910376205532bc0
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,141 @@
#if !BESTHTTP_DISABLE_SIGNALR
using System;
using UnityEngine;
using BestHTTP.SignalR;
using BestHTTP.SignalR.Hubs;
namespace BestHTTP.Examples
{
public sealed class ConnectionStatusSample : MonoBehaviour
{
readonly Uri URI = new Uri(GUIHelper.BaseURL + "/signalr");
/// <summary>
/// Reference to the SignalR Connection
/// </summary>
Connection signalRConnection;
GUIMessageList messages = new GUIMessageList();
#region Unity Events
void Start()
{
// Connect to the StatusHub hub
signalRConnection = new Connection(URI, "StatusHub");
// General events
signalRConnection.OnNonHubMessage += signalRConnection_OnNonHubMessage;
signalRConnection.OnError += signalRConnection_OnError;
signalRConnection.OnStateChanged += signalRConnection_OnStateChanged;
// Set up a callback for Hub events
signalRConnection["StatusHub"].OnMethodCall += statusHub_OnMethodCall;
// Connect to the server
signalRConnection.Open();
}
void OnDestroy()
{
// Close the connection when we are closing the sample
signalRConnection.Close();
}
void OnGUI()
{
GUIHelper.DrawArea(GUIHelper.ClientArea, true, () =>
{
GUILayout.BeginHorizontal();
if (GUILayout.Button("START") && signalRConnection.State != ConnectionStates.Connected)
signalRConnection.Open();
if (GUILayout.Button("STOP") && signalRConnection.State == ConnectionStates.Connected)
{
signalRConnection.Close();
messages.Clear();
}
if (GUILayout.Button("PING") && signalRConnection.State == ConnectionStates.Connected)
{
// Call a Hub-method on the server.
signalRConnection["StatusHub"].Call("Ping");
}
GUILayout.EndHorizontal();
GUILayout.Space(20);
GUILayout.Label("Connection Status Messages");
GUILayout.BeginHorizontal();
GUILayout.Space(20);
messages.Draw(Screen.width - 20, 0);
GUILayout.EndHorizontal();
});
}
#endregion
#region SignalR Events
/// <summary>
/// Called on server-sent non-hub messages.
/// </summary>
void signalRConnection_OnNonHubMessage(Connection manager, object data)
{
messages.Add("[Server Message] " + data.ToString());
}
/// <summary>
/// Called when the SignalR Connection's state changes.
/// </summary>
void signalRConnection_OnStateChanged(Connection manager, ConnectionStates oldState, ConnectionStates newState)
{
messages.Add(string.Format("[State Change] {0} => {1}", oldState, newState));
}
/// <summary>
/// Called when an error occures. The plugin may close the connection after this event.
/// </summary>
void signalRConnection_OnError(Connection manager, string error)
{
messages.Add("[Error] " + error);
}
/// <summary>
/// Called when the "StatusHub" hub wants to call a method on this client.
/// </summary>
void statusHub_OnMethodCall(Hub hub, string method, params object[] args)
{
string id = args.Length > 0 ? args[0] as string : string.Empty;
string when = args.Length > 1 ? args[1].ToString() : string.Empty;
switch (method)
{
case "joined":
messages.Add(string.Format("[{0}] {1} joined at {2}", hub.Name, id, when));
break;
case "rejoined":
messages.Add(string.Format("[{0}] {1} reconnected at {2}", hub.Name, id, when));
break;
case "leave":
messages.Add(string.Format("[{0}] {1} leaved at {2}", hub.Name, id, when));
break;
default: // pong
messages.Add(string.Format("[{0}] {1}", hub.Name, method));
break;
}
}
#endregion
}
}
#endif

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 0d5b759afc726754fb1e1d49d529bae5
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,557 @@
#if !BESTHTTP_DISABLE_SIGNALR
using System;
using UnityEngine;
using BestHTTP.SignalR;
using BestHTTP.SignalR.Hubs;
using BestHTTP.SignalR.Messages;
using BestHTTP.SignalR.JsonEncoders;
namespace BestHTTP.Examples
{
public sealed class DemoHubSample : MonoBehaviour
{
readonly Uri URI = new Uri(GUIHelper.BaseURL + "/signalr");
/// <summary>
/// The SignalR connection instance
/// </summary>
Connection signalRConnection;
/// <summary>
/// DemoHub client side implementation
/// </summary>
DemoHub demoHub;
/// <summary>
/// TypedDemoHub client side implementation
/// </summary>
TypedDemoHub typedDemoHub;
/// <summary>
/// VB .NET Hub
/// </summary>
Hub vbDemoHub;
/// <summary>
/// Result of the VB demo's ReadStateValue call
/// </summary>
string vbReadStateResult = string.Empty;
Vector2 scrollPos;
void Start()
{
// Create the hubs
demoHub = new DemoHub();
typedDemoHub = new TypedDemoHub();
vbDemoHub = new Hub("vbdemo");
// Create the SignalR connection, passing all the three hubs to it
signalRConnection = new Connection(URI, demoHub, typedDemoHub, vbDemoHub);
// Switch from the default encoder to the LitJson Encoder because it can handle the complex types too.
signalRConnection.JsonEncoder = new LitJsonEncoder();
// Call the demo functions when we successfully connect to the server
signalRConnection.OnConnected += (connection) =>
{
var person = new { Name = "Foo", Age = 20, Address = new { Street = "One Microsoft Way", Zip = "98052" } };
// Call the demo functions
demoHub.AddToGroups();
demoHub.GetValue();
demoHub.TaskWithException();
demoHub.GenericTaskWithException();
demoHub.SynchronousException();
demoHub.DynamicTask();
demoHub.PassingDynamicComplex(person);
demoHub.SimpleArray(new int[] { 5, 5, 6 });
demoHub.ComplexType(person);
demoHub.ComplexArray(new object[] { person, person, person });
demoHub.ReportProgress("Long running job!");
demoHub.Overload();
// set some state
demoHub.State["name"] = "Testing state!";
demoHub.ReadStateValue();
demoHub.PlainTask();
demoHub.GenericTaskWithContinueWith();
typedDemoHub.Echo("Typed echo callback");
// vbDemo is not wrapped in a hub class, it would contain only one function
vbDemoHub.Call("readStateValue", (hub, msg, result) => vbReadStateResult = string.Format("Read some state from VB.NET! => {0}", result.ReturnValue == null ? "undefined" : result.ReturnValue.ToString()));
};
// Start opening the signalR connection
signalRConnection.Open();
}
void OnDestroy()
{
// Close the connection when we are closing this sample
signalRConnection.Close();
}
void OnGUI()
{
GUIHelper.DrawArea(GUIHelper.ClientArea, true, () =>
{
scrollPos = GUILayout.BeginScrollView(scrollPos, false, false);
GUILayout.BeginVertical();
demoHub.Draw();
typedDemoHub.Draw();
GUILayout.Label("Read State Value");
GUILayout.BeginHorizontal();
GUILayout.Space(20);
GUILayout.Label(vbReadStateResult);
GUILayout.EndHorizontal();
GUILayout.Space(10);
GUILayout.EndVertical();
GUILayout.EndScrollView();
});
}
}
/// <summary>
/// Wrapper class of the 'TypedDemoHub' hub
/// </summary>
class TypedDemoHub : Hub
{
string typedEchoResult = string.Empty;
string typedEchoClientResult = string.Empty;
public TypedDemoHub()
: base("typeddemohub")
{
// Setup server-called functions
base.On("Echo", Echo);
}
#region Server Called Functions
/// <summary>
/// Server-called, client side implementation of the Echo function
/// </summary>
private void Echo(Hub hub, MethodCallMessage methodCall)
{
typedEchoClientResult = string.Format("{0} #{1} triggered!", methodCall.Arguments[0], methodCall.Arguments[1]);
}
#endregion
#region Client Called Function(s)
/// <summary>
/// Client-called, server side implementation of the Echo function.
/// When the function successfully executed on the server the OnEcho_Done callback function will be called.
/// </summary>
public void Echo(string msg)
{
base.Call("echo", OnEcho_Done, msg);
}
/// <summary>
/// When the function successfully executed on the server this callback function will be called.
/// </summary>
private void OnEcho_Done(Hub hub, ClientMessage originalMessage, ResultMessage result)
{
typedEchoResult = "TypedDemoHub.Echo(string message) invoked!";
}
#endregion
public void Draw()
{
GUILayout.Label("Typed callback");
GUILayout.BeginHorizontal();
GUILayout.Space(20);
GUILayout.BeginVertical();
GUILayout.Label(typedEchoResult);
GUILayout.Label(typedEchoClientResult);
GUILayout.EndVertical();
GUILayout.EndHorizontal();
GUILayout.Space(10);
}
}
/// <summary>
/// A wrapper class for the 'DemoHub' hub.
/// </summary>
class DemoHub : Hub
{
#region Private fields
// These fields are here to store results of the function calls
float longRunningJobProgress = 0f;
string longRunningJobStatus = "Not Started!";
string fromArbitraryCodeResult = string.Empty;
string groupAddedResult = string.Empty;
string dynamicTaskResult = string.Empty;
string genericTaskResult = string.Empty;
string taskWithExceptionResult = string.Empty;
string genericTaskWithExceptionResult = string.Empty;
string synchronousExceptionResult = string.Empty;
string invokingHubMethodWithDynamicResult = string.Empty;
string simpleArrayResult = string.Empty;
string complexTypeResult = string.Empty;
string complexArrayResult = string.Empty;
string voidOverloadResult = string.Empty;
string intOverloadResult = string.Empty;
string readStateResult = string.Empty;
string plainTaskResult = string.Empty;
string genericTaskWithContinueWithResult = string.Empty;
GUIMessageList invokeResults = new GUIMessageList();
#endregion
public DemoHub()
: base("demo")
{
// Setup server-called functions
base.On("invoke", Invoke);
base.On("signal", Signal);
base.On("groupAdded", GroupAdded);
base.On("fromArbitraryCode", FromArbitraryCode);
}
#region Client Called Functions
#region ReportProgress
public void ReportProgress(string arg)
{
Call("reportProgress", OnLongRunningJob_Done, null, OnLongRunningJob_Progress, arg);
}
public void OnLongRunningJob_Progress(Hub hub, ClientMessage originialMessage, ProgressMessage progress)
{
longRunningJobProgress = (float)progress.Progress;
longRunningJobStatus = progress.Progress.ToString() + "%";
}
public void OnLongRunningJob_Done(Hub hub, ClientMessage originalMessage, ResultMessage result)
{
longRunningJobStatus = result.ReturnValue.ToString();
MultipleCalls();
}
#endregion
public void MultipleCalls()
{
base.Call("multipleCalls");
}
#region DynamicTask
public void DynamicTask()
{
base.Call("dynamicTask", OnDynamicTask_Done, OnDynamicTask_Failed);
}
private void OnDynamicTask_Failed(Hub hub, ClientMessage originalMessage, FailureMessage result)
{
dynamicTaskResult = string.Format("The dynamic task failed :( {0}", result.ErrorMessage);
}
private void OnDynamicTask_Done(Hub hub, ClientMessage originalMessage, ResultMessage result)
{
dynamicTaskResult = string.Format("The dynamic task! {0}", result.ReturnValue);
}
#endregion
public void AddToGroups()
{
base.Call("addToGroups");
}
public void GetValue()
{
base.Call("getValue", (hub, msg, result) => genericTaskResult = string.Format("The value is {0} after 5 seconds", result.ReturnValue));
}
public void TaskWithException()
{
// This method call must fail, so only error handler added
base.Call("taskWithException", null, (Hub hub, ClientMessage msg, FailureMessage error) => taskWithExceptionResult = string.Format("Error: {0}", error.ErrorMessage));
}
public void GenericTaskWithException()
{
// This method call must fail, so only error handler added
base.Call("genericTaskWithException", null, (Hub hub, ClientMessage msg, FailureMessage error) => genericTaskWithExceptionResult = string.Format("Error: {0}", error.ErrorMessage));
}
public void SynchronousException()
{
// This method call must fail, so only error handler added
base.Call("synchronousException", null, (Hub hub, ClientMessage msg, FailureMessage error) => synchronousExceptionResult = string.Format("Error: {0}", error.ErrorMessage));
}
public void PassingDynamicComplex(object person)
{
base.Call("passingDynamicComplex", (hub, msg, result) => invokingHubMethodWithDynamicResult = string.Format("The person's age is {0}", result.ReturnValue), person);
}
public void SimpleArray(int[] array)
{
base.Call("simpleArray", (hub, msg, result) => simpleArrayResult = "Simple array works!", array);
}
public void ComplexType(object person)
{
base.Call("complexType", (hub, msg, result) => complexTypeResult = string.Format("Complex Type -> {0}", (this as IHub).Connection.JsonEncoder.Encode(this.State["person"])), person);
}
public void ComplexArray(object[] complexArray)
{
// We need to cast the object array to object to keep it as an array
// http://stackoverflow.com/questions/36350/how-to-pass-a-single-object-to-a-params-object
base.Call("ComplexArray", (hub, msg, result) => complexArrayResult = "Complex Array Works!", (object)complexArray);
}
#region Overloads
public void Overload()
{
base.Call("Overload", OnVoidOverload_Done);
}
private void OnVoidOverload_Done(Hub hub, ClientMessage originalMessage, ResultMessage result)
{
voidOverloadResult = "Void Overload called";
Overload(101);
}
public void Overload(int number)
{
base.Call("Overload", OnIntOverload_Done, number);
}
private void OnIntOverload_Done(Hub hub, ClientMessage originalMessage, ResultMessage result)
{
intOverloadResult = string.Format("Overload with return value called => {0}", result.ReturnValue.ToString());
}
#endregion
public void ReadStateValue()
{
base.Call("readStateValue", (hub, msg, result) => readStateResult = string.Format("Read some state! => {0}", result.ReturnValue));
}
public void PlainTask()
{
base.Call("plainTask", (hub, msg, result) => plainTaskResult = "Plain Task Result");
}
public void GenericTaskWithContinueWith()
{
base.Call("genericTaskWithContinueWith", (hub, msg, result) => genericTaskWithContinueWithResult = result.ReturnValue.ToString());
}
#endregion
#region Server Called Functions
private void FromArbitraryCode(Hub hub, MethodCallMessage methodCall)
{
fromArbitraryCodeResult = methodCall.Arguments[0] as string;
}
private void GroupAdded(Hub hub, MethodCallMessage methodCall)
{
if (!string.IsNullOrEmpty(groupAddedResult))
groupAddedResult = "Group Already Added!";
else
groupAddedResult = "Group Added!";
}
private void Signal(Hub hub, MethodCallMessage methodCall)
{
dynamicTaskResult = string.Format("The dynamic task! {0}", methodCall.Arguments[0]);
}
private void Invoke(Hub hub, MethodCallMessage methodCall)
{
invokeResults.Add(string.Format("{0} client state index -> {1}", methodCall.Arguments[0], this.State["index"]));
}
#endregion
#region Draw
/// <summary>
/// Display the result's of the function calls.
/// </summary>
public void Draw()
{
GUILayout.Label("Arbitrary Code");
GUILayout.BeginHorizontal();
GUILayout.Space(20);
GUILayout.Label(string.Format("Sending {0} from arbitrary code without the hub itself!", fromArbitraryCodeResult));
GUILayout.EndHorizontal();
GUILayout.Space(10);
GUILayout.Label("Group Added");
GUILayout.BeginHorizontal();
GUILayout.Space(20);
GUILayout.Label(groupAddedResult);
GUILayout.EndHorizontal();
GUILayout.Space(10);
GUILayout.Label("Dynamic Task");
GUILayout.BeginHorizontal();
GUILayout.Space(20);
GUILayout.Label(dynamicTaskResult);
GUILayout.EndHorizontal();
GUILayout.Space(10);
GUILayout.Label("Report Progress");
GUILayout.BeginHorizontal();
GUILayout.Space(20);
GUILayout.BeginVertical();
GUILayout.Label(longRunningJobStatus);
GUILayout.HorizontalSlider(longRunningJobProgress, 0, 100);
GUILayout.EndVertical();
GUILayout.EndHorizontal();
GUILayout.Space(10);
GUILayout.Label("Generic Task");
GUILayout.BeginHorizontal();
GUILayout.Space(20);
GUILayout.Label(genericTaskResult);
GUILayout.EndHorizontal();
GUILayout.Space(10);
GUILayout.Label("Task With Exception");
GUILayout.BeginHorizontal();
GUILayout.Space(20);
GUILayout.Label(taskWithExceptionResult);
GUILayout.EndHorizontal();
GUILayout.Space(10);
GUILayout.Label("Generic Task With Exception");
GUILayout.BeginHorizontal();
GUILayout.Space(20);
GUILayout.Label(genericTaskWithExceptionResult);
GUILayout.EndHorizontal();
GUILayout.Space(10);
GUILayout.Label("Synchronous Exception");
GUILayout.BeginHorizontal();
GUILayout.Space(20);
GUILayout.Label(synchronousExceptionResult);
GUILayout.EndHorizontal();
GUILayout.Space(10);
GUILayout.Label("Invoking hub method with dynamic");
GUILayout.BeginHorizontal();
GUILayout.Space(20);
GUILayout.Label(invokingHubMethodWithDynamicResult);
GUILayout.EndHorizontal();
GUILayout.Space(10);
GUILayout.Label("Simple Array");
GUILayout.BeginHorizontal();
GUILayout.Space(20);
GUILayout.Label(simpleArrayResult);
GUILayout.EndHorizontal();
GUILayout.Space(10);
GUILayout.Label("Complex Type");
GUILayout.BeginHorizontal();
GUILayout.Space(20);
GUILayout.Label(complexTypeResult);
GUILayout.EndHorizontal();
GUILayout.Space(10);
GUILayout.Label("Complex Array");
GUILayout.BeginHorizontal();
GUILayout.Space(20);
GUILayout.Label(complexArrayResult);
GUILayout.EndHorizontal();
GUILayout.Space(10);
GUILayout.Label("Overloads");
GUILayout.BeginHorizontal();
GUILayout.Space(20);
GUILayout.BeginVertical();
GUILayout.Label(voidOverloadResult);
GUILayout.Label(intOverloadResult);
GUILayout.EndVertical();
GUILayout.EndHorizontal();
GUILayout.Space(10);
GUILayout.Label("Read State Value");
GUILayout.BeginHorizontal();
GUILayout.Space(20);
GUILayout.Label(readStateResult);
GUILayout.EndHorizontal();
GUILayout.Space(10);
GUILayout.Label("Plain Task");
GUILayout.BeginHorizontal();
GUILayout.Space(20);
GUILayout.Label(plainTaskResult);
GUILayout.EndHorizontal();
GUILayout.Space(10);
GUILayout.Label("Generic Task With ContinueWith");
GUILayout.BeginHorizontal();
GUILayout.Space(20);
GUILayout.Label(genericTaskWithContinueWithResult);
GUILayout.EndHorizontal();
GUILayout.Space(10);
GUILayout.Label("Message Pump");
GUILayout.BeginHorizontal();
GUILayout.Space(20);
invokeResults.Draw(Screen.width - 40, 270);
GUILayout.EndHorizontal();
GUILayout.Space(10);
}
#endregion
}
}
#endif

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 55779d2699b42c34ab1549c70402d294
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 1c996438e0be72649b8abf5fbdee3f41
folderAsset: yes
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,23 @@
#if !BESTHTTP_DISABLE_SIGNALR && BESTHTTP_SIGNALR_WITH_JSONDOTNET
using System.Collections.Generic;
using Newtonsoft.Json;
namespace BestHTTP.SignalR.JsonEncoders
{
public sealed class JSonDotnetEncoder : IJsonEncoder
{
public string Encode(object obj)
{
return JsonConvert.SerializeObject(obj);
}
public IDictionary<string, object> DecodeMessage(string json)
{
return JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
}
}
}
#endif

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 653a0f163689052438748b7beda14886
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,28 @@
#if !BESTHTTP_DISABLE_SIGNALR
using System.Collections.Generic;
using LitJson;
namespace BestHTTP.SignalR.JsonEncoders
{
public sealed class LitJsonEncoder : IJsonEncoder
{
public string Encode(object obj)
{
JsonWriter writer = new JsonWriter();
JsonMapper.ToJson(obj, writer);
return writer.ToString();
}
public IDictionary<string, object> DecodeMessage(string json)
{
JsonReader reader = new JsonReader(json);
return JsonMapper.ToObject<Dictionary<string, object>>(reader);
}
}
}
#endif

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 2870a746a601b8b439c495ff39474385
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,91 @@
#if !BESTHTTP_DISABLE_SIGNALR
using System;
using UnityEngine;
using BestHTTP.SignalR;
namespace BestHTTP.Examples
{
public sealed class SimpleStreamingSample : MonoBehaviour
{
readonly Uri URI = new Uri(GUIHelper.BaseURL + "/streaming-connection");
/// <summary>
/// Reference to the SignalR Connection
/// </summary>
Connection signalRConnection;
/// <summary>
/// Helper GUI class to handle and display a string-list
/// </summary>
GUIMessageList messages = new GUIMessageList();
#region Unity Events
void Start()
{
// Create the SignalR connection
signalRConnection = new Connection(URI);
// set event handlers
signalRConnection.OnNonHubMessage += signalRConnection_OnNonHubMessage;
signalRConnection.OnStateChanged += signalRConnection_OnStateChanged;
signalRConnection.OnError += signalRConnection_OnError;
// Start connecting to the server
signalRConnection.Open();
}
void OnDestroy()
{
// Close the connection when the sample is closed
signalRConnection.Close();
}
void OnGUI()
{
GUIHelper.DrawArea(GUIHelper.ClientArea, true, () =>
{
GUILayout.Label("Messages");
GUILayout.BeginHorizontal();
GUILayout.Space(20);
messages.Draw(Screen.width - 20, 0);
GUILayout.EndHorizontal();
});
}
#endregion
#region SignalR Events
/// <summary>
/// Handle Server-sent messages
/// </summary>
void signalRConnection_OnNonHubMessage(Connection connection, object data)
{
messages.Add("[Server Message] " + data.ToString());
}
/// <summary>
/// Display state changes
/// </summary>
void signalRConnection_OnStateChanged(Connection connection, ConnectionStates oldState, ConnectionStates newState)
{
messages.Add(string.Format("[State Change] {0} => {1}", oldState, newState));
}
/// <summary>
/// Display errors.
/// </summary>
void signalRConnection_OnError(Connection connection, string error)
{
messages.Add("[Error] " + error);
}
#endregion
}
}
#endif

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 0eb1f1efe4749fc489977765e40a04e4
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: f7ff75ba203704d45bf1098536a2db5a
folderAsset: yes
timeCreated: 1515401610
licenseType: Store
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9e87559ef678942428f064af598c1696
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,63 @@
#if !BESTHTTP_DISABLE_SIGNALR_CORE
using System;
namespace BestHTTP.SignalRCore.Authentication
{
public sealed class HeaderAuthenticator : IAuthenticationProvider
{
/// <summary>
/// No pre-auth step required for this type of authentication
/// </summary>
public bool IsPreAuthRequired { get { return false; } }
#pragma warning disable 0067
/// <summary>
/// Not used event as IsPreAuthRequired is false
/// </summary>
public event OnAuthenticationSuccededDelegate OnAuthenticationSucceded;
/// <summary>
/// Not used event as IsPreAuthRequired is false
/// </summary>
public event OnAuthenticationFailedDelegate OnAuthenticationFailed;
#pragma warning restore 0067
private string _credentials;
public HeaderAuthenticator(string credentials)
{
this._credentials = credentials;
}
/// <summary>
/// Not used as IsPreAuthRequired is false
/// </summary>
public void StartAuthentication()
{ }
/// <summary>
/// Prepares the request by adding two headers to it
/// </summary>
public void PrepareRequest(BestHTTP.HTTPRequest request)
{
#if !UNITY_WEBGL
request.SetHeader("Authorization", "Bearer " + this._credentials);
#endif
}
public Uri PrepareUri(Uri uri)
{
#if UNITY_WEBGL
string query = string.IsNullOrEmpty(uri.Query) ? "?" : uri.Query + "&";
UriBuilder uriBuilder = new UriBuilder(uri.Scheme, uri.Host, uri.Port, uri.AbsolutePath, query + "access_token=" + this._credentials);
return uriBuilder.Uri;
#else
return uri;
#endif
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 80b2246c164414c468eea4f0550eb9ad
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 35c592488a6dbbc4a96c1739cd74046c
folderAsset: yes
timeCreated: 1515401610
licenseType: Store
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,38 @@
#if !BESTHTTP_DISABLE_SIGNALR_CORE && !BESTHTTP_DISABLE_WEBSOCKET
using System;
namespace BestHTTP.SignalRCore.Encoders
{
/*public sealed class JsonDotNetEncoder : BestHTTP.SignalRCore.IEncoder
{
public string Name { get { return "json"; } }
public object ConvertTo(Type toType, object obj)
{
string json = Newtonsoft.Json.JsonConvert.SerializeObject(obj);
return Newtonsoft.Json.JsonConvert.DeserializeObject(json, toType);
}
public T DecodeAs<T>(string text)
{
return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(text);
}
public T DecodeAs<T>(byte[] data)
{
throw new NotImplementedException();
}
public byte[] EncodeAsBinary<T>(T value)
{
throw new NotImplementedException();
}
public string EncodeAsText<T>(T value)
{
return Newtonsoft.Json.JsonConvert.SerializeObject(value);
}
}*/
}
#endif

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 5e565b09f1e97ee4c9d119735901397b
timeCreated: 1515401618
licenseType: Store
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,48 @@
#if !BESTHTTP_DISABLE_SIGNALR_CORE && !BESTHTTP_DISABLE_WEBSOCKET
using System;
namespace BestHTTP.SignalRCore.Encoders
{
public sealed class LitJsonEncoder : BestHTTP.SignalRCore.IEncoder
{
public string Name { get { return "json"; } }
public LitJsonEncoder()
{
LitJson.JsonMapper.RegisterImporter<int, long>((input) => input);
LitJson.JsonMapper.RegisterImporter<long, int>((input) => (int)input);
LitJson.JsonMapper.RegisterImporter<double, int>((input) => (int)(input + 0.5));
LitJson.JsonMapper.RegisterImporter<string, DateTime>((input) => Convert.ToDateTime((string)input).ToUniversalTime());
LitJson.JsonMapper.RegisterImporter<double, float>((input) => (float)input);
LitJson.JsonMapper.RegisterImporter<string, byte[]>((input) => Convert.FromBase64String(input));
}
public T DecodeAs<T>(string text)
{
return LitJson.JsonMapper.ToObject<T>(text);
}
public T DecodeAs<T>(byte[] data)
{
throw new NotImplementedException();
}
public byte[] EncodeAsBinary<T>(T value)
{
throw new NotImplementedException();
}
public string EncodeAsText<T>(T value)
{
return LitJson.JsonMapper.ToJson(value);
}
public object ConvertTo(Type toType, object obj)
{
string json = LitJson.JsonMapper.ToJson(obj);
return LitJson.JsonMapper.ToObject(toType, json);
}
}
}
#endif

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: b5784b64da7c8ad47b441a9f2f27a33b
timeCreated: 1515401618
licenseType: Store
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,92 @@
#if !BESTHTTP_DISABLE_SIGNALR_CORE
using System;
using System.Collections.Generic;
using BestHTTP.SignalRCore.Messages;
namespace BestHTTP.SignalRCore.Encoders
{
public sealed class MessagePackEncoder : BestHTTP.SignalRCore.IEncoder
{
public string Name { get { return "messagepack"; } }
public object ConvertTo(Type toType, object obj)
{
throw new NotImplementedException();
}
public T DecodeAs<T>(string text)
{
throw new NotImplementedException();
}
public T DecodeAs<T>(byte[] data)
{
throw new NotImplementedException();
}
public byte[] EncodeAsBinary<T>(T value)
{
throw new NotImplementedException();
}
public string EncodeAsText<T>(T value)
{
throw new NotImplementedException();
}
}
public sealed class MessagePackProtocol : BestHTTP.SignalRCore.IProtocol
{
public TransferModes Type { get { return TransferModes.Binary; } }
public IEncoder Encoder { get; private set; }
public HubConnection Connection { get; set; }
public MessagePackProtocol()
{
this.Encoder = new MessagePackEncoder();
}
/// <summary>
/// Convert a value to the given type.
/// </summary>
public object ConvertTo(Type toType, object obj)
{
throw new NotImplementedException();
}
/// <summary>
/// This function must return the encoded representation of the given message.
/// </summary>
public byte[] EncodeMessage(Message message)
{
throw new NotImplementedException();
}
/// <summary>
/// This function must convert all element in the arguments array to the corresponding type from the argTypes array.
/// </summary>
public object[] GetRealArguments(Type[] argTypes, object[] arguments)
{
throw new NotImplementedException();
}
/// <summary>
/// This function must parse binary representation of the messages into the list of Messages.
/// </summary>
public void ParseMessages(string data, ref List<Message> messages)
{
throw new NotImplementedException();
}
/// <summary>
/// This function must parse textual representation of the messages into the list of Messages.
/// </summary>
public void ParseMessages(byte[] data, ref List<Message> messages)
{
throw new NotImplementedException();
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1fe4434eade98e547aca1e026a4dbcc3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,109 @@
#if !BESTHTTP_DISABLE_SIGNALR_CORE
using BestHTTP.Examples;
using BestHTTP.SignalRCore;
using BestHTTP.SignalRCore.Encoders;
using System;
using UnityEngine;
namespace BestHTTP.Examples
{
/// <summary>
/// A sample to demonstrate Bearer token authorization on the server. The client will connect to the /redirect route
/// where it will receive the token and will receive the new url (/HubWithAuthorization) to connect to.
/// HubWithAuthorization without the token would throw an error.
/// </summary>
public sealed class HubWithAuthorizationSample : MonoBehaviour
{
// Server uri to connect to
readonly Uri URI = new Uri(GUIHelper.BaseURL + "/redirect");
// Instance of the HubConnection
HubConnection hub;
Vector2 scrollPos;
string uiText;
void Start()
{
// Server side of this example can be found here:
// https://github.com/Benedicht/BestHTTP_DemoSite/blob/master/BestHTTP_DemoSite/Hubs/
// Crete the HubConnection
hub = new HubConnection(URI, new JsonProtocol(new LitJsonEncoder()));
// Subscribe to hub events
hub.OnConnected += Hub_OnConnected;
hub.OnError += Hub_OnError;
hub.OnClosed += Hub_OnClosed;
hub.OnMessage += Hub_OnMessage;
// And finally start to connect to the server
hub.StartConnect();
uiText = "StartConnect called\n";
}
void OnDestroy()
{
if (hub != null)
hub.StartClose();
}
// Draw the text stored in the 'uiText' field
void OnGUI()
{
GUIHelper.DrawArea(GUIHelper.ClientArea, true, () =>
{
scrollPos = GUILayout.BeginScrollView(scrollPos, false, false);
GUILayout.BeginVertical();
GUILayout.Label(uiText);
GUILayout.EndVertical();
GUILayout.EndScrollView();
});
}
/// <summary>
/// This callback is called when the plugin is connected to the server successfully. Messages can be sent to the server after this point.
/// </summary>
private void Hub_OnConnected(HubConnection hub)
{
uiText += "Hub Connected\n";
// Call a parameterless function. We expect a string return value.
hub.Invoke<string>("Echo", "Message from the client")
.OnSuccess(ret => uiText += string.Format(" 'Echo' returned: '{0}'\n", ret));
}
/// <summary>
/// This callback is called for every hub message. If false is returned, the plugin will cancel any further processing of the message.
/// </summary>
private bool Hub_OnMessage(HubConnection hub, BestHTTP.SignalRCore.Messages.Message message)
{
//uiText += string.Format("( Message received: {0} )\n", message.ToString());
return true;
}
/// <summary>
/// This is called when the hub is closed after a StartClose() call.
/// </summary>
private void Hub_OnClosed(HubConnection hub)
{
uiText += "Hub Closed\n";
}
/// <summary>
/// Called when an unrecoverable error happen. After this event the hub will not send or receive any messages.
/// </summary>
private void Hub_OnError(HubConnection hub, string error)
{
uiText += "Hub Error: " + error + "\n";
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a0d6f71c9108b3b419ee412fa4ddd018
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,224 @@
#if !BESTHTTP_DISABLE_SIGNALR_CORE
using BestHTTP;
using BestHTTP.SignalRCore;
using BestHTTP.SignalRCore.Encoders;
using System;
using UnityEngine;
namespace BestHTTP.Examples
{
public sealed class HubWithPreAuthorizationSample : MonoBehaviour
{
// Server uri to connect to
readonly Uri URI = new Uri(GUIHelper.BaseURL + "/HubWithAuthorization");
readonly Uri AuthURI = new Uri(GUIHelper.BaseURL + "/generateJwtToken");
// Instance of the HubConnection
HubConnection hub;
Vector2 scrollPos;
string uiText;
void Start()
{
// Server side of this example can be found here:
// https://github.com/Benedicht/BestHTTP_DemoSite/blob/master/BestHTTP_DemoSite/Hubs/
// Crete the HubConnection
hub = new HubConnection(URI, new JsonProtocol(new LitJsonEncoder()));
hub.AuthenticationProvider = new PreAuthAccessTokenAuthenticator(AuthURI);
hub.AuthenticationProvider.OnAuthenticationSucceded += AuthenticationProvider_OnAuthenticationSucceded;
hub.AuthenticationProvider.OnAuthenticationFailed += AuthenticationProvider_OnAuthenticationFailed;
// Subscribe to hub events
hub.OnConnected += Hub_OnConnected;
hub.OnError += Hub_OnError;
hub.OnClosed += Hub_OnClosed;
hub.OnMessage += Hub_OnMessage;
// And finally start to connect to the server
hub.StartConnect();
uiText = "StartConnect called\n";
}
private void AuthenticationProvider_OnAuthenticationSucceded(IAuthenticationProvider provider)
{
string str = string.Format("Pre-Authentication Succeded! Token: '{0}' \n", (hub.AuthenticationProvider as PreAuthAccessTokenAuthenticator).Token);
Debug.Log(str);
uiText += str;
}
private void AuthenticationProvider_OnAuthenticationFailed(IAuthenticationProvider provider, string reason)
{
uiText += string.Format("Authentication Failed! Reason: '{0}'\n", reason);
}
void OnDestroy()
{
if (hub != null)
hub.StartClose();
}
// Draw the text stored in the 'uiText' field
void OnGUI()
{
GUIHelper.DrawArea(GUIHelper.ClientArea, true, () =>
{
scrollPos = GUILayout.BeginScrollView(scrollPos, false, false);
GUILayout.BeginVertical();
GUILayout.Label(uiText);
GUILayout.EndVertical();
GUILayout.EndScrollView();
});
}
/// <summary>
/// This callback is called when the plugin is connected to the server successfully. Messages can be sent to the server after this point.
/// </summary>
private void Hub_OnConnected(HubConnection hub)
{
uiText += "Hub Connected\n";
// Call a parameterless function. We expect a string return value.
hub.Invoke<string>("Echo", "Message from the client")
.OnSuccess(ret => uiText += string.Format(" 'Echo' returned: '{0}'\n", ret));
}
/// <summary>
/// This callback is called for every hub message. If false is returned, the plugin will cancel any further processing of the message.
/// </summary>
private bool Hub_OnMessage(HubConnection hub, BestHTTP.SignalRCore.Messages.Message message)
{
//uiText += string.Format("( Message received: {0} )\n", message.ToString());
return true;
}
/// <summary>
/// This is called when the hub is closed after a StartClose() call.
/// </summary>
private void Hub_OnClosed(HubConnection hub)
{
uiText += "Hub Closed\n";
}
/// <summary>
/// Called when an unrecoverable error happen. After this event the hub will not send or receive any messages.
/// </summary>
private void Hub_OnError(HubConnection hub, string error)
{
uiText += "Hub Error: " + error + "\n";
}
}
public sealed class PreAuthAccessTokenAuthenticator : IAuthenticationProvider
{
/// <summary>
/// No pre-auth step required for this type of authentication
/// </summary>
public bool IsPreAuthRequired { get { return true; } }
#pragma warning disable 0067
/// <summary>
/// Not used event as IsPreAuthRequired is false
/// </summary>
public event OnAuthenticationSuccededDelegate OnAuthenticationSucceded;
/// <summary>
/// Not used event as IsPreAuthRequired is false
/// </summary>
public event OnAuthenticationFailedDelegate OnAuthenticationFailed;
#pragma warning restore 0067
private Uri authenticationUri;
public string Token { get; private set; }
public PreAuthAccessTokenAuthenticator(Uri authUri)
{
this.authenticationUri = authUri;
}
public void StartAuthentication()
{
var request = new HTTPRequest(this.authenticationUri, OnAuthenticationRequestFinished);
request.Send();
}
private void OnAuthenticationRequestFinished(HTTPRequest req, HTTPResponse resp)
{
switch (req.State)
{
// The request finished without any problem.
case HTTPRequestStates.Finished:
if (resp.IsSuccess)
{
this.Token = resp.DataAsText;
if (this.OnAuthenticationSucceded != null)
this.OnAuthenticationSucceded(this);
}
else // Internal server error?
AuthenticationFailed(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:
AuthenticationFailed("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:
AuthenticationFailed("Request Aborted!");
break;
// Connecting to the server is timed out.
case HTTPRequestStates.ConnectionTimedOut:
AuthenticationFailed("Connection Timed Out!");
break;
// The request didn't finished in the given time.
case HTTPRequestStates.TimedOut:
AuthenticationFailed("Processing the request Timed Out!");
break;
}
}
private void AuthenticationFailed(string reason)
{
if (this.OnAuthenticationFailed != null)
this.OnAuthenticationFailed(this, reason);
}
/// <summary>
/// Prepares the request by adding two headers to it
/// </summary>
public void PrepareRequest(BestHTTP.HTTPRequest request)
{
if (HTTPProtocolFactory.GetProtocolFromUri(request.CurrentUri) == SupportedProtocols.HTTP)
request.Uri = PrepareUri(request.Uri);
}
public Uri PrepareUri(Uri uri)
{
if (!string.IsNullOrEmpty(this.Token))
{
string query = string.IsNullOrEmpty(uri.Query) ? "?" : uri.Query + "&";
UriBuilder uriBuilder = new UriBuilder(uri.Scheme, uri.Host, uri.Port, uri.AbsolutePath, query + "access_token=" + this.Token);
return uriBuilder.Uri;
}
else
return uri;
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bfb23ec912f317944b34485c85ab6b31
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,175 @@
#if !BESTHTTP_DISABLE_SIGNALR_CORE
using BestHTTP;
using BestHTTP.SignalRCore;
using BestHTTP.SignalRCore.Encoders;
using System;
using UnityEngine;
namespace BestHTTP.Examples
{
/// <summary>
/// This sample demonstrates redirection capabilities. The server will redirect a few times the client before
/// routing it to the final endpoint.
/// </summary>
public sealed class RedirectSample : MonoBehaviour
{
// Server uri to connect to
readonly Uri URI = new Uri(GUIHelper.BaseURL + "/redirect_sample");
// Instance of the HubConnection
public HubConnection hub;
Vector2 scrollPos;
public string uiText;
void Start()
{
// Server side of this example can be found here:
// https://github.com/Benedicht/BestHTTP_DemoSite/blob/master/BestHTTP_DemoSite/Hubs/
// Crete the HubConnection
hub = new HubConnection(URI, new JsonProtocol(new LitJsonEncoder()));
hub.AuthenticationProvider = new RedirectLoggerAccessTokenAuthenticator(hub);
// Subscribe to hub events
hub.OnConnected += Hub_OnConnected;
hub.OnError += Hub_OnError;
hub.OnClosed += Hub_OnClosed;
hub.OnMessage += Hub_OnMessage;
hub.OnRedirected += Hub_Redirected;
// And finally start to connect to the server
hub.StartConnect();
uiText = "StartConnect called\n";
}
void OnDestroy()
{
if (hub != null)
{
hub.StartClose();
}
}
// Draw the text stored in the 'uiText' field
void OnGUI()
{
GUIHelper.DrawArea(GUIHelper.ClientArea, true, () =>
{
scrollPos = GUILayout.BeginScrollView(scrollPos, false, false);
GUILayout.BeginVertical();
GUILayout.Label(uiText);
GUILayout.EndVertical();
GUILayout.EndScrollView();
});
}
private void Hub_Redirected(HubConnection hub, Uri oldUri, Uri newUri)
{
uiText += string.Format("Hub connection redirected to '<color=green>{0}</color>'!\n", hub.Uri);
}
/// <summary>
/// This callback is called when the plugin is connected to the server successfully. Messages can be sent to the server after this point.
/// </summary>
private void Hub_OnConnected(HubConnection hub)
{
uiText += "Hub Connected\n";
// Call a parameterless function. We expect a string return value.
hub.Invoke<string>("Echo", "Message from the client")
.OnSuccess(ret => uiText += string.Format(" 'Echo' returned: '{0}'\n", ret));
}
/// <summary>
/// This callback is called for every hub message. If false is returned, the plugin will cancel any further processing of the message.
/// </summary>
private bool Hub_OnMessage(HubConnection hub, BestHTTP.SignalRCore.Messages.Message message)
{
//uiText += string.Format("( Message received: {0} )\n", message.ToString());
return true;
}
/// <summary>
/// This is called when the hub is closed after a StartClose() call.
/// </summary>
private void Hub_OnClosed(HubConnection hub)
{
uiText += "Hub Closed\n";
}
/// <summary>
/// Called when an unrecoverable error happen. After this event the hub will not send or receive any messages.
/// </summary>
private void Hub_OnError(HubConnection hub, string error)
{
uiText += "Hub Error: " + error + "\n";
}
}
public sealed class RedirectLoggerAccessTokenAuthenticator : IAuthenticationProvider
{
/// <summary>
/// No pre-auth step required for this type of authentication
/// </summary>
public bool IsPreAuthRequired { get { return false; } }
#pragma warning disable 0067
/// <summary>
/// Not used event as IsPreAuthRequired is false
/// </summary>
public event OnAuthenticationSuccededDelegate OnAuthenticationSucceded;
/// <summary>
/// Not used event as IsPreAuthRequired is false
/// </summary>
public event OnAuthenticationFailedDelegate OnAuthenticationFailed;
#pragma warning restore 0067
private HubConnection _connection;
public RedirectLoggerAccessTokenAuthenticator(HubConnection connection)
{
this._connection = connection;
}
/// <summary>
/// Not used as IsPreAuthRequired is false
/// </summary>
public void StartAuthentication()
{ }
/// <summary>
/// Prepares the request by adding two headers to it
/// </summary>
public void PrepareRequest(BestHTTP.HTTPRequest request)
{
request.SetHeader("x-redirect-count", _connection.RedirectCount.ToString());
if (HTTPProtocolFactory.GetProtocolFromUri(request.CurrentUri) == SupportedProtocols.HTTP)
request.Uri = PrepareUri(request.Uri);
}
public Uri PrepareUri(Uri uri)
{
if (this._connection.NegotiationResult != null && !string.IsNullOrEmpty(this._connection.NegotiationResult.AccessToken))
{
string query = string.IsNullOrEmpty(uri.Query) ? "?" : uri.Query + "&";
UriBuilder uriBuilder = new UriBuilder(uri.Scheme, uri.Host, uri.Port, uri.AbsolutePath, query + "access_token=" + this._connection.NegotiationResult.AccessToken);
return uriBuilder.Uri;
}
else
return uri;
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: febf35a5598c76843a7573e8f650079e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,174 @@
#if !BESTHTTP_DISABLE_SIGNALR_CORE
using System;
using UnityEngine;
using BestHTTP.SignalRCore;
using BestHTTP.SignalRCore.Encoders;
namespace BestHTTP.Examples
{
public class TestHubExample : MonoBehaviour
{
// Server uri to connect to
readonly Uri URI = new Uri(GUIHelper.BaseURL + "/TestHub");
// Instance of the HubConnection
HubConnection hub;
Vector2 scrollPos;
string uiText;
void Start()
{
// Server side of this example can be found here:
// https://github.com/Benedicht/BestHTTP_DemoSite/blob/master/BestHTTP_DemoSite/Hubs/TestHub.cs
// Set up optional options
HubOptions options = new HubOptions();
options.SkipNegotiation = false;
// Crete the HubConnection
hub = new HubConnection(URI, new JsonProtocol(new LitJsonEncoder()), options);
// Optionally add an authenticator
//hub.AuthenticationProvider = new BestHTTP.SignalRCore.Authentication.HeaderAuthenticator("<generated jwt token goes here>");
// Subscribe to hub events
hub.OnConnected += Hub_OnConnected;
hub.OnError += Hub_OnError;
hub.OnClosed += Hub_OnClosed;
hub.OnMessage += Hub_OnMessage;
// Set up server callable functions
hub.On("Send", (string arg) => uiText += string.Format(" On Send: {0}\n", arg));
hub.On<Person>("Person", (person) => uiText += string.Format(" On Person: {0}\n", person));
hub.On<Person, Person>("TwoPersons", (person1, person2) => uiText += string.Format(" On TwoPersons: {0}, {1}\n", person1, person2));
// And finally start to connect to the server
hub.StartConnect();
uiText = "StartConnect called\n";
}
void OnDestroy()
{
if (hub != null)
hub.StartClose();
}
// Draw the text stored in the 'uiText' field
void OnGUI()
{
GUIHelper.DrawArea(GUIHelper.ClientArea, true, () =>
{
scrollPos = GUILayout.BeginScrollView(scrollPos, false, false);
GUILayout.BeginVertical();
GUILayout.Label(uiText);
GUILayout.EndVertical();
GUILayout.EndScrollView();
});
}
/// <summary>
/// This callback is called when the plugin is connected to the server successfully. Messages can be sent to the server after this point.
/// </summary>
private void Hub_OnConnected(HubConnection hub)
{
uiText += "Hub Connected\n";
// Call a server function with a string param. We expect no return value.
hub.Send("Send", "my message");
// Call a parameterless function. We expect a string return value.
hub.Invoke<string>("NoParam")
.OnSuccess(ret => uiText += string.Format(" 'NoParam' returned: {0}\n", ret));
// Call a function on the server to add two numbers. OnSuccess will be called with the result and OnError if there's an error.
hub.Invoke<int>("Add", 10, 20)
.OnSuccess(result => uiText += string.Format(" 'Add(10, 20)' returned: {0}\n", result))
.OnError(error => uiText += string.Format(" 'Add(10, 20)' error: {0}\n", error));
// Call a function that will return a Person object constructed from the function's parameters.
hub.Invoke<Person>("GetPerson", "Mr. Smith", 26)
.OnSuccess(result => uiText += string.Format(" 'GetPerson(\"Mr. Smith\", 26)' returned: {0}\n", result))
.OnError(error => uiText += string.Format(" 'GetPerson(\"Mr. Smith\", 26)' error: {0}\n", error));
// To test errors/exceptions this call always throws an exception on the server side resulting in an OnError call.
// OnError expected here!
hub.Invoke<int>("SingleResultFailure", 10, 20)
.OnSuccess(result => uiText += string.Format(" 'SingleResultFailure(10, 20)' returned: {0}\n", result))
.OnError(error => uiText += string.Format(" 'SingleResultFailure(10, 20)' error: {0}\n", error));
// This call demonstrates IEnumerable<> functions, result will be the yielded numbers.
hub.Invoke<int[]>("Batched", 10)
.OnSuccess(result => uiText += string.Format(" 'Batched(10)' returned items: {0}\n", result.Length))
.OnError(error => uiText += string.Format(" 'Batched(10)' error: {0}\n", error));
// OnItem is called for a streaming request for every items returned by the server. OnSuccess will still be called with all the items.
hub.Stream<int>("ObservableCounter", 10, 1000)
.OnItem(result => uiText += string.Format(" 'ObservableCounter(10, 1000)' OnItem: {0}\n", result.LastAdded))
.OnSuccess(result => uiText += string.Format(" 'ObservableCounter(10, 1000)' OnSuccess. Final count: {0}\n", result.Items.Count))
.OnError(error => uiText += string.Format(" 'ObservableCounter(10, 1000)' error: {0}\n", error));
// A stream request can be cancelled any time.
var container = hub.Stream<int>("ChannelCounter", 10, 1000)
.OnItem(result => uiText += string.Format(" 'ChannelCounter(10, 1000)' OnItem: {0}\n", result.LastAdded))
.OnSuccess(result => uiText += string.Format(" 'ChannelCounter(10, 1000)' OnSuccess. Final count: {0}\n", result.Items.Count))
.OnError(error => uiText += string.Format(" 'ChannelCounter(10, 1000)' error: {0}\n", error)).value;
// a stream can be cancelled by calling CancelStream
hub.CancelStream(container);
// This call will stream strongly typed objects
hub.Stream<Person>("GetRandomPersons", 20, 2000)
.OnItem(result => uiText += string.Format(" 'GetRandomPersons(20, 1000)' OnItem: {0}\n", result.LastAdded))
.OnSuccess(result => uiText += string.Format(" 'GetRandomPersons(20, 1000)' OnSuccess. Final count: {0}\n", result.Items.Count));
}
/// <summary>
/// This callback is called for every hub message. If false is returned, the plugin will cancel any further processing of the message.
/// </summary>
private bool Hub_OnMessage(HubConnection hub, BestHTTP.SignalRCore.Messages.Message message)
{
//UnityEngine.Debug.Log("Message Arrived: " + message.ToString());
return true;
}
/// <summary>
/// This is called when the hub is closed after a StartClose() call.
/// </summary>
private void Hub_OnClosed(HubConnection hub)
{
uiText += "Hub Closed\n";
}
/// <summary>
/// Called when an unrecoverable error happen. After this event the hub will not send or receive any messages.
/// </summary>
private void Hub_OnError(HubConnection hub, string error)
{
uiText += "Hub Error: " + error + "\n";
}
/// <summary>
/// Helper class to demonstrate strongly typed callbacks
/// </summary>
sealed class Person
{
public string Name { get; set; }
public long Age { get; set; }
public override string ToString()
{
return string.Format("[Person Name: '{0}', Age: {1}]", this.Name, this.Age.ToString());
}
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6bd28a72bf1727542937e09ab435abcc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 6d952d96253d7454992111c6a4116837
folderAsset: yes
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 745fcd55afb34e4429897e798738aebd
folderAsset: yes
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,27 @@
#if !BESTHTTP_DISABLE_SOCKETIO
using System;
using System.Collections.Generic;
namespace BestHTTP.SocketIO.JsonEncoders
{
/*using Newtonsoft.Json;
/// <summary>
/// This class uses Newtonsoft's Json encoder (JSON .NET For Unity - http://u3d.as/5q2).
/// </summary>
public sealed class JsonDotNetEncoder : IJsonEncoder
{
public List<object> Decode(string json)
{
return JsonConvert.DeserializeObject<List<object>>(json);
}
public string Encode(List<object> obj)
{
return JsonConvert.SerializeObject(obj);
}
}*/
}
#endif

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: c2d9c71662df0b641980b51cd68443fa
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,30 @@
#if !BESTHTTP_DISABLE_SOCKETIO
using System.Collections.Generic;
using LitJson;
namespace BestHTTP.SocketIO.JsonEncoders
{
/// <summary>
/// This IJsonEncoder implementation uses the LitJson library located in the Examples\LitJson directory.
/// </summary>
public sealed class LitJsonEncoder : IJsonEncoder
{
public List<object> Decode(string json)
{
JsonReader reader = new JsonReader(json);
return JsonMapper.ToObject<List<object>>(reader);
}
public string Encode(List<object> obj)
{
JsonWriter writer = new JsonWriter();
JsonMapper.ToJson(obj, writer);
return writer.ToString();
}
}
}
#endif

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 0329bd6a6be04394b9da7576fc41d1dc
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,321 @@
#if !BESTHTTP_DISABLE_SOCKETIO
using System;
using System.Collections.Generic;
using UnityEngine;
using BestHTTP.SocketIO;
namespace BestHTTP.Examples
{
public sealed class SocketIOChatSample : MonoBehaviour
{
private readonly TimeSpan TYPING_TIMER_LENGTH = TimeSpan.FromMilliseconds(700);
private enum ChatStates
{
Login,
Chat
}
#region Fields
/// <summary>
/// The Socket.IO manager instance.
/// </summary>
private SocketManager Manager;
/// <summary>
/// Current state of the chat demo.
/// </summary>
private ChatStates State;
/// <summary>
/// The selected nickname
/// </summary>
private string userName = string.Empty;
/// <summary>
/// Currently typing message
/// </summary>
private string message = string.Empty;
/// <summary>
/// Sent and received messages.
/// </summary>
private string chatLog = string.Empty;
/// <summary>
/// Position of the scroller
/// </summary>
private Vector2 scrollPos;
/// <summary>
/// True if the user is currently typing
/// </summary>
private bool typing;
/// <summary>
/// When the message changed.
/// </summary>
private DateTime lastTypingTime = DateTime.MinValue;
/// <summary>
/// Users that typing.
/// </summary>
private List<string> typingUsers = new List<string>();
#endregion
#region Unity Events
void Start()
{
// The current state is Login
State = ChatStates.Login;
// Change an option to show how it should be done
SocketOptions options = new SocketOptions();
options.AutoConnect = false;
options.ConnectWith = BestHTTP.SocketIO.Transports.TransportTypes.WebSocket;
// Create the Socket.IO manager
Manager = new SocketManager(new Uri("https://socket-io-chat.now.sh/socket.io/"), options);
// Set up custom chat events
Manager.Socket.On("login", OnLogin);
Manager.Socket.On("new message", OnNewMessage);
Manager.Socket.On("user joined", OnUserJoined);
Manager.Socket.On("user left", OnUserLeft);
Manager.Socket.On("typing", OnTyping);
Manager.Socket.On("stop typing", OnStopTyping);
// The argument will be an Error object.
Manager.Socket.On(SocketIOEventTypes.Error, (socket, packet, args) => Debug.LogError(string.Format("Error: {0}", args[0].ToString())));
// We set SocketOptions' AutoConnect to false, so we have to call it manually.
Manager.Open();
}
void OnDestroy()
{
// Leaving this sample, close the socket
Manager.Close();
}
void Update()
{
// Go back to the demo selector
if (Input.GetKeyDown(KeyCode.Escape))
SampleSelector.SelectedSample.DestroyUnityObject();
// Stop typing if some time passed without typing
if (typing)
{
var typingTimer = DateTime.UtcNow;
var timeDiff = typingTimer - lastTypingTime;
if (timeDiff >= TYPING_TIMER_LENGTH)
{
Manager.Socket.Emit("stop typing");
typing = false;
}
}
}
void OnGUI()
{
switch (State)
{
case ChatStates.Login: DrawLoginScreen(); break;
case ChatStates.Chat: DrawChatScreen(); break;
}
}
#endregion
#region Chat Logic
/// <summary>
/// Called from an OnGUI event to draw the Login Screen.
/// </summary>
void DrawLoginScreen()
{
GUIHelper.DrawArea(GUIHelper.ClientArea, true, () =>
{
GUILayout.BeginVertical();
GUILayout.FlexibleSpace();
GUIHelper.DrawCenteredText("What's your nickname?");
userName = GUILayout.TextField(userName);
if (GUILayout.Button("Join"))
SetUserName();
GUILayout.FlexibleSpace();
GUILayout.EndVertical();
});
}
/// <summary>
/// Called from an OnGUI event to draw the Chat Screen.
/// </summary>
void DrawChatScreen()
{
GUIHelper.DrawArea(GUIHelper.ClientArea, true, () =>
{
GUILayout.BeginVertical();
scrollPos = GUILayout.BeginScrollView(scrollPos);
GUILayout.Label(chatLog, GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(true));
GUILayout.EndScrollView();
string typing = string.Empty;
if (typingUsers.Count > 0)
{
typing += string.Format("{0}", typingUsers[0]);
for (int i = 1; i < typingUsers.Count; ++i)
typing += string.Format(", {0}", typingUsers[i]);
if (typingUsers.Count == 1)
typing += " is typing!";
else
typing += " are typing!";
}
GUILayout.Label(typing);
GUILayout.Label("Type here:");
GUILayout.BeginHorizontal();
message = GUILayout.TextField(message);
if (GUILayout.Button("Send", GUILayout.MaxWidth(100)))
SendMessage();
GUILayout.EndHorizontal();
if (GUI.changed)
UpdateTyping();
GUILayout.EndVertical();
});
}
void SetUserName()
{
if (string.IsNullOrEmpty(userName))
return;
State = ChatStates.Chat;
Manager.Socket.Emit("add user", userName);
}
void SendMessage()
{
if (string.IsNullOrEmpty(message))
return;
Manager.Socket.Emit("new message", message);
chatLog += string.Format("{0}: {1}\n", userName, message);
message = string.Empty;
}
void UpdateTyping()
{
if (!typing)
{
typing = true;
Manager.Socket.Emit("typing");
}
lastTypingTime = DateTime.UtcNow;
}
void addParticipantsMessage(Dictionary<string, object> data)
{
int numUsers = Convert.ToInt32(data["numUsers"]);
if (numUsers == 1)
chatLog += "there's 1 participant\n";
else
chatLog += "there are " + numUsers + " participants\n";
}
void addChatMessage(Dictionary<string, object> data)
{
var username = data["username"] as string;
var msg = data["message"] as string;
chatLog += string.Format("{0}: {1}\n", username, msg);
}
void AddChatTyping(Dictionary<string, object> data)
{
var username = data["username"] as string;
typingUsers.Add(username);
}
void RemoveChatTyping(Dictionary<string, object> data)
{
var username = data["username"] as string;
int idx = typingUsers.FindIndex((name) => name.Equals(username));
if (idx != -1)
typingUsers.RemoveAt(idx);
}
#endregion
#region Custom SocketIO Events
void OnLogin(Socket socket, Packet packet, params object[] args)
{
chatLog = "Welcome to Socket.IO Chat — \n";
addParticipantsMessage(args[0] as Dictionary<string, object>);
}
void OnNewMessage(Socket socket, Packet packet, params object[] args)
{
addChatMessage(args[0] as Dictionary<string, object>);
}
void OnUserJoined(Socket socket, Packet packet, params object[] args)
{
var data = args[0] as Dictionary<string, object>;
var username = data["username"] as string;
chatLog += string.Format("{0} joined\n", username);
addParticipantsMessage(data);
}
void OnUserLeft(Socket socket, Packet packet, params object[] args)
{
var data = args[0] as Dictionary<string, object>;
var username = data["username"] as string;
chatLog += string.Format("{0} left\n", username);
addParticipantsMessage(data);
}
void OnTyping(Socket socket, Packet packet, params object[] args)
{
AddChatTyping(args[0] as Dictionary<string, object>);
}
void OnStopTyping(Socket socket, Packet packet, params object[] args)
{
RemoveChatTyping(args[0] as Dictionary<string, object>);
}
#endregion
}
}
#endif

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: feaffc82c9b6aa54ba0e8bf6572d279e
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,394 @@
#if !BESTHTTP_DISABLE_SOCKETIO
using System;
using System.Collections.Generic;
using UnityEngine;
using BestHTTP.SocketIO;
namespace BestHTTP.Examples
{
public sealed class SocketIOWePlaySample : MonoBehaviour
{
/// <summary>
/// Possible states of the game.
/// </summary>
enum States
{
Connecting,
WaitForNick,
Joined
}
/// <summary>
/// Controls that the server understands as a parameter in the move event.
/// </summary>
private string[] controls = new string[] { "left", "right", "a", "b", "up", "down", "select", "start" };
/// <summary>
/// Ratio of the drawn GUI texture from the screen
/// </summary>
private const float ratio = 1.5f;
/// <summary>
/// How many messages to keep.
/// </summary>
private int MaxMessages = 50;
/// <summary>
/// Current state of the game.
/// </summary>
private States State;
/// <summary>
/// The root("/") Socket instance.
/// </summary>
private Socket Socket;
/// <summary>
/// The user-selected nickname.
/// </summary>
private string Nick = string.Empty;
/// <summary>
/// The message that the user want to send to the chat.
/// </summary>
private string messageToSend = string.Empty;
/// <summary>
/// How many user connected to the server.
/// </summary>
private int connections;
/// <summary>
/// Local and server sent messages.
/// </summary>
private List<string> messages = new List<string>();
/// <summary>
/// The chat scroll position.
/// </summary>
private Vector2 scrollPos;
/// <summary>
/// The decoded texture from the server sent binary data
/// </summary>
private Texture2D FrameTexture;
#region Unity Events
void Start()
{
// Change an option to show how it should be done
SocketOptions options = new SocketOptions();
options.AutoConnect = false;
// Create the SocketManager instance
var manager = new SocketManager(new Uri("http://io.weplay.io/socket.io/"), options);
// Keep a reference to the root namespace
Socket = manager.Socket;
// Set up our event handlers.
Socket.On(SocketIOEventTypes.Connect, OnConnected);
Socket.On("joined", OnJoined);
Socket.On("connections", OnConnections);
Socket.On("join", OnJoin);
Socket.On("move", OnMove);
Socket.On("message", OnMessage);
Socket.On("reload", OnReload);
// Don't waste cpu cycles on decoding the payload, we are expecting only binary data with this event,
// and we can access it through the packet's Attachments property.
Socket.On("frame", OnFrame, /*autoDecodePayload:*/ false);
// Add error handler, so we can display it
Socket.On(SocketIOEventTypes.Error, OnError);
// We set SocketOptions' AutoConnect to false, so we have to call it manually.
manager.Open();
// We are connecting to the server.
State = States.Connecting;
}
void OnDestroy()
{
// Leaving this sample, close the socket
Socket.Manager.Close();
}
void Update()
{
// Go back to the demo selector
if (Input.GetKeyDown(KeyCode.Escape))
SampleSelector.SelectedSample.DestroyUnityObject();
}
void OnGUI()
{
switch (State)
{
case States.Connecting:
GUIHelper.DrawArea(GUIHelper.ClientArea, true, () =>
{
GUILayout.BeginVertical();
GUILayout.FlexibleSpace();
GUIHelper.DrawCenteredText("Connecting to the server...");
GUILayout.FlexibleSpace();
GUILayout.EndVertical();
});
break;
case States.WaitForNick:
GUIHelper.DrawArea(GUIHelper.ClientArea, true, () =>
{
DrawLoginScreen();
});
break;
case States.Joined:
GUIHelper.DrawArea(GUIHelper.ClientArea, true, () =>
{
// Draw Texture
if (FrameTexture != null)
GUILayout.Box(FrameTexture);
DrawControls();
DrawChat();
});
break;
}
}
#endregion
#region Helper Functions
/// <summary>
/// Called from an OnGUI event to draw the Login Screen.
/// </summary>
void DrawLoginScreen()
{
GUILayout.BeginVertical();
GUILayout.FlexibleSpace();
GUIHelper.DrawCenteredText("What's your nickname?");
Nick = GUILayout.TextField(Nick);
if (GUILayout.Button("Join"))
Join();
GUILayout.FlexibleSpace();
GUILayout.EndVertical();
}
void DrawControls()
{
GUILayout.BeginHorizontal();
GUILayout.Label("Controls:");
for (int i = 0; i < controls.Length; ++i)
if (GUILayout.Button(controls[i]))
Socket.Emit("move", controls[i]);
GUILayout.Label(" Connections: " + connections);
GUILayout.EndHorizontal();
}
void DrawChat(bool withInput = true)
{
GUILayout.BeginVertical();
// Draw the messages
scrollPos = GUILayout.BeginScrollView(scrollPos, false, false);
for (int i = 0; i < messages.Count; ++i)
GUILayout.Label(messages[i], GUILayout.MinWidth(Screen.width));
GUILayout.EndScrollView();
if (withInput)
{
GUILayout.Label("Your message: ");
GUILayout.BeginHorizontal();
messageToSend = GUILayout.TextField(messageToSend);
if (GUILayout.Button("Send", GUILayout.MaxWidth(100)))
SendMessage();
GUILayout.EndHorizontal();
}
GUILayout.EndVertical();
}
/// <summary>
/// Add a message to the message log
/// </summary>
/// <param name="msg"></param>
void AddMessage(string msg)
{
messages.Insert(0, msg);
if (messages.Count > MaxMessages)
messages.RemoveRange(MaxMessages, messages.Count - MaxMessages);
}
/// <summary>
/// Send a chat message. The message must be in the messageToSend field.
/// </summary>
void SendMessage()
{
if (string.IsNullOrEmpty(messageToSend))
return;
Socket.Emit("message", messageToSend);
AddMessage(string.Format("{0}: {1}", Nick, messageToSend));
messageToSend = string.Empty;
}
/// <summary>
/// Join to the game with the nickname stored in the Nick field.
/// </summary>
void Join()
{
PlayerPrefs.SetString("Nick", Nick);
Socket.Emit("join", Nick);
}
/// <summary>
/// Reload the game.
/// </summary>
void Reload()
{
FrameTexture = null;
if (Socket != null)
{
Socket.Manager.Close();
Socket = null;
Start();
}
}
#endregion
#region SocketIO Events
/// <summary>
/// Socket connected event.
/// </summary>
private void OnConnected(Socket socket, Packet packet, params object[] args)
{
if (PlayerPrefs.HasKey("Nick"))
{
Nick = PlayerPrefs.GetString("Nick", "NickName");
Join();
}
else
State = States.WaitForNick;
AddMessage("connected");
}
/// <summary>
/// Local player joined after sending a 'join' event
/// </summary>
private void OnJoined(Socket socket, Packet packet, params object[] args)
{
State = States.Joined;
}
/// <summary>
/// Server sent us a 'reload' event.
/// </summary>
private void OnReload(Socket socket, Packet packet, params object[] args)
{
Reload();
}
/// <summary>
/// Someone wrote a message to the chat.
/// </summary>
private void OnMessage(Socket socket, Packet packet, params object[] args)
{
if (args.Length == 1)
AddMessage(args[0] as string);
else
AddMessage(string.Format("{0}: {1}", args[1], args[0]));
}
/// <summary>
/// Someone (including us) pressed a button.
/// </summary>
private void OnMove(Socket socket, Packet packet, params object[] args)
{
AddMessage(string.Format("{0} pressed {1}", args[1], args[0]));
}
/// <summary>
/// Someone joined to the game
/// </summary>
private void OnJoin(Socket socket, Packet packet, params object[] args)
{
string loc = args.Length > 1 ? string.Format("({0})", args[1]) : string.Empty;
AddMessage(string.Format("{0} joined {1}", args[0], loc));
}
/// <summary>
/// How many players are connected to the game.
/// </summary>
private void OnConnections(Socket socket, Packet packet, params object[] args)
{
connections = Convert.ToInt32(args[0]);
}
/// <summary>
/// The server sent us a new picture to draw the game.
/// </summary>
private void OnFrame(Socket socket, Packet packet, params object[] args)
{
if (State != States.Joined)
return;
if (FrameTexture == null)
{
FrameTexture = new Texture2D(0, 0, TextureFormat.RGBA32, false);
FrameTexture.filterMode = FilterMode.Point;
}
// Binary data usage case 1 - using directly the Attachments property:
byte[] data = packet.Attachments[0];
// Binary data usage case 2 - using the packet's ReconstructAttachmentAsIndex() function
/*packet.ReconstructAttachmentAsIndex();
args = packet.Decode(socket.Manager.Encoder);
data = packet.Attachments[Convert.ToInt32(args[0])];*/
// Binary data usage case 3 - using the packet's ReconstructAttachmentAsBase64() function
/*packet.ReconstructAttachmentAsBase64();
args = packet.Decode(socket.Manager.Encoder);
data = Convert.FromBase64String(args[0] as string);*/
// Load the server sent picture
FrameTexture.LoadImage(data);
}
/// <summary>
/// Called on local or remote error.
/// </summary>
private void OnError(Socket socket, Packet packet, params object[] args)
{
AddMessage(string.Format("--ERROR - {0}", args[0].ToString()));
}
#endregion
}
}
#endif

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 3ce53a6e4419d8f429db4a753d71a0c2
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 3f80c43b87778214daf5495f2854dfe0
folderAsset: yes
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,169 @@
#if !BESTHTTP_DISABLE_WEBSOCKET
using System;
using UnityEngine;
namespace BestHTTP.Examples
{
public class WebSocketSample : MonoBehaviour
{
#region Private Fields
/// <summary>
/// The WebSocket address to connect
/// </summary>
string address = "wss://echo.websocket.org";
/// <summary>
/// Default text to send
/// </summary>
string msgToSend = "Hello World!";
/// <summary>
/// Debug text to draw on the gui
/// </summary>
string Text = string.Empty;
/// <summary>
/// Saved WebSocket instance
/// </summary>
WebSocket.WebSocket webSocket;
/// <summary>
/// GUI scroll position
/// </summary>
Vector2 scrollPos;
#endregion
#region Unity Events
void OnDestroy()
{
if (webSocket != null)
{
webSocket.Close();
}
}
void OnGUI()
{
GUIHelper.DrawArea(GUIHelper.ClientArea, true, () =>
{
scrollPos = GUILayout.BeginScrollView(scrollPos);
GUILayout.Label(Text);
GUILayout.EndScrollView();
GUILayout.Space(5);
GUILayout.FlexibleSpace();
address = GUILayout.TextField(address);
if (webSocket == null && GUILayout.Button("Open Web Socket"))
{
// Create the WebSocket instance
webSocket = new WebSocket.WebSocket(new Uri(address));
#if !UNITY_WEBGL
webSocket.StartPingThread = true;
#if !BESTHTTP_DISABLE_PROXY
if (HTTPManager.Proxy != null)
webSocket.InternalRequest.Proxy = new HTTPProxy(HTTPManager.Proxy.Address, HTTPManager.Proxy.Credentials, false);
#endif
#endif
// Subscribe to the WS events
webSocket.OnOpen += OnOpen;
webSocket.OnMessage += OnMessageReceived;
webSocket.OnClosed += OnClosed;
webSocket.OnError += OnError;
// Start connecting to the server
webSocket.Open();
Text += "Opening Web Socket...\n";
}
if (webSocket != null && webSocket.IsOpen)
{
GUILayout.Space(10);
GUILayout.BeginHorizontal();
msgToSend = GUILayout.TextField(msgToSend);
GUILayout.EndHorizontal();
if (GUILayout.Button("Send", GUILayout.MaxWidth(70)))
{
Text += "Sending message...\n";
// Send message to the server
webSocket.Send(msgToSend);
}
GUILayout.Space(10);
if (GUILayout.Button("Close"))
{
// Close the connection
webSocket.Close(1000, "Bye!");
}
}
});
}
#endregion
#region WebSocket Event Handlers
/// <summary>
/// Called when the web socket is open, and we are ready to send and receive data
/// </summary>
void OnOpen(WebSocket.WebSocket ws)
{
Text += string.Format("-WebSocket Open!\n");
}
/// <summary>
/// Called when we received a text message from the server
/// </summary>
void OnMessageReceived(WebSocket.WebSocket ws, string message)
{
Text += string.Format("-Message received: {0}\n", message);
}
/// <summary>
/// Called when the web socket closed
/// </summary>
void OnClosed(WebSocket.WebSocket ws, UInt16 code, string message)
{
Text += string.Format("-WebSocket closed! Code: {0} Message: {1}\n", code, message);
webSocket = null;
}
/// <summary>
/// Called when an error occured on client side
/// </summary>
void OnError(WebSocket.WebSocket ws, Exception ex)
{
string errorMsg = string.Empty;
#if !UNITY_WEBGL || UNITY_EDITOR
if (ws.InternalRequest.Response != null)
{
errorMsg = string.Format("Status Code from Server: {0} and Message: {1}", ws.InternalRequest.Response.StatusCode, ws.InternalRequest.Response.Message);
}
#endif
Text += string.Format("-An error occured: {0}\n", (ex != null ? ex.Message : "Unknown Error " + errorMsg));
webSocket = null;
}
#endregion
}
}
#endif

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: e62ab818fc89e124db079d6cc7323474
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: