/// <summary>
 /// The only unmanaged resource here is the client, so get rid of them.
 /// </summary>
 /// <remarks>Call <see cref="Dispose"/> when you are finished using the <see cref="MyWebSocket.WebSocketSpinner"/>. The
 /// <see cref="Dispose"/> method leaves the <see cref="MyWebSocket.WebSocketSpinner"/> in an unusable state. After
 /// calling <see cref="Dispose"/>, you must release all references to the
 /// <see cref="MyWebSocket.WebSocketSpinner"/> so the garbage collector can reclaim the memory that the
 /// <see cref="MyWebSocket.WebSocketSpinner"/> was occupying.</remarks>
 public void Dispose()
 {
    if (client != null)
    {
       client.Dispose();
       client = null;
    }
 }
      public WebSocketConnection(WebSocketClient supportingClient, WebSocketUser newUser, Logger logger) //, WebSocketSettings settings, WebSocketUser newUser)
      {
         client = supportingClient;
         this.logger = logger;
         ID = GenerateID();

         User = newUser;

         fragmentBuffer = new byte[Client.MaxReceiveSize];
      }
      public WebSocketSpinner(WebSocketClient supportingClient, WebSocketUser newUser, WebSocketSettings settings) 
         : base("WebsocketSpinner", settings.ShutdownTimeout)
      {
         connection = new WebSocketConnection(supportingClient, newUser, settings.LogProvider);
         this.settings = settings;

         //Fix up the user so it does what we want.
         User.SetSendPlaceholder((message) =>
         {
            if(connection.Client != null)
               connection.Client.QueueMessage(message);
         });
         User.SetCloseSelfPlaceholder(() =>
         {
            connection.Client.QueueRaw(WebSocketFrame.GetCloseFrame().GetRawBytes());
         });
      }
      public async Task StartAsync()
      {
         //OY! Don't call us again!
         if (server != null)
            return;

         server = new TcpListener(System.Net.IPAddress.Any, settings.Port);

         try
         {
            server.Start();
         }
         catch(Exception e)
         {
            Log("Couldn't start base server: " + e.Message, LogLevel.FatalError);
            return;
         }

         running = true;
         Log("Started server on port: " + settings.Port);

         while (running)
         {
            //Accept the client and set it up
            try
            {
               TcpClient client = await server.AcceptTcpClientAsync();
               client.ReceiveBufferSize = settings.ReceiveBufferSize;
               client.SendBufferSize = settings.SendBufferSize;
               client.SendTimeout = client.ReceiveTimeout = (int)settings.ReadWriteTimeout.TotalMilliseconds;
               WebSocketClient webClient = new WebSocketClient(client, settings.MaxReceiveSize);

               Log("Accepted connection from " + client.Client.RemoteEndPoint);

               //Start up a spinner to handle this new connection. The spinner will take care of headers and all that,
               //we're just here to intercept new connections.
               WebSocketConnectionAsync connection = 
                  new WebSocketConnectionAsync(webClient, GenerateNewUser(), settings.LogProvider);
               connection.Awaitable = ProcessConnection(connection);

               lock (connectionLock)
               {
                  connections.Add(connection);
               }
            }
            catch(Exception e)
            {
               if (e is ObjectDisposedException)
                  Log("Connection accepter has gone away it seems...", LogLevel.Debug);
               else
                  Log("Encountered exception while accepting: " + e, LogLevel.Error);
            }
         }

         running = false;
      }
 public WebSocketConnectionAsync(WebSocketClient client, WebSocketUser user, Logger logger) 
    : base(client, user, logger)
 {
    
 }
      /// <summary>
      /// The worker function which should be run on a thread. It accepts connections
      /// </summary>
      protected override void Spin()
      {
         spinnerStatus = SpinStatus.Starting;
         TcpListener server = new TcpListener(System.Net.IPAddress.Any, settings.Port);

         try
         {
            server.Start();
         }
         catch(Exception e)
         {
            Log("Couldn't start accept spinner: " + e.Message, LogLevel.FatalError);
            spinnerStatus = SpinStatus.Error;
            return;
         }

         Log("Started server on port: " + settings.Port);
         spinnerStatus = SpinStatus.Spinning;

         while (!shouldStop)
         {
            //NO! NO BLOCKING! This is basically nonblocking... kind of.
            if (server.Pending())
            {
               //Accept the client and set it up
               try
               {
                  TcpClient client = server.AcceptTcpClient();
                  client.ReceiveBufferSize = settings.ReceiveBufferSize;
                  client.SendBufferSize = settings.SendBufferSize;
                  client.SendTimeout = client.ReceiveTimeout = (int)settings.ReadWriteTimeout.TotalMilliseconds;
                  WebSocketClient webClient = new WebSocketClient(client, settings.MaxReceiveSize);

                  //Start up a spinner to handle this new connection. The spinner will take care of headers and all that,
                  //we're just here to intercept new connections.
                  WebSocketSpinner newSpinner = new WebSocketSpinner(webClient, GenerateNewUser(), settings);
                  newSpinner.OnComplete += RemoveSpinner;

                  Log("Accepted connection from " + client.Client.RemoteEndPoint);
                  lock (spinnerLock)
                  {
                     connectionSpinners.Add(newSpinner);
                  }

                  if (!newSpinner.Start())
                  {
                     Log("Couldn't startup client spinner!", LogLevel.Error);
                     ObliterateSpinner(newSpinner);
                  }
               }
               catch(Exception e)
               {
                  Log("Encountered exception while accepting: " + e, LogLevel.Error);
               }
            }

            System.Threading.Thread.Sleep((int)settings.AcceptPollInterval.TotalMilliseconds);
         }

         Log("Attempting to stop server", LogLevel.Debug);

         server.Stop();

         foreach (WebSocketSpinner spinner in new List<WebSocketSpinner>(connectionSpinners))
            ObliterateSpinner(spinner);

         Log("Server shut down");
         spinnerStatus = SpinStatus.Complete;
      }