public static ServiceHost <T> CreateDiscoverableHost <T>(Uri scope = null) where T : class { ServiceHost <T> host = ServiceModelEx.DiscoveryFactory.CreateDiscoverableHost <T>(scope); DiscoveryRequestService requestService = new DiscoveryRequestService(host.Description.Endpoints.UnsafeToArray <ServiceEndpoint>()); ServiceHost requestHost = new ServiceHost(requestService); Uri requestServiceAddress = new Uri(DiscoveryHelper.AvailableTcpBaseAddress.AbsoluteUri + typeof(T) + "/" + "DiscoveryEndpoint"); requestHost.AddServiceEndpoint(typeof(IDiscovery), DiscoveryFactory.Binding, requestServiceAddress); host.Opened += delegate { try { requestHost.Open(); IDiscoverySubscription pubsubProxy = ChannelFactory <IDiscoverySubscription> .CreateChannel(DiscoveryFactory.Binding, Address.DiscoverySubscription); pubsubProxy.Subscribe(requestServiceAddress.AbsoluteUri); (pubsubProxy as ICommunicationObject).Close(); } catch { Trace.WriteLine("Could not subscribe to discovery requests for service " + typeof(T)); } IAnnouncements announcementsProxy = ChannelFactory <IAnnouncements> .CreateChannel(DiscoveryFactory.Binding, Address.Announcements); PublishAvailabilityEvent(host.Description.Endpoints.ToArray(), announcementsProxy.OnHello); }; host.Closing += delegate { try { IDiscoverySubscription pubsubProxy = ChannelFactory <IDiscoverySubscription> .CreateChannel(DiscoveryFactory.Binding, Address.DiscoverySubscription); pubsubProxy.Unsubscribe(requestServiceAddress.AbsoluteUri); (pubsubProxy as ICommunicationObject).Close(); requestHost.Close(); } catch { Trace.WriteLine("Could not unsubscribe to discovery requests for service " + typeof(T)); } IAnnouncements announcementsProxy = ChannelFactory <IAnnouncements> .CreateChannel(DiscoveryFactory.Binding, Address.Announcements); PublishAvailabilityEvent(host.Description.Endpoints.ToArray(), announcementsProxy.OnBye); }; return(host); }
public void MultiThreadIsSafe() { using (var cts = new CancellationTokenSource(Utils.TestTimeoutMs)) { var delayedException = new Utils.DelayedException(); using (var svc1 = MakeAgent(1)) using (var svc2 = MakeAgent(2)) { for (int i = 0; i < 1000; ++i) { { var category = "DisposeInHandler" + i; svc1.PublishAsync(category, ""); svc2.PublishAsync(category, ""); IDiscoverySubscription sub = svc2.Subscribe(category); sub.Updated += delayedException.Wrap <IDiscoverySubscription>( subscription => { Assert.True(subscription.Resources.Count() >= 0); subscription.Dispose(); }); } { var category = "DisposeInOtherThread" + i; svc1.PublishAsync(category, ""); svc2.PublishAsync(category, ""); IDiscoverySubscription sub = svc2.Subscribe(category); Task.Delay(random_.Next(0, 200)).ContinueWith( delayedException.Wrap <Task>( _ => { Assert.True(sub.Resources.Count() >= 0); sub.Dispose(); })); } } } Thread.Sleep(200); delayedException.Rethrow(); } }
// Run a query and wait for the predicate to be satisfied. // Return the list of resources which satisfied the predicate or null if canceled before the predicate was satisfied. public static IEnumerable <IDiscoveryResource> QueryAndWaitForResourcesPredicate( IDiscoverySubscription discovery, Func <IEnumerable <IDiscoveryResource>, bool> pred, CancellationToken token) { // Check optimistically before subscribing to the discovery event. var resources = discovery.Resources; if (pred(resources)) { return(resources); } if (token.IsCancellationRequested) { return(null); } using (var wakeUp = new AutoResetEvent(false)) { Action <IDiscoverySubscription> onChange = (IDiscoverySubscription sender) => wakeUp.Set(); using (var unregisterCancel = token.Register(() => wakeUp.Set())) using (var unregisterWatch = new RaiiGuard(() => discovery.Updated += onChange, () => discovery.Updated -= onChange)) { while (true) { // Check before waiting on the event so that updates aren't missed. resources = discovery.Resources; if (pred(resources)) { return(resources); } wakeUp.WaitOne(); // wait for cancel or update if (token.IsCancellationRequested) { return(null); } } } } }
public void Run(string username, IPAddress broadcastAddress) { _username = username; _localAddrString = GetLocalIPAddress().ToString(); _chatServer = new TcpListener(IPAddress.Any, ChatPort); _chatServer.Start(); Task.Run(ListenForConnections); // Initialize the discovery agent _discoveryAgent = new PeerDiscoveryAgent(new UdpPeerDiscoveryTransport(broadcastAddress, DiscoveryPort)); // Publish a resource exposing the local IP address for connections and the user name as an attribute. var connection = GetLocalIPAddress().ToString(); var attributes = new Dictionary <string, string> { [NameKey] = username }; _discoveryAgent.PublishAsync(ParticipantCategory, connection, attributes); // Subscribe to other participant resources. _discoverySubscription = _discoveryAgent.Subscribe(ParticipantCategory); _discoverySubscription.Updated += (IDiscoverySubscription subscription) => { // Parse discovered resources. var activePeers = new Dictionary <IPAddress, string>(); foreach (var res in subscription.Resources) { if (res.Connection == _localAddrString) { // Exclude the local resource. continue; } try { var address = IPAddress.Parse(res.Connection); var name = res.Attributes[NameKey]; activePeers.Add(address, name); } catch (Exception e) { // Invalid resource format, or multiple resources per host. Debug.WriteLine($"Invalid resource: {e}"); continue; } } // Create reader connections to the active peers. RefreshReaderConnections(activePeers); }; // Loop waiting for input. Console.CursorTop = Console.WindowHeight; Console.Write(Prompt); while (true) { string message = Console.ReadLine(); PostLocalMessageToConsole(message); PostLocalMessageToPeers(message); } }