mirror of
https://gitee.com/jisol/jisol-game/
synced 2025-11-11 08:38:45 +00:00
提交帧同步案例
This commit is contained in:
7
JNFrame/Assets/Plugins/BestHTTP/Examples/HTTP.meta
Normal file
7
JNFrame/Assets/Plugins/BestHTTP/Examples/HTTP.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 56badbd91a344cf49b819809ce60c94a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,195 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using UnityEngine;
|
||||
using BestHTTP;
|
||||
|
||||
namespace BestHTTP.Examples
|
||||
{
|
||||
public sealed class AssetBundleSample : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// The url of the resource to download
|
||||
/// </summary>
|
||||
private Uri URI = new Uri(GUIHelper.BaseURL + "/AssetBundles/WebGL/demobundle.assetbundle");
|
||||
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Debug status text
|
||||
/// </summary>
|
||||
string status = "Waiting for user interaction";
|
||||
|
||||
/// <summary>
|
||||
/// The downloaded and cached AssetBundle
|
||||
/// </summary>
|
||||
AssetBundle cachedBundle;
|
||||
|
||||
/// <summary>
|
||||
/// The loaded texture from the AssetBundle
|
||||
/// </summary>
|
||||
Texture2D texture;
|
||||
|
||||
/// <summary>
|
||||
/// A flag that indicates that we are processing the request/bundle to hide the "Start Download" button.
|
||||
/// </summary>
|
||||
bool downloading;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unity Events
|
||||
|
||||
void OnGUI()
|
||||
{
|
||||
GUIHelper.DrawArea(GUIHelper.ClientArea, true, () =>
|
||||
{
|
||||
GUILayout.Label("Status: " + status);
|
||||
|
||||
// Draw the texture from the downloaded bundle
|
||||
if (texture != null)
|
||||
GUILayout.Box(texture, GUILayout.MaxHeight(256));
|
||||
|
||||
if (!downloading && GUILayout.Button("Start Download"))
|
||||
{
|
||||
UnloadBundle();
|
||||
|
||||
StartCoroutine(DownloadAssetBundle());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
UnloadBundle();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Helper Functions
|
||||
|
||||
IEnumerator DownloadAssetBundle()
|
||||
{
|
||||
downloading = true;
|
||||
|
||||
// Create and send our request
|
||||
var request = new HTTPRequest(URI).Send();
|
||||
|
||||
status = "Download started";
|
||||
|
||||
// Wait while it's finishes and add some fancy dots to display something while the user waits for it.
|
||||
// A simple "yield return StartCoroutine(request);" would do the job too.
|
||||
while (request.State < HTTPRequestStates.Finished)
|
||||
{
|
||||
yield return new WaitForSeconds(0.1f);
|
||||
|
||||
status += ".";
|
||||
}
|
||||
|
||||
// Check the outcome of our request.
|
||||
switch (request.State)
|
||||
{
|
||||
// The request finished without any problem.
|
||||
case HTTPRequestStates.Finished:
|
||||
|
||||
if (request.Response.IsSuccess)
|
||||
{
|
||||
#if !BESTHTTP_DISABLE_CACHING
|
||||
status = string.Format("AssetBundle downloaded! Loaded from local cache: {0}", request.Response.IsFromCache.ToString());
|
||||
#else
|
||||
status = "AssetBundle downloaded!";
|
||||
#endif
|
||||
|
||||
// Start creating the downloaded asset bundle
|
||||
AssetBundleCreateRequest async =
|
||||
#if UNITY_5_3_OR_NEWER
|
||||
AssetBundle.LoadFromMemoryAsync(request.Response.Data);
|
||||
#else
|
||||
AssetBundle.CreateFromMemory(request.Response.Data);
|
||||
#endif
|
||||
|
||||
// wait for it
|
||||
yield return async;
|
||||
|
||||
// And process the bundle
|
||||
yield return StartCoroutine(ProcessAssetBundle(async.assetBundle));
|
||||
}
|
||||
else
|
||||
{
|
||||
status = string.Format("Request finished Successfully, but the server sent an error. Status Code: {0}-{1} Message: {2}",
|
||||
request.Response.StatusCode,
|
||||
request.Response.Message,
|
||||
request.Response.DataAsText);
|
||||
Debug.LogWarning(status);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// The request finished with an unexpected error. The request's Exception property may contain more info about the error.
|
||||
case HTTPRequestStates.Error:
|
||||
status = "Request Finished with Error! " + (request.Exception != null ? (request.Exception.Message + "\n" + request.Exception.StackTrace) : "No Exception");
|
||||
Debug.LogError(status);
|
||||
break;
|
||||
|
||||
// The request aborted, initiated by the user.
|
||||
case HTTPRequestStates.Aborted:
|
||||
status = "Request Aborted!";
|
||||
Debug.LogWarning(status);
|
||||
break;
|
||||
|
||||
// Connecting to the server is timed out.
|
||||
case HTTPRequestStates.ConnectionTimedOut:
|
||||
status = "Connection Timed Out!";
|
||||
Debug.LogError(status);
|
||||
break;
|
||||
|
||||
// The request didn't finished in the given time.
|
||||
case HTTPRequestStates.TimedOut:
|
||||
status = "Processing the request Timed Out!";
|
||||
Debug.LogError(status);
|
||||
break;
|
||||
}
|
||||
|
||||
downloading = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// In this function we can do whatever we want with the freshly downloaded bundle.
|
||||
/// In this example we will cache it for later use, and we will load a texture from it.
|
||||
/// </summary>
|
||||
IEnumerator ProcessAssetBundle(AssetBundle bundle)
|
||||
{
|
||||
if (bundle == null)
|
||||
yield break;
|
||||
|
||||
// Save the bundle for future use
|
||||
cachedBundle = bundle;
|
||||
|
||||
// Start loading the asset from the bundle
|
||||
var asyncAsset =
|
||||
#if UNITY_5_1 || UNITY_5_2 || UNITY_5_3_OR_NEWER
|
||||
cachedBundle.LoadAssetAsync("9443182_orig", typeof(Texture2D));
|
||||
#else
|
||||
|
||||
cachedBundle.LoadAsync("9443182_orig", typeof(Texture2D));
|
||||
#endif
|
||||
|
||||
// wait til load
|
||||
yield return asyncAsset;
|
||||
|
||||
// get the texture
|
||||
texture = asyncAsset.asset as Texture2D;
|
||||
}
|
||||
|
||||
void UnloadBundle()
|
||||
{
|
||||
if (cachedBundle != null)
|
||||
{
|
||||
cachedBundle.Unload(true);
|
||||
cachedBundle = null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 03eab9c6191c5cd4c9613084e817bd29
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,244 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using UnityEngine;
|
||||
using BestHTTP;
|
||||
|
||||
namespace BestHTTP.Examples
|
||||
{
|
||||
public sealed class LargeFileDownloadSample : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// The url of the resource to download
|
||||
/// </summary>
|
||||
const string URL = "https://uk3.testmy.net/dl-102400";
|
||||
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Cached request to be able to abort it
|
||||
/// </summary>
|
||||
HTTPRequest request;
|
||||
|
||||
/// <summary>
|
||||
/// Debug status of the request
|
||||
/// </summary>
|
||||
string status = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Download(processing) progress. Its range is between [0..1]
|
||||
/// </summary>
|
||||
float progress;
|
||||
|
||||
/// <summary>
|
||||
/// The fragment size that we will set to the request
|
||||
/// </summary>
|
||||
int fragmentSize = HTTPResponse.MinBufferSize;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unity Events
|
||||
|
||||
void Awake()
|
||||
{
|
||||
// If we have a non-finished download, set the progress to the value where we left it
|
||||
if (PlayerPrefs.HasKey("DownloadLength"))
|
||||
progress = PlayerPrefs.GetInt("DownloadProgress") / (float)PlayerPrefs.GetInt("DownloadLength");
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
// Stop the download if we are leaving this example
|
||||
if (request != null && request.State < HTTPRequestStates.Finished)
|
||||
{
|
||||
request.OnProgress = null;
|
||||
request.Callback = null;
|
||||
request.Abort();
|
||||
}
|
||||
}
|
||||
|
||||
void OnGUI()
|
||||
{
|
||||
GUIHelper.DrawArea(GUIHelper.ClientArea, true, () =>
|
||||
{
|
||||
// Draw the current status
|
||||
GUILayout.Label("Request status: " + status);
|
||||
|
||||
GUILayout.Space(5);
|
||||
|
||||
// Draw the current progress
|
||||
GUILayout.Label(string.Format("Progress: {0:P2} of {1:N0}Mb", progress, PlayerPrefs.GetInt("DownloadLength") / 1048576 /*1 Mb*/));
|
||||
GUILayout.HorizontalSlider(progress, 0, 1);
|
||||
|
||||
GUILayout.Space(50);
|
||||
|
||||
if (request == null)
|
||||
{
|
||||
// Draw a slider to be able to change the fragment size
|
||||
GUILayout.Label(string.Format("Desired Fragment Size: {0:N} KBytes", fragmentSize / 1024f));
|
||||
fragmentSize = (int)GUILayout.HorizontalSlider(fragmentSize, HTTPResponse.MinBufferSize, 10 * 1024 * 1024);
|
||||
|
||||
GUILayout.Space(5);
|
||||
|
||||
string buttonStr = PlayerPrefs.HasKey("DownloadProgress") ? "Continue Download" : "Start Download";
|
||||
if (GUILayout.Button(buttonStr))
|
||||
StreamLargeFileTest();
|
||||
}
|
||||
else if (request.State == HTTPRequestStates.Processing && GUILayout.Button("Abort Download"))
|
||||
{
|
||||
// Simulate a connection lost
|
||||
request.Abort();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Helper Functions
|
||||
|
||||
// Calling this function again when the "DownloadProgress" key in the PlayerPrefs present will
|
||||
// continue the download
|
||||
void StreamLargeFileTest()
|
||||
{
|
||||
request = new HTTPRequest(new Uri(URL), (req, resp) =>
|
||||
{
|
||||
switch (req.State)
|
||||
{
|
||||
// The request is currently processed. With UseStreaming == true, we can get the streamed fragments here
|
||||
case HTTPRequestStates.Processing:
|
||||
|
||||
// Set the DownloadLength, so we can display the progress
|
||||
if (!PlayerPrefs.HasKey("DownloadLength"))
|
||||
{
|
||||
string value = resp.GetFirstHeaderValue("content-length");
|
||||
if (!string.IsNullOrEmpty(value))
|
||||
PlayerPrefs.SetInt("DownloadLength", int.Parse(value));
|
||||
}
|
||||
|
||||
// Get the fragments, and save them
|
||||
ProcessFragments(resp.GetStreamedFragments());
|
||||
|
||||
status = "Processing";
|
||||
break;
|
||||
|
||||
// The request finished without any problem.
|
||||
case HTTPRequestStates.Finished:
|
||||
if (resp.IsSuccess)
|
||||
{
|
||||
// Save any remaining fragments
|
||||
ProcessFragments(resp.GetStreamedFragments());
|
||||
|
||||
// Completely finished
|
||||
if (resp.IsStreamingFinished)
|
||||
{
|
||||
status = "Streaming finished!";
|
||||
|
||||
// We are done, delete the progress key
|
||||
PlayerPrefs.DeleteKey("DownloadProgress");
|
||||
PlayerPrefs.Save();
|
||||
|
||||
request = null;
|
||||
}
|
||||
else
|
||||
status = "Processing";
|
||||
}
|
||||
else
|
||||
{
|
||||
status = string.Format("Request finished Successfully, but the server sent an error. Status Code: {0}-{1} Message: {2}",
|
||||
resp.StatusCode,
|
||||
resp.Message,
|
||||
resp.DataAsText);
|
||||
Debug.LogWarning(status);
|
||||
|
||||
request = null;
|
||||
}
|
||||
break;
|
||||
|
||||
// The request finished with an unexpected error. The request's Exception property may contain more info about the error.
|
||||
case HTTPRequestStates.Error:
|
||||
status = "Request Finished with Error! " + (req.Exception != null ? (req.Exception.Message + "\n" + req.Exception.StackTrace) : "No Exception");
|
||||
Debug.LogError(status);
|
||||
|
||||
request = null;
|
||||
break;
|
||||
|
||||
// The request aborted, initiated by the user.
|
||||
case HTTPRequestStates.Aborted:
|
||||
status = "Request Aborted!";
|
||||
Debug.LogWarning(status);
|
||||
|
||||
request = null;
|
||||
break;
|
||||
|
||||
// Connecting to the server is timed out.
|
||||
case HTTPRequestStates.ConnectionTimedOut:
|
||||
status = "Connection Timed Out!";
|
||||
Debug.LogError(status);
|
||||
|
||||
request = null;
|
||||
break;
|
||||
|
||||
// The request didn't finished in the given time.
|
||||
case HTTPRequestStates.TimedOut:
|
||||
status = "Processing the request Timed Out!";
|
||||
Debug.LogError(status);
|
||||
|
||||
request = null;
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
// Are there any progress, that we can continue?
|
||||
if (PlayerPrefs.HasKey("DownloadProgress"))
|
||||
// Set the range header
|
||||
request.SetRangeHeader(PlayerPrefs.GetInt("DownloadProgress"));
|
||||
else
|
||||
// This is a new request
|
||||
PlayerPrefs.SetInt("DownloadProgress", 0);
|
||||
|
||||
#if !BESTHTTP_DISABLE_CACHING
|
||||
// If we are writing our own file set it true(disable), so don't duplicate it on the file-system
|
||||
request.DisableCache = true;
|
||||
#endif
|
||||
|
||||
// We want to access the downloaded bytes while we are still downloading
|
||||
request.UseStreaming = true;
|
||||
|
||||
// Set a reasonable high fragment size. Here it is 5 megabytes.
|
||||
request.StreamFragmentSize = fragmentSize;
|
||||
|
||||
// Start Processing the request
|
||||
request.Send();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// In this function we can do whatever we want with the downloaded bytes. In this sample we will do nothing, just set the metadata to display progress.
|
||||
/// </summary>
|
||||
void ProcessFragments(List<byte[]> fragments)
|
||||
{
|
||||
if (fragments != null && fragments.Count > 0)
|
||||
{
|
||||
/*string dir = "TODO!";
|
||||
string filename = "TODO!";
|
||||
|
||||
using (System.IO.FileStream fs = new System.IO.FileStream(System.IO.Path.Combine(dir, filename), System.IO.FileMode.Append))
|
||||
for (int i = 0; i < fragments.Count; ++i)
|
||||
fs.Write(fragments[i], 0, fragments[i].Length);*/
|
||||
|
||||
for (int i = 0; i < fragments.Count; ++i)
|
||||
{
|
||||
// Save how many bytes we wrote successfully
|
||||
int downloaded = PlayerPrefs.GetInt("DownloadProgress") + fragments[i].Length;
|
||||
PlayerPrefs.SetInt("DownloadProgress", downloaded);
|
||||
}
|
||||
|
||||
PlayerPrefs.Save();
|
||||
|
||||
// Set the progress to the actually processed bytes
|
||||
progress = PlayerPrefs.GetInt("DownloadProgress") / (float)PlayerPrefs.GetInt("DownloadLength");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 972fc2301f87c9e46bfb5523f2bc5090
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,181 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using UnityEngine;
|
||||
using BestHTTP;
|
||||
|
||||
namespace BestHTTP.Examples
|
||||
{
|
||||
public sealed class TextureDownloadSample : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// The URL of the server that will serve the image resources
|
||||
/// </summary>
|
||||
string BaseURL = GUIHelper.BaseURL + "/images/Demo/";
|
||||
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// The downloadable images
|
||||
/// </summary>
|
||||
string[] Images = new string[9] { "One.png", "Two.png", "Three.png", "Four.png", "Five.png", "Six.png", "Seven.png", "Eight.png", "Nine.png" };
|
||||
|
||||
/// <summary>
|
||||
/// The downloaded images will be stored as textures in this array
|
||||
/// </summary>
|
||||
Texture2D[] Textures = new Texture2D[9];
|
||||
|
||||
#if !BESTHTTP_DISABLE_CACHING
|
||||
/// <summary>
|
||||
/// True if all images are loaded from the local cache instead of the server
|
||||
/// </summary>
|
||||
bool allDownloadedFromLocalCache;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// How many sent requests are finished
|
||||
/// </summary>
|
||||
int finishedCount;
|
||||
|
||||
/// <summary>
|
||||
/// GUI scroll position
|
||||
/// </summary>
|
||||
Vector2 scrollPos;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unity Events
|
||||
|
||||
void Awake()
|
||||
{
|
||||
// Set a well observable value
|
||||
// This is how many concurrent requests can be made to a server
|
||||
HTTPManager.MaxConnectionPerServer = 1;
|
||||
|
||||
// Create placeholder textures
|
||||
for (int i = 0; i < Images.Length; ++i)
|
||||
Textures[i] = new Texture2D(100, 150);
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
// Set back to its defualt value.
|
||||
HTTPManager.MaxConnectionPerServer = 4;
|
||||
}
|
||||
|
||||
void OnGUI()
|
||||
{
|
||||
GUIHelper.DrawArea(GUIHelper.ClientArea, true, () =>
|
||||
{
|
||||
scrollPos = GUILayout.BeginScrollView(scrollPos);
|
||||
|
||||
// Draw out the textures
|
||||
GUILayout.SelectionGrid(0, Textures, 3);
|
||||
|
||||
#if !BESTHTTP_DISABLE_CACHING
|
||||
if (finishedCount == Images.Length && allDownloadedFromLocalCache)
|
||||
GUIHelper.DrawCenteredText("All images loaded from the local cache!");
|
||||
#endif
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Label("Max Connection/Server: ", GUILayout.Width(150));
|
||||
GUILayout.Label(HTTPManager.MaxConnectionPerServer.ToString(), GUILayout.Width(20));
|
||||
HTTPManager.MaxConnectionPerServer = (byte)GUILayout.HorizontalSlider(HTTPManager.MaxConnectionPerServer, 1, 10);
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
if (GUILayout.Button("Start Download"))
|
||||
DownloadImages();
|
||||
|
||||
GUILayout.EndScrollView();
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Helper Functions
|
||||
|
||||
void DownloadImages()
|
||||
{
|
||||
// Set these metadatas to its initial values
|
||||
#if !BESTHTTP_DISABLE_CACHING
|
||||
allDownloadedFromLocalCache = true;
|
||||
#endif
|
||||
finishedCount = 0;
|
||||
|
||||
for (int i = 0; i < Images.Length; ++i)
|
||||
{
|
||||
// Set a blank placeholder texture, overriding previously downloaded texture
|
||||
Textures[i] = new Texture2D(100, 150);
|
||||
|
||||
// Construct the request
|
||||
var request = new HTTPRequest(new Uri(BaseURL + Images[i]), ImageDownloaded);
|
||||
|
||||
// Set the Tag property, we can use it as a general storage bound to the request
|
||||
request.Tag = Textures[i];
|
||||
|
||||
// Send out the request
|
||||
request.Send();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Callback function of the image download http requests
|
||||
/// </summary>
|
||||
void ImageDownloaded(HTTPRequest req, HTTPResponse resp)
|
||||
{
|
||||
// Increase the finished count regardless of the state of our request
|
||||
finishedCount++;
|
||||
|
||||
switch (req.State)
|
||||
{
|
||||
// The request finished without any problem.
|
||||
case HTTPRequestStates.Finished:
|
||||
if (resp.IsSuccess)
|
||||
{
|
||||
// Get the Texture from the Tag property
|
||||
Texture2D tex = req.Tag as Texture2D;
|
||||
|
||||
// Load the texture
|
||||
tex.LoadImage(resp.Data);
|
||||
|
||||
#if !BESTHTTP_DISABLE_CACHING
|
||||
// Update the cache-info variable
|
||||
allDownloadedFromLocalCache = allDownloadedFromLocalCache && resp.IsFromCache;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning(string.Format("Request finished Successfully, but the server sent an error. Status Code: {0}-{1} Message: {2}",
|
||||
resp.StatusCode,
|
||||
resp.Message,
|
||||
resp.DataAsText));
|
||||
}
|
||||
break;
|
||||
|
||||
// The request finished with an unexpected error. The request's Exception property may contain more info about the error.
|
||||
case HTTPRequestStates.Error:
|
||||
Debug.LogError("Request Finished with Error! " + (req.Exception != null ? (req.Exception.Message + "\n" + req.Exception.StackTrace) : "No Exception"));
|
||||
break;
|
||||
|
||||
// The request aborted, initiated by the user.
|
||||
case HTTPRequestStates.Aborted:
|
||||
Debug.LogWarning("Request Aborted!");
|
||||
break;
|
||||
|
||||
// Connecting to the server is timed out.
|
||||
case HTTPRequestStates.ConnectionTimedOut:
|
||||
Debug.LogError("Connection Timed Out!");
|
||||
break;
|
||||
|
||||
// The request didn't finished in the given time.
|
||||
case HTTPRequestStates.TimedOut:
|
||||
Debug.LogError("Processing the request Timed Out!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: af6ffe2bbf96d2b49ba3ef0713511d45
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
222
JNFrame/Assets/Plugins/BestHTTP/Examples/HTTP/UploadStream.cs
Normal file
222
JNFrame/Assets/Plugins/BestHTTP/Examples/HTTP/UploadStream.cs
Normal file
@@ -0,0 +1,222 @@
|
||||
using BestHTTP;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
|
||||
namespace BestHTTP.Examples
|
||||
{
|
||||
public sealed class UploadStream : Stream
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Buffer for reads
|
||||
/// </summary>
|
||||
MemoryStream ReadBuffer = new MemoryStream();
|
||||
|
||||
/// <summary>
|
||||
/// Buffer for writes
|
||||
/// </summary>
|
||||
MemoryStream WriteBuffer = new MemoryStream();
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that we will not write more data to this stream
|
||||
/// </summary>
|
||||
bool noMoreData;
|
||||
|
||||
/// <summary>
|
||||
/// For thread synchronization
|
||||
/// </summary>
|
||||
AutoResetEvent ARE = new AutoResetEvent(false);
|
||||
|
||||
/// <summary>
|
||||
/// For thread synchronization
|
||||
/// </summary>
|
||||
object locker = new object();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Name of this stream for easier debugging
|
||||
/// </summary>
|
||||
public string Name { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// true if we are read all data from the read buffer
|
||||
/// </summary>
|
||||
private bool IsReadBufferEmpty { get { lock (locker) return ReadBuffer.Position == ReadBuffer.Length; } }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public UploadStream(string name)
|
||||
: this()
|
||||
{
|
||||
this.Name = name;
|
||||
}
|
||||
|
||||
public UploadStream()
|
||||
{
|
||||
this.ReadBuffer = new MemoryStream();
|
||||
this.WriteBuffer = new MemoryStream();
|
||||
this.Name = string.Empty;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Stream Implementation
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
// We will not push more data to the write buffer
|
||||
if (noMoreData)
|
||||
{
|
||||
// No data left in the read buffer
|
||||
if (ReadBuffer.Position == ReadBuffer.Length)
|
||||
{
|
||||
// Is there any data in the write buffer? If so, switch the buffers
|
||||
if (WriteBuffer.Length > 0)
|
||||
SwitchBuffers();
|
||||
else
|
||||
{
|
||||
HTTPManager.Logger.Information("UploadStream", string.Format("{0} - Read - End Of Stream", this.Name));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
return ReadBuffer.Read(buffer, offset, count);
|
||||
}
|
||||
|
||||
// There are no more data in the read buffer? Wait for it.
|
||||
if (IsReadBufferEmpty)
|
||||
{
|
||||
ARE.WaitOne();
|
||||
|
||||
lock (locker)
|
||||
if (IsReadBufferEmpty && WriteBuffer.Length > 0)
|
||||
SwitchBuffers();
|
||||
}
|
||||
|
||||
int read = -1;
|
||||
|
||||
lock (locker)
|
||||
read = ReadBuffer.Read(buffer, offset, count);
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (noMoreData)
|
||||
throw new System.ArgumentException("noMoreData already set!");
|
||||
|
||||
lock (locker)
|
||||
{
|
||||
WriteBuffer.Write(buffer, offset, count);
|
||||
|
||||
SwitchBuffers();
|
||||
}
|
||||
|
||||
ARE.Set();
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
Finish();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Dispose Implementation
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
HTTPManager.Logger.Information("UploadStream", string.Format("{0} - Dispose", this.Name));
|
||||
|
||||
ReadBuffer.Dispose();
|
||||
ReadBuffer = null;
|
||||
|
||||
WriteBuffer.Dispose();
|
||||
WriteBuffer = null;
|
||||
|
||||
#if NETFX_CORE
|
||||
ARE.Dispose();
|
||||
#else
|
||||
ARE.Close();
|
||||
#endif
|
||||
ARE = null;
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helper Functions
|
||||
|
||||
public void Finish()
|
||||
{
|
||||
if (noMoreData)
|
||||
throw new System.ArgumentException("noMoreData already set!");
|
||||
|
||||
HTTPManager.Logger.Information("UploadStream", string.Format("{0} - Finish", this.Name));
|
||||
|
||||
noMoreData = true;
|
||||
|
||||
ARE.Set();
|
||||
}
|
||||
|
||||
private bool SwitchBuffers()
|
||||
{
|
||||
// Switch the buffers only when all data are consumed from our read buffer
|
||||
lock (locker)
|
||||
{
|
||||
if (ReadBuffer.Position == ReadBuffer.Length)
|
||||
{
|
||||
// This buffer will be the read buffer, we need to seek back to the beginning
|
||||
WriteBuffer.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
// This will be the write buffer, set the length to zero
|
||||
ReadBuffer.SetLength(0);
|
||||
|
||||
// switch the two buffers
|
||||
MemoryStream tmp = WriteBuffer;
|
||||
WriteBuffer = ReadBuffer;
|
||||
ReadBuffer = tmp;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Not Implemented Functions and Properties
|
||||
|
||||
public override bool CanRead { get { throw new NotImplementedException(); } }
|
||||
public override bool CanSeek { get { throw new NotImplementedException(); } }
|
||||
public override bool CanWrite { get { throw new NotImplementedException(); } }
|
||||
|
||||
public override long Length { get { throw new NotImplementedException(); } }
|
||||
public override long Position { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } }
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a2ab021301a7baf45a80b5a46275a140
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
7
JNFrame/Assets/Plugins/BestHTTP/Examples/Helpers.meta
Normal file
7
JNFrame/Assets/Plugins/BestHTTP/Examples/Helpers.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 61ccf02e2b33b974b9bc1bfd84f2610c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
101
JNFrame/Assets/Plugins/BestHTTP/Examples/Helpers/GUIHelper.cs
Normal file
101
JNFrame/Assets/Plugins/BestHTTP/Examples/Helpers/GUIHelper.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fd560ff6f0fa60844a43a82db1ad03be
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
7
JNFrame/Assets/Plugins/BestHTTP/Examples/LitJson.meta
Normal file
7
JNFrame/Assets/Plugins/BestHTTP/Examples/LitJson.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e1e93ac0ec69bb948b0485b8ae204cee
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: db4954c0960d19d4996b2ad47fdc364d
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
1004
JNFrame/Assets/Plugins/BestHTTP/Examples/LitJson/JsonData.cs
Normal file
1004
JNFrame/Assets/Plugins/BestHTTP/Examples/LitJson/JsonData.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d992e71a7032d1c458a25f6effb6e03d
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2d8be66110036ea4782540091a745448
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
1014
JNFrame/Assets/Plugins/BestHTTP/Examples/LitJson/JsonMapper.cs
Normal file
1014
JNFrame/Assets/Plugins/BestHTTP/Examples/LitJson/JsonMapper.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cd3700150c3fb4d4aa8f68e160243328
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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) {}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 21c195443705c59408ba7baf2d2b3175
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
464
JNFrame/Assets/Plugins/BestHTTP/Examples/LitJson/JsonReader.cs
Normal file
464
JNFrame/Assets/Plugins/BestHTTP/Examples/LitJson/JsonReader.cs
Normal 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]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f93d78475ddbea54e9f40b76a8813968
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
463
JNFrame/Assets/Plugins/BestHTTP/Examples/LitJson/JsonWriter.cs
Normal file
463
JNFrame/Assets/Plugins/BestHTTP/Examples/LitJson/JsonWriter.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 902e614ca1244e2478d32eef3bd0d68e
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
912
JNFrame/Assets/Plugins/BestHTTP/Examples/LitJson/Lexer.cs
Normal file
912
JNFrame/Assets/Plugins/BestHTTP/Examples/LitJson/Lexer.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 906778e065bdcac499e4d8a01871e594
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e0f6927815038254080d13c1ab81506b
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
7
JNFrame/Assets/Plugins/BestHTTP/Examples/Plugin.meta
Normal file
7
JNFrame/Assets/Plugins/BestHTTP/Examples/Plugin.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e4b189b8db53fae40b63e2563cc658ba
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 502d4f4ff21e26a4d8d19e12ba63e376
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
298
JNFrame/Assets/Plugins/BestHTTP/Examples/SampleSelector.cs
Normal file
298
JNFrame/Assets/Plugins/BestHTTP/Examples/SampleSelector.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8265be5da926116458a8948712d2eddb
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
286
JNFrame/Assets/Plugins/BestHTTP/Examples/SampleSelector.unity
Normal file
286
JNFrame/Assets/Plugins/BestHTTP/Examples/SampleSelector.unity
Normal 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}
|
||||
@@ -0,0 +1,6 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5ed13563a809f06489c3e97e4da02176
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
7
JNFrame/Assets/Plugins/BestHTTP/Examples/SignalR.meta
Normal file
7
JNFrame/Assets/Plugins/BestHTTP/Examples/SignalR.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d69707652d0d406448aedf33b807bf6d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9286baa677f488b4bb493dd5436147c6
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 48a74a50eeb07bb4ea649a902e9d487a
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5ebd4ce02d369a6498f9be6bb7141ac3
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 02921d1602244e44cbd5103f972bf1fb
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 872d6dfdac0e67f4d910376205532bc0
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0d5b759afc726754fb1e1d49d529bae5
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 55779d2699b42c34ab1549c70402d294
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1c996438e0be72649b8abf5fbdee3f41
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 653a0f163689052438748b7beda14886
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2870a746a601b8b439c495ff39474385
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0eb1f1efe4749fc489977765e40a04e4
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
10
JNFrame/Assets/Plugins/BestHTTP/Examples/SignalRCore.meta
Normal file
10
JNFrame/Assets/Plugins/BestHTTP/Examples/SignalRCore.meta
Normal file
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f7ff75ba203704d45bf1098536a2db5a
|
||||
folderAsset: yes
|
||||
timeCreated: 1515401610
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9e87559ef678942428f064af598c1696
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 80b2246c164414c468eea4f0550eb9ad
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 35c592488a6dbbc4a96c1739cd74046c
|
||||
folderAsset: yes
|
||||
timeCreated: 1515401610
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
@@ -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:
|
||||
@@ -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
|
||||
@@ -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:
|
||||
@@ -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
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1fe4434eade98e547aca1e026a4dbcc3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a0d6f71c9108b3b419ee412fa4ddd018
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bfb23ec912f317944b34485c85ab6b31
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: febf35a5598c76843a7573e8f650079e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6bd28a72bf1727542937e09ab435abcc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
7
JNFrame/Assets/Plugins/BestHTTP/Examples/SocketIO.meta
Normal file
7
JNFrame/Assets/Plugins/BestHTTP/Examples/SocketIO.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6d952d96253d7454992111c6a4116837
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 745fcd55afb34e4429897e798738aebd
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c2d9c71662df0b641980b51cd68443fa
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0329bd6a6be04394b9da7576fc41d1dc
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: feaffc82c9b6aa54ba0e8bf6572d279e
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3ce53a6e4419d8f429db4a753d71a0c2
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
7
JNFrame/Assets/Plugins/BestHTTP/Examples/Websocket.meta
Normal file
7
JNFrame/Assets/Plugins/BestHTTP/Examples/Websocket.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3f80c43b87778214daf5495f2854dfe0
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e62ab818fc89e124db079d6cc7323474
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user