using JamesFrowen.SimpleWeb;
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace FishNet.Transporting.Bayou.Client
{
public class ClientSocket : CommonSocket
{
~ClientSocket()
{
StopConnection();
}
#region Private.
#region Configuration.
///
/// Address to bind server to.
///
private string _address = string.Empty;
///
/// Port used by server.
///
private ushort _port;
///
/// MTU sizes for each channel.
///
private int _mtu;
#endregion
#region Queues.
///
/// Outbound messages which need to be handled.
///
private Queue _outgoing = new Queue();
#endregion
///
/// Client socket manager.
///
private SimpleWebClient _client;
#endregion
///
/// Initializes this for use.
///
///
internal void Initialize(Transport t, int mtu)
{
base.Transport = t;
_mtu = mtu;
}
///
/// Threaded operation to process client actions.
///
private void Socket(bool useWss)
{
TcpConfig tcpConfig = new TcpConfig(false, 5000, 20000);
_client = SimpleWebClient.Create(ushort.MaxValue, 5000, tcpConfig);
_client.onConnect += _client_onConnect;
_client.onDisconnect += _client_onDisconnect;
_client.onData += _client_onData;
_client.onError += _client_onError;
string scheme = (useWss) ? "wss" : "ws";
UriBuilder builder = new UriBuilder
{
Scheme = scheme,
Host = _address,
Port = _port
};
base.SetConnectionState(LocalConnectionState.Starting, false);
_client.Connect(builder.Uri);
}
private void _client_onError(Exception obj)
{
StopConnection();
}
private void _client_onData(ArraySegment data)
{
if (_client == null || _client.ConnectionState != ClientState.Connected)
return;
Channel channel;
data = base.RemoveChannel(data, out channel);
ClientReceivedDataArgs dataArgs = new ClientReceivedDataArgs(data, channel, base.Transport.Index);
base.Transport.HandleClientReceivedDataArgs(dataArgs);
}
private void _client_onDisconnect()
{
StopConnection();
}
private void _client_onConnect()
{
base.SetConnectionState(LocalConnectionState.Started, false);
}
///
/// Starts the client connection.
///
///
///
///
///
internal bool StartConnection(string address, ushort port, bool useWss)
{
if (base.GetConnectionState() != LocalConnectionState.Stopped)
return false;
base.SetConnectionState(LocalConnectionState.Starting, false);
//Assign properties.
_port = port;
_address = address;
ResetQueues();
Socket(useWss);
return true;
}
///
/// Stops the local socket.
///
internal bool StopConnection()
{
if (base.GetConnectionState() == LocalConnectionState.Stopped || base.GetConnectionState() == LocalConnectionState.Stopping)
return false;
base.SetConnectionState(LocalConnectionState.Stopping, false);
_client.Disconnect();
base.SetConnectionState(LocalConnectionState.Stopped, false);
return true;
}
///
/// Resets queues.
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ResetQueues()
{
base.ClearPacketQueue(ref _outgoing);
}
///
/// Dequeues and processes outgoing.
///
private void DequeueOutgoing()
{
int count = _outgoing.Count;
for (int i = 0; i < count; i++)
{
Packet outgoing = _outgoing.Dequeue();
base.AddChannel(ref outgoing);
_client.Send(outgoing.GetArraySegment());
outgoing.Dispose();
}
}
///
/// Allows for Outgoing queue to be iterated.
///
internal void IterateOutgoing()
{
DequeueOutgoing();
}
///
/// Iterates the Incoming queue.
///
internal void IterateIncoming()
{
if (_client == null)
return;
/* This has to be called even if not connected because it will also poll events such as
* Connected, or Disconnected, ect. */
_client.ProcessMessageQueue();
}
///
/// Sends a packet to the server.
///
internal void SendToServer(byte channelId, ArraySegment segment)
{
//Not started, cannot send.
if (base.GetConnectionState() != LocalConnectionState.Started)
return;
base.Send(ref _outgoing, channelId, segment, -1);
}
}
}