209 lines
5.7 KiB
C#
209 lines
5.7 KiB
C#
// This file is part of the EonaCat project(s) which is released under the Apache License.
|
|
// See the LICENSE file or go to https://EonaCat.com/License for full license details.
|
|
|
|
using System;
|
|
using System.IO;
|
|
|
|
namespace EonaCat.Network
|
|
{
|
|
public abstract class WSEndpoint : IWSSession
|
|
{
|
|
private bool _emitOnPing;
|
|
private string _protocol;
|
|
private WSClient _websocket;
|
|
|
|
protected WSEndpoint()
|
|
{
|
|
StartTime = DateTime.MaxValue;
|
|
}
|
|
|
|
public WSContext Context { get; private set; }
|
|
public Func<CookieCollection, CookieCollection, bool> CookiesValidator { get; set; }
|
|
|
|
public bool EmitOnPing
|
|
{
|
|
get
|
|
{
|
|
return _websocket != null ? _websocket.CallMessageOnPing : _emitOnPing;
|
|
}
|
|
|
|
set
|
|
{
|
|
if (_websocket != null)
|
|
{
|
|
_websocket.CallMessageOnPing = value;
|
|
return;
|
|
}
|
|
|
|
_emitOnPing = value;
|
|
}
|
|
}
|
|
|
|
public string ID { get; private set; }
|
|
public bool IgnoreExtensions { get; set; }
|
|
public Func<string, bool> OriginValidator { get; set; }
|
|
|
|
public string Protocol
|
|
{
|
|
get
|
|
{
|
|
return _websocket != null ? _websocket.Protocol : (_protocol ?? string.Empty);
|
|
}
|
|
|
|
set
|
|
{
|
|
if (State != WSState.Connecting)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (value != null && (value.Length == 0 || !value.IsToken()))
|
|
{
|
|
return;
|
|
}
|
|
|
|
_protocol = value;
|
|
}
|
|
}
|
|
|
|
public DateTime StartTime { get; private set; }
|
|
public WSState State => _websocket != null ? _websocket.ReadyState : WSState.Connecting;
|
|
protected WSSessionManager Sessions { get; private set; }
|
|
|
|
internal void Start(WSContext context, WSSessionManager sessions)
|
|
{
|
|
if (_websocket != null)
|
|
{
|
|
Logger.Error("A session instance cannot be reused.");
|
|
context.WebSocket.Close(HttpStatusCode.ServiceUnavailable);
|
|
|
|
return;
|
|
}
|
|
|
|
Context = context;
|
|
Sessions = sessions;
|
|
|
|
_websocket = context.WebSocket;
|
|
_websocket.CustomHandshakeRequestChecker = checkHandshakeRequest;
|
|
_websocket.CallMessageOnPing = _emitOnPing;
|
|
_websocket.IgnoreExtensions = IgnoreExtensions;
|
|
_websocket.Protocol = _protocol;
|
|
|
|
var responseWaitingTime = sessions.ResponseWaitingTime;
|
|
if (responseWaitingTime != _websocket.ResponseWaitingTime)
|
|
{
|
|
_websocket.ResponseWaitingTime = responseWaitingTime;
|
|
}
|
|
|
|
_websocket.OnConnect += onOpen;
|
|
_websocket.OnMessageReceived += onMessage;
|
|
_websocket.OnError += onError;
|
|
_websocket.OnDisconnect += onClose;
|
|
|
|
_websocket.InternalAccept();
|
|
}
|
|
|
|
protected void Error(string message, Exception exception)
|
|
{
|
|
if (message != null && message.Length > 0)
|
|
{
|
|
OnError(new ErrorEventArgs(message, exception));
|
|
}
|
|
}
|
|
|
|
protected virtual void OnClose(CloseEventArgs e)
|
|
{
|
|
}
|
|
|
|
protected virtual void OnError(ErrorEventArgs e)
|
|
{
|
|
}
|
|
|
|
protected virtual void OnMessage(MessageEventArgs e)
|
|
{
|
|
}
|
|
|
|
protected virtual void OnOpen()
|
|
{
|
|
}
|
|
|
|
protected void Send(byte[] data)
|
|
{
|
|
_websocket?.Send(data);
|
|
}
|
|
|
|
protected void Send(FileInfo file)
|
|
{
|
|
_websocket?.Send(file);
|
|
}
|
|
|
|
protected void Send(string data)
|
|
{
|
|
_websocket?.Send(data);
|
|
}
|
|
|
|
protected void SendAsync(byte[] data, Action<bool> completed)
|
|
{
|
|
_websocket?.SendAsync(data, completed);
|
|
}
|
|
|
|
protected void SendAsync(FileInfo file, Action<bool> completed)
|
|
{
|
|
_websocket?.SendAsync(file, completed);
|
|
}
|
|
|
|
protected void SendAsync(string data, Action<bool> completed)
|
|
{
|
|
_websocket?.SendAsync(data, completed);
|
|
}
|
|
|
|
protected void SendAsync(Stream stream, int length, Action<bool> completed)
|
|
{
|
|
_websocket?.SendAsync(stream, length, completed);
|
|
}
|
|
|
|
private string checkHandshakeRequest(WSContext context)
|
|
{
|
|
return OriginValidator != null && !OriginValidator(context.Origin)
|
|
? "Includes no Origin header, or it has an invalid value."
|
|
: CookiesValidator != null
|
|
&& !CookiesValidator(context.CookieCollection, context.WebSocket.CookieCollection)
|
|
? "Includes no cookie, or an invalid cookie exists."
|
|
: null;
|
|
}
|
|
|
|
private void onClose(object sender, CloseEventArgs e)
|
|
{
|
|
if (ID == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Sessions.Remove(ID);
|
|
OnClose(e);
|
|
}
|
|
|
|
private void onError(object sender, ErrorEventArgs e)
|
|
{
|
|
OnError(e);
|
|
}
|
|
|
|
private void onMessage(object sender, MessageEventArgs e)
|
|
{
|
|
OnMessage(e);
|
|
}
|
|
|
|
private void onOpen(object sender, EventArgs e)
|
|
{
|
|
ID = Sessions.Add(this);
|
|
if (ID == null)
|
|
{
|
|
_websocket.Close(CloseStatusCode.Away);
|
|
return;
|
|
}
|
|
|
|
StartTime = DateTime.Now;
|
|
OnOpen();
|
|
}
|
|
}
|
|
} |