培训考核三期,新版培训,网页版培训登录器
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

272 lines
7.3 KiB

#if !BESTHTTP_DISABLE_SIGNALR_CORE
using System;
using System.Collections.Generic;
using BestHTTP.PlatformSupport.Memory;
namespace BestHTTP.SignalRCore
{
public enum TransportTypes
{
#if !BESTHTTP_DISABLE_WEBSOCKET
WebSocket,
#endif
LongPolling
}
public enum TransferModes
{
Binary,
Text
}
public enum TransportStates
{
Initial,
Connecting,
Connected,
Closing,
Failed,
Closed
}
/// <summary>
/// Possible states of a HubConnection
/// </summary>
public enum ConnectionStates
{
Initial,
Authenticating,
Negotiating,
Redirected,
Reconnecting,
Connected,
CloseInitiated,
Closed
}
/// <summary>
/// States that a transport can goes trough as seen from 'outside'.
/// </summary>
public enum TransportEvents
{
/// <summary>
/// Transport is selected to try to connect to the server
/// </summary>
SelectedToConnect,
/// <summary>
/// Transport failed to connect to the server. This event can occur after SelectedToConnect, when already connected and an error occurs it will be a ClosedWithError one.
/// </summary>
FailedToConnect,
/// <summary>
/// The transport successfully connected to the server.
/// </summary>
Connected,
/// <summary>
/// Transport gracefully terminated.
/// </summary>
Closed,
/// <summary>
/// Unexpected error occured and the transport can't recover from it.
/// </summary>
ClosedWithError
}
public interface ITransport
{
TransferModes TransferMode { get; }
TransportTypes TransportType { get; }
TransportStates State { get; }
string ErrorReason { get; }
event Action<TransportStates, TransportStates> OnStateChanged;
void StartConnect();
void StartClose();
void Send(BufferSegment bufferSegment);
}
public interface IEncoder
{
BufferSegment Encode<T>(T value);
T DecodeAs<T>(BufferSegment buffer);
object ConvertTo(Type toType, object obj);
}
public sealed class StreamItemContainer<T>
{
public readonly long id;
public List<T> Items { get; private set; }
public T LastAdded { get; private set; }
public bool IsCanceled;
public StreamItemContainer(long _id)
{
this.id = _id;
this.Items = new List<T>();
}
public void AddItem(T item)
{
if (this.Items == null)
this.Items = new List<T>();
this.Items.Add(item);
this.LastAdded = item;
}
}
struct CallbackDescriptor
{
public readonly Type[] ParamTypes;
public readonly Action<object[]> Callback;
public CallbackDescriptor(Type[] paramTypes, Action<object[]> callback)
{
this.ParamTypes = paramTypes;
this.Callback = callback;
}
}
internal struct InvocationDefinition
{
public Action<Messages.Message> callback;
public Type returnType;
}
internal sealed class Subscription
{
public List<CallbackDescriptor> callbacks = new List<CallbackDescriptor>(1);
public void Add(Type[] paramTypes, Action<object[]> callback)
{
this.callbacks.Add(new CallbackDescriptor(paramTypes, callback));
}
public void Remove(Action<object[]> callback)
{
int idx = -1;
for (int i = 0; i < this.callbacks.Count && idx == -1; ++i)
if (this.callbacks[i].Callback == callback)
idx = i;
if (idx != -1)
this.callbacks.RemoveAt(idx);
}
}
public sealed class HubOptions
{
/// <summary>
/// When this is set to true, the plugin will skip the negotiation request if the PreferedTransport is WebSocket. Its default value is false.
/// </summary>
public bool SkipNegotiation { get; set; }
/// <summary>
/// The preferred transport to choose when more than one available. Its default value is TransportTypes.WebSocket.
/// </summary>
public TransportTypes PreferedTransport { get; set; }
/// <summary>
/// A ping message is only sent if the interval has elapsed without a message being sent. Its default value is 15 seconds.
/// </summary>
public TimeSpan PingInterval { get; set; }
/// <summary>
/// If the client doesn't see any message in this interval, considers the connection broken. Its default value is 30 seconds.
/// </summary>
public TimeSpan PingTimeoutInterval { get; set; }
/// <summary>
/// The maximum count of redirect negotiation result that the plugin will follow. Its default value is 100.
/// </summary>
public int MaxRedirects { get; set; }
/// <summary>
/// The maximum time that the plugin allowed to spend trying to connect. Its default value is 1 minute.
/// </summary>
public TimeSpan ConnectTimeout { get; set; }
public HubOptions()
{
this.SkipNegotiation = false;
#if !BESTHTTP_DISABLE_WEBSOCKET
this.PreferedTransport = TransportTypes.WebSocket;
#else
this.PreferedTransport = TransportTypes.LongPolling;
#endif
this.PingInterval = TimeSpan.FromSeconds(15);
this.PingTimeoutInterval = TimeSpan.FromSeconds(30);
this.MaxRedirects = 100;
this.ConnectTimeout = TimeSpan.FromSeconds(60);
}
}
public interface IRetryPolicy
{
/// <summary>
/// This function must return with a delay time to wait until a new connection attempt, or null to do not do another one.
/// </summary>
TimeSpan? GetNextRetryDelay(RetryContext context);
}
public struct RetryContext
{
/// <summary>
/// Previous reconnect attempts. A successful connection sets it back to zero.
/// </summary>
public uint PreviousRetryCount;
/// <summary>
/// Elapsed time since the original connection error.
/// </summary>
public TimeSpan ElapsedTime;
/// <summary>
/// String representation of the connection error.
/// </summary>
public string RetryReason;
}
public sealed class DefaultRetryPolicy : IRetryPolicy
{
private static TimeSpan?[] DefaultBackoffTimes = new TimeSpan?[]
{
TimeSpan.Zero,
TimeSpan.FromSeconds(2),
TimeSpan.FromSeconds(10),
TimeSpan.FromSeconds(30),
null
};
TimeSpan?[] backoffTimes;
public DefaultRetryPolicy()
{
this.backoffTimes = DefaultBackoffTimes;
}
public DefaultRetryPolicy(TimeSpan?[] customBackoffTimes)
{
this.backoffTimes = customBackoffTimes;
}
public TimeSpan? GetNextRetryDelay(RetryContext context)
{
if (context.PreviousRetryCount >= this.backoffTimes.Length)
return null;
return this.backoffTimes[context.PreviousRetryCount];
}
}
}
#endif