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); } } }