using System;
using System.Text;
using System.Threading;
namespace IFramework.Net.WebSocket
{
using IFramework.Net.Tcp;
internal class WSClientProvider : IDisposable, IWSClientProvider
{
TcpClientProvider clientProvider = null;
private Encoding encoding = Encoding.UTF8;
ManualResetEvent resetEvent = new ManualResetEvent(false);
int waitingTimeout = 1000 * 60 * 30;
public bool IsConnected { get; private set; }
AcceptInfo acceptInfo = null;
public OnDisconnectedHandler OnDisconnected{ get; set; }
public OnConnectedHandler OnConnected { get; set; }
public OnReceivedHandler OnReceived { get; set; }
public OnReceivedSegmentHandler OnReceivedBytes { get; set; }
public OnSentHandler OnSent { get; set; }
public WSClientProvider(int bufferSize=4096,int blocks=8)
{
clientProvider = new TcpClientProvider(bufferSize, blocks);
clientProvider.DisconnectedCallback = new OnDisconnectedHandler(DisconnectedHandler);
clientProvider.ReceivedOffsetCallback = new OnReceivedSegmentHandler(ReceivedHanlder);
clientProvider.SentCallback = new OnSentHandler(SentHandler);
}
public void Dispose()
{
resetEvent.Dispose();
}
public static WSClientProvider CreateProvider(int bufferSize = 4096, int blocks = 8)
{
return new WSClientProvider(bufferSize,blocks);
}
///
/// wsUrl:ws://ip:port
///
///
///
public bool Connect(string wsUrl)
{
Random rand = new Random(DateTime.Now.Millisecond);
WSConnectionItem wsItem = new WSConnectionItem(wsUrl);
bool isOk = clientProvider.ConnectTo(wsItem.Port, wsItem.Domain);
if (isOk == false) throw new Exception("连接失败...");
string req = new AccessInfo()
{
Host = wsItem.Host,
Origin = "http://" + wsItem.Host,
SecWebSocketKey = Convert.ToBase64String(encoding.GetBytes(wsUrl + rand.Next(100, 100000).ToString()))
}.ToString();
isOk = clientProvider.Send(new SegmentOffset(encoding.GetBytes(req)));
resetEvent.WaitOne(waitingTimeout);
return IsConnected;
}
public bool Connect(WSConnectionItem wsUrl)
{
return Connect(wsUrl);
}
public bool Send(string msg,bool waiting=true)
{
if (IsConnected == false) return false;
var buf = new WebsocketFrame().ToSegmentFrame(msg);
clientProvider.Send(buf,waiting);
return true;
}
public bool Send(SegmentOffset data,bool waiting=true)
{
if (IsConnected == false) return false;
clientProvider.Send(data,waiting);
return true;
}
public void SendPong(SegmentOffset buf)
{
var seg = new WebsocketFrame().ToSegmentFrame(buf,OpCodeType.Bong);
clientProvider.Send(seg, true);
}
public void SendPing()
{
var buf = new WebsocketFrame().ToSegmentFrame(new byte[] { },OpCodeType.Bing);
clientProvider.Send(buf, true);
}
private void DisconnectedHandler(SocketToken sToken)
{
IsConnected = false;
if (OnDisconnected != null) OnDisconnected(sToken);
}
private void ReceivedHanlder(SegmentToken session)
{
if (IsConnected == false)
{
string msg = encoding.GetString(session.Data.buffer, session.Data.offset, session.Data.size);
acceptInfo = new WebsocketFrame().ParseAcceptedFrame(msg);
if ((IsConnected = acceptInfo.IsHandShaked()))
{
resetEvent.Set();
if (OnConnected != null) OnConnected(session.sToken, IsConnected);
}
else
{
clientProvider.Disconnect();
}
}
else
{
WebsocketFrame packet = new WebsocketFrame();
bool isOk= packet.DecodingFromBytes(session.Data, true);
if (isOk == false) return;
if (packet.OpCode == 0x01)
{
if (OnReceived != null)
OnReceived(session.sToken, encoding.GetString(packet.Payload.buffer,
packet.Payload.offset, packet.Payload.size));
return;
}
else if (packet.OpCode == 0x08)//close
{
IsConnected = false;
clientProvider.Disconnect();
}
else if (packet.OpCode == 0x09)//ping
{
SendPong(session.Data);
}
else if (packet.OpCode == 0x0A)//pong
{
SendPing();
}
if (OnReceivedBytes != null && packet.Payload.size > 0)
OnReceivedBytes(new SegmentToken(session.sToken, packet.Payload));
}
}
private void SentHandler(SegmentToken session)
{
if (OnSent!=null){
OnSent(session);
}
}
//private void ConnectedHandler(SocketToken sToken,bool isConnected)
//{
//}
}
}