add WinRT websocket support #1227

Closed
Alikont opened this Issue Jan 3, 2013 · 5 comments

Comments

Projects
None yet
5 participants

Alikont commented Jan 3, 2013

Is websocket support is planned for WinRT .NET Client library?

WinRT supports websockets
http://msdn.microsoft.com/en-US/library/windows/apps/windows.networking.sockets.streamwebsocket

Owner

davidfowl commented Jan 3, 2013

Post RTM most likely

Alikont commented Jan 3, 2013

Do I understand correctly: if I'll try to implement it myself all I need is to implement IClientTransport interface and put my transport as a first item in client connection`s transports array?

And do you have approximate date of RTM?

Owner

davidfowl commented Jan 3, 2013

RTM date is sometime in the end of January or early Feb.

You can implement transports completely outside of the SignalR client and pass it as the first argument to Start. You don't need to modify the source. You can take a look at the .NET 4.5 websocket client for some ideas on how to get started:

https://github.com/SignalR/SignalR/blob/dev/src/Microsoft.AspNet.SignalR.Client45/Transports/WebSocketTransport.cs

using Microsoft.AspNet.SignalR.Client.Http;
using Microsoft.AspNet.SignalR.Client.Infrastructure;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Windows.Networking.Sockets;
using Windows.Storage.Streams;
using System.IO;
using Windows.Web;
namespace Microsoft.AspNet.SignalR.Client.Transports
{
    public class WebSocketTransport : IClientTransport
    {
        private readonly IHttpClient _client;
        private MessageWebSocket _webSocket;
        private IConnection _connection;
        private CancellationToken _disconnectToken;
        // private TaskCompletionSource<object> _startTcs;
        private ManualResetEventSlim _abortEventSlim;
        private DataWriter messageWriter;
        public WebSocketTransport1()
            : this(new DefaultHttpClient())
        {
        }
        public WebSocketTransport(IHttpClient client)
        {
            _client = client;
            //    _disconnectToken = CancellationToken.None;
            //   ReconnectDelay = TimeSpan.FromSeconds(2);
        }
        public string Name
        {
            get
            {
                return "webSockets";
            }
        }

        public bool SupportsKeepAlive
        {
            get
            {
                return true;
            }
        }
        public Task<NegotiationResponse> Negotiate(IConnection connection)
        {
            return _client.GetNegotiationResponse(connection);
        }
        public Task Start(IConnection connection, string data, System.Threading.CancellationToken disconnectToken)
        {
            _connection = connection;
            //_startTcs = new TaskCompletionSource<object>();
            _disconnectToken = disconnectToken;
            var url = _connection.Url + "connect";
            url += TransportHelper.GetReceiveQueryString(connection, data, "webSockets");
            var builder = new UriBuilder(url);
            builder.Scheme = builder.Scheme == "https" ? "wss" : "ws";

            _connection.Trace(TraceLevels.Events, "WS: {0}", builder.Uri);
            _webSocket = new MessageWebSocket();
            _webSocket.Control.MessageType = SocketMessageType.Utf8;
            _webSocket.MessageReceived += _webSocket_MessageReceived;
            messageWriter = new DataWriter(_webSocket.OutputStream);
            _webSocket.Closed += _webSocket_Closed;
            return _webSocket.ConnectAsync(builder.Uri).AsTask();
        }

        void _webSocket_Closed(IWebSocket sender, WebSocketClosedEventArgs args)
        {
            OnClose(true);
        }

        void _webSocket_MessageReceived(MessageWebSocket sender, MessageWebSocketMessageReceivedEventArgs args)
        {
            OnOpen();
            try
            {
                var dataStream = args.GetDataStream();
                using (DataReader reader = args.GetDataReader())
                {
                    reader.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;

                    string read = reader.ReadString(reader.UnconsumedBufferLength);
                    OnMessage(read);
                }
            }
            catch (Exception ex)
            {
                WebErrorStatus status = WebSocketError.GetStatus(ex.GetBaseException().HResult);
            }
        }
        public void OnMessage(string message)
        {
            _connection.Trace(TraceLevels.Messages, "WS: OnMessage1({0})", message);

            bool timedOut;
            bool disconnected;
            TransportHelper.ProcessResponse(_connection,
                                            message,
                                            out timedOut,
                                            out disconnected);

            if (disconnected && !_disconnectToken.IsCancellationRequested)
            {
                _connection.Disconnect();
                Close();
            }
        }
        public void OnOpen()
        {
            if (_connection.ChangeState(ConnectionState.Reconnecting, ConnectionState.Connected))
            {
                _connection.OnReconnected();
            }
        }

        public void OnClose(bool clean)
        {
            _connection.Trace(TraceLevels.Events, "WS: OnClose({0})", clean);

            if (_disconnectToken.IsCancellationRequested)
            {
                return;
            }

            if (_abortEventSlim != null)
            {
                _abortEventSlim.Set();
                return;
            }

            DoReconnect();
        }

        private async void DoReconnect()
        {
            while (_connection.EnsureReconnecting())
            {
                try
                {
                    //   await PerformConnect(reconnecting: true);
                    break;
                }
                catch (OperationCanceledException)
                {
                    break;
                }
                catch (Exception ex)
                {
                    if (ExceptionHelper.IsRequestAborted(ex))
                    {
                        break;
                    }

                    _connection.OnError(ex);
                }

                await Task.Delay(TimeSpan.FromSeconds(10));
            }
        }

        //public  void OnError()
        //{
        //    _connectionInfo.Connection.OnError(Error);
        //}

        public void LostConnection(IConnection connection)
        {
            _connection.Trace(TraceLevels.Events, "WS: LostConnection");

            Close();
        }
        public void Abort(IConnection connection, TimeSpan timeout)
        {
            lock (this)
            {
                if (_abortEventSlim == null)
                {
                    _abortEventSlim = new ManualResetEventSlim();

                    Close();
                }
            }

            if (!_abortEventSlim.Wait(timeout))
            {
                _connection.Trace(TraceLevels.Events, "WS: Abort never fired");
            }
        }
        public void Close()
        {
            _webSocket.Close(1000, string.Empty);
        }
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_abortEventSlim != null)
                {
                    _abortEventSlim.Dispose();
                    _abortEventSlim = null;
                }
            }
        }
        public Task Send(IConnection connection, string data)
        {

            //webSocket.OutputStream.WriteAsync(
            // messageWriter.WriteBytes(System.Text.Encoding.UTF8.GetBytes(data));
            messageWriter.WriteString(data);
            var dataWriterStoreOperation = messageWriter.StoreAsync();
            return TaskAsyncHelper.Empty;

        }




    }
}
Contributor

moozzyk commented Jul 22, 2014

This is the same as #3027 and has been completed. Closing.

@moozzyk moozzyk closed this Jul 22, 2014

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment