/// <summary> /// Captures received messages and waits until dispatcher permission has been granted. /// </summary> /// <param name="proxy">The received messages proxy.</param> /// <param name="cancelToken">The cancellation token.</param> public static async Task WaitForPermissionAsync(DispatcherProxy proxy, CancellationToken cancelToken = default(CancellationToken)) { TaskCompletionSource <object> tcs = new TaskCompletionSource <object>(); proxy.SetTarget(new PermissionWaiter(tcs)); try { using (cancelToken.Register(() => tcs.TrySetCanceled())) { await tcs.Task; } } finally { proxy.SetTarget(null); } }
/// <summary> /// Captures received messages and waits until dispatcher permission has been granted. /// </summary> /// <param name="proxy">The received messages proxy.</param> /// <param name="cancelToken">The cancellation token.</param> public static async Task <int> WaitForSubAreaNumberAsync(DispatcherProxy proxy, CancellationToken cancelToken = default(CancellationToken)) { TaskCompletionSource <int> tcs = new TaskCompletionSource <int>(); proxy.SetTarget(new SubAreaNumberWaiter(tcs)); try { using (cancelToken.Register(() => tcs.TrySetCanceled())) { return(await tcs.Task); } } finally { proxy.SetTarget(null); } }
/// <summary> /// The implementation of Execute. /// </summary> /// <param name="welcomeWindow">The welcome window, which is closed if login succeeds.</param> /// <param name="cancelToken">A token used to cancel connection.</param> private async Task ExecuteAsync(Window welcomeWindow, CancellationToken cancelToken) { Debug.Assert(Parent.ConnectionProgress == EConnectionProgress.None); // Create the objects. NetTcpBinding binding = new NetTcpBinding(SecurityMode.None); DispatcherProxy proxy = new DispatcherProxy(); InstanceContext ic = new InstanceContext(proxy); string uri = BuildUri(Parent.ConnectToLocal ? "localhost" : Parent.RemoteHostname).ToString(); DuplexChannelFactory <IRun8> dcf = new DuplexChannelFactory <IRun8>(ic, binding, uri); Parent.ConnectionProgress = EConnectionProgress.Connecting; dcf.Open(); if (dcf.State == CommunicationState.Faulted) { Parent.LastErrorMessage = "Failed to connect."; Parent.ConnectionProgress = EConnectionProgress.None; return; } Run8Wrapper run8 = new Run8Wrapper(dcf.CreateChannel()); // Send the DispatcherConnected message, allowing the operation to be cancelled. { Task connectTask = null; try { TaskCompletionSource <object> cancelTCS = new TaskCompletionSource <object>(); connectTask = run8.DispatcherConnectedAsync(); using (cancelToken.Register(() => cancelTCS.TrySetCanceled())) { await await Task.WhenAny(connectTask, cancelTCS.Task); } } catch (OperationCanceledException) { dcf.Abort(); Parent.ConnectionProgress = EConnectionProgress.None; try { await connectTask; } catch (CommunicationException) { // Swallow. } return; } catch (CommunicationException exp) { dcf.Abort(); Parent.LastErrorMessage = "Failed to connect: " + exp.Message; Parent.ConnectionProgress = EConnectionProgress.None; return; } } // Wait until Run8 grants us permission, allowing the operation to be cancelled. Parent.ConnectionProgress = EConnectionProgress.WaitingForPermission; try { await PermissionWaiter.WaitForPermissionAsync(proxy, cancelToken); } catch (OperationCanceledException) { dcf.Abort(); Parent.ConnectionProgress = EConnectionProgress.None; return; } // Wait until Run8 sends us a message with a route number in it so we can look up in the database what data to load. Parent.ConnectionProgress = EConnectionProgress.WaitingForData; int route; try { route = await SubAreaNumberWaiter.WaitForSubAreaNumberAsync(proxy, cancelToken); } catch (OperationCanceledException) { dcf.Abort(); Parent.ConnectionProgress = EConnectionProgress.None; return; } // Create the world. World.World world; try { world = new World.World(run8, route); } catch (World.World.UnrecognizedRegionException) { dcf.Abort(); Parent.LastErrorMessage = "Unrecognized route ID " + route; Parent.ConnectionProgress = EConnectionProgress.None; return; } proxy.SetTarget(world); // Done! Launch the main window. Parent.ConnectionProgress = EConnectionProgress.None; MainWindow mw = new MainWindow(new MainViewModel(world)); Application.Current.MainWindow = mw; mw.Show(); welcomeWindow.Close(); }