/// <summary> /// Initializes a new instance of the <see cref="ObservableClientWebSocket"/> class. /// </summary> /// <param name="uri"> /// The uri. /// </param> /// <param name="cancellationToken"> /// The cancellation token. /// </param> public ObservableClientWebSocket(Uri uri, CancellationToken cancellationToken) { this.uri = uri; this.status = new ReplaySubject <ConnectionStatus>(1); this.Status = this.status.AsObservable(); this.sendActor = new MutuallyExclusiveTaskExecutor(); this.receiveActor = new MutuallyExclusiveTaskExecutor(); this.cancellation = new CancellationTokenSource(); cancellationToken.Register(this.cancellation.Cancel); this.sendMemoryStream = new MemoryStream(); this.sendEncoder = new StreamWriter(this.sendMemoryStream, Utf8EncodingWithoutByteOrderMark); this.sendEncoder.AutoFlush = true; this.sendActor.Start(this.cancellation.Token).ContinueWith( _ => { Debug.WriteLine("Send Actor completed: Status: {0}, Exception: {1}", _.Status, _.Exception); this.sendActor.Dispose(); this.sendMemoryStream.Dispose(); this.sendEncoder.Dispose(); }); this.receiveActor.Start(this.cancellation.Token).ContinueWith( _ => { Debug.WriteLine("Receive Actor completed: Status: {0}, Exception: {1}", _.Status, _.Exception); this.receiveActor.Dispose(); }); this.Incoming = Observable.Create <string>( observer => { if (this.cancellation.IsCancellationRequested) { throw new OperationCanceledException(); } var observerCancellation = new CancellationTokenSource(); this.cancellation.Token.Register( () => { observerCancellation.Cancel(); observer.OnCompleted(); }); this.receiveActor.Schedule(() => this.ReceivePump(observer, observerCancellation.Token)); return(Disposable.Create(observerCancellation.Cancel)); }).Publish().RefCount(); }
/// <summary> /// The socket send pump. /// </summary> /// <param name="socket"> /// The socket. /// </param> /// <param name="uri"> /// The uri. /// </param> /// <param name="cancellation"> /// The cancellation. /// </param> /// <returns> /// The observer used to send messages to the socket. /// </returns> private static Func <string, Task> SocketSendPump(IWebSocket socket, Uri uri, CancellationTokenSource cancellation, TaskCompletionSource <int> connected) { var sender = new MutuallyExclusiveTaskExecutor(); sender.Schedule( async() => { try { await socket.ConnectAsync(uri).AsTask(cancellation.Token).ConfigureAwait(false); connected.TrySetResult(0); } catch { cancellation.Cancel(); } }); var writer = new DataWriter(socket.OutputStream); sender.Run(cancellation.Token).ContinueWith( _ => { if (_.Status != TaskStatus.RanToCompletion) { cancellation.Cancel(); } sender.Dispose(); }, CancellationToken.None); return(next => sender.Schedule( async() => { try { writer.WriteString(next); await writer.StoreAsync().AsTask(cancellation.Token).ConfigureAwait(false); } catch { cancellation.Cancel(); } })); }