mirror of
https://github.com/AlexMacocian/MTSC.git
synced 2026-07-22 18:29:31 +00:00
141 lines
5.0 KiB
C#
141 lines
5.0 KiB
C#
using MTSC.Common.Http;
|
|
using MTSC.Common.WebSockets;
|
|
using MTSC.Common.WebSockets.ClientModules;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Security.Cryptography;
|
|
using System.Text;
|
|
|
|
namespace MTSC.Client.Handlers
|
|
{
|
|
/// <summary>
|
|
/// Handler implementing websocket protocol.
|
|
/// </summary>
|
|
public class WebsocketHandler : IHandler
|
|
{
|
|
private static string WebsocketHeaderAcceptKey = "Sec-WebSocket-Accept";
|
|
private static string WebsocketHeaderKey = "Sec-WebSocket-Key";
|
|
private static string WebsocketProtocolKey = "Sec-WebSocket-Protocol";
|
|
private static string WebsocketProtocolVersionKey = "Sec-WebSocket-Version";
|
|
private static string GlobalUniqueIdentifier = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
|
private static SHA1 sha1Provider = SHA1.Create();
|
|
private enum SocketState
|
|
{
|
|
Initial,
|
|
Handshaking,
|
|
Established,
|
|
Closed
|
|
}
|
|
|
|
#region Fields
|
|
SocketState state = SocketState.Initial;
|
|
Queue<byte[]> messageQueue = new Queue<byte[]>();
|
|
List<IWebsocketModule> websocketModules = new List<IWebsocketModule>();
|
|
string expectedguid = string.Empty;
|
|
#endregion
|
|
#region Properties
|
|
public string WebsocketURI { get; set; }
|
|
#endregion
|
|
#region Constructors
|
|
public WebsocketHandler()
|
|
{
|
|
WebsocketURI = "/";
|
|
}
|
|
#endregion
|
|
#region Public Methods
|
|
/// <summary>
|
|
/// Add a module to the websocket handler.
|
|
/// </summary>
|
|
/// <param name="websocketModule">Module to be added.</param>
|
|
/// <returns>This handler object.</returns>
|
|
public WebsocketHandler AddModule(IWebsocketModule websocketModule)
|
|
{
|
|
websocketModules.Add(websocketModule);
|
|
return this;
|
|
}
|
|
/// <summary>
|
|
/// Add a message to the queue to be sent.
|
|
/// </summary>
|
|
/// <param name="message">Message to be sent.</param>
|
|
public void QueueMessage(byte[] message)
|
|
{
|
|
messageQueue.Enqueue(message);
|
|
}
|
|
#endregion
|
|
#region Handler Implementation
|
|
void IHandler.Disconnected(Client client)
|
|
{
|
|
|
|
}
|
|
|
|
bool IHandler.HandleReceivedMessage(Client client, Message message)
|
|
{
|
|
if(state == SocketState.Handshaking)
|
|
{
|
|
HttpMessage response = new HttpMessage();
|
|
response.ParseResponse(message.MessageBytes);
|
|
if(response.StatusCode == HttpMessage.StatusCodes.SwitchingProtocols &&
|
|
response["Upgrade"] == "websocket" &&
|
|
response[HttpMessage.GeneralHeadersEnum.Connection].ToLower() == "upgrade" &&
|
|
response[WebsocketHeaderAcceptKey].Trim() == expectedguid)
|
|
{
|
|
state = SocketState.Established;
|
|
}
|
|
return true;
|
|
}
|
|
else if(state == SocketState.Established)
|
|
{
|
|
WebsocketMessage receivedMessage = new WebsocketMessage(message.MessageBytes);
|
|
foreach(IWebsocketModule websocketModule in websocketModules)
|
|
{
|
|
if(websocketModule.HandleReceivedMessage(client, this, receivedMessage))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool IHandler.HandleSendMessage(Client client, ref Message message)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool IHandler.InitializeConnection(Client client)
|
|
{
|
|
state = SocketState.Handshaking;
|
|
string handshakeGuid = Guid.NewGuid().ToString();
|
|
string handshakeKey = handshakeGuid+ GlobalUniqueIdentifier;
|
|
expectedguid = Convert.ToBase64String(sha1Provider.ComputeHash(Encoding.UTF8.GetBytes(handshakeKey)));
|
|
HttpMessage beginRequest = new HttpMessage();
|
|
beginRequest.Method = HttpMessage.MethodEnum.Get;
|
|
beginRequest.RequestURI = WebsocketURI;
|
|
beginRequest[HttpMessage.RequestHeadersEnum.Host] = client.Address;
|
|
beginRequest[HttpMessage.GeneralHeadersEnum.Connection] = "Upgrade";
|
|
beginRequest[WebsocketHeaderKey] = handshakeGuid;
|
|
beginRequest["Origin"] = client.Address;
|
|
beginRequest[WebsocketProtocolKey] = "chat";
|
|
beginRequest[WebsocketProtocolVersionKey] = "13";
|
|
client.QueueMessage(beginRequest.GetRequest());
|
|
return true;
|
|
}
|
|
|
|
bool IHandler.PreHandleReceivedMessage(Client client, ref Message message)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
void IHandler.Tick(Client client)
|
|
{
|
|
while(messageQueue.Count > 0)
|
|
{
|
|
byte[] message = messageQueue.Dequeue();
|
|
client.QueueMessage(message);
|
|
}
|
|
}
|
|
#endregion
|
|
}
|
|
}
|