Is there anybody out there? (Online /Offline and the Peer Channel)

*********************************************************

Updated to reflect changes in the February CTP

*********************************************************

One of the most frequently asked questions is this: How can I tell if a node is the only member of the mesh?  We addedevents and a property that can be queried to get this information

The definition of online status is straightforward:

  • A node that has no immediate neighbors is Offline.
  • A node with at least one neighbor is Online.

 

PeerNode and Online Status

To set the online and offline events to handlers specified in your own code use:

IOnlineStatus status = channel.GetProperty<IOnlineStatus>();

status.Online += online;

status.Offline += offline;

The handler is a method of type EventHandler very simple handlers might look like:

static void Online(object o, EventArgs args)

{

  Console.WriteLine("Online");

}

static void Offline(object o, EventArgs args)

{

  Console.WriteLine("Offline");

}

It should be noted that in Beta 1 and the forthcoming Beta 2 release of Peer Channel the handlers are not called on the UI thread so you must take care to ensure that you write thread safe code for these handlers.  If you try not to change global or static state you should be all right, the 2 most common uses of these events are to 1. Send a message to the mesh or 2 to toggle an indicator on the UI.

If instead of responding to an event you prefer to query the status then use the IsOnline property true means online false means offline:

IOnlineStatus status = channel.GetProperty<IOnlineStatus>();

if (status.IsOnline)

Console.WriteLine("Online");

 

 

Non-Guarantees

It should be noted that the online status is subject to change at any time; it is eminently possible for you to receive an Online event during which you send a message to the mesh and then before the message has been transmitted to any neighbors for the node to go offline again.

Online is fired when a node becomes Online, Offline is fired when a node loses it’s last neighbor.  Offline is not fired during Open if the node is opened and does not have any neighbors.

The following example shows how to create a proxy and specify handlers for the online and offline events, this is not the only way to do it but it is the way I like and use.

 

The contract

The contract is the same as before

[ServiceContract(Namespace = "urn:uuid:F0E619F9-3AB7-4b9d-A009-269B381C6C85/", CallbackContract = typeof(IHelloMesh))]

interface IHelloMesh

{

  [OperationContract(IsOneWay = true)]

  void Say(string message);

}

 

The proxy

Add an overloaded Constructor to HelloProxy that sets the events to handlers passed into the constructor:

public HelloProxy(InstanceContext inputInstance, string name, EventHandler online, EventHandler offline)

       : base(inputInstance, name)

{

  IOnlineStatus status = base.InnerChannel.GetProperty<IOnlineStatus>();

  status.Online += online;

  status.Offline += offline;

  base.InnerDuplexChannel.Open();

}

 

Add the message handler

class HelloMesh : IHelloMesh

{

  public void Say(string message)

  {

    Console.WriteLine("Say : {0}", message);

  }

}

 

Add handlers to the main program:

 

static void Online(object o, EventArgs args)

{

Console.WriteLine("Online");

}

static void Offline(object o, EventArgs args)

{

Console.WriteLine("Offline");

}

And that is all there is to it.  Now when your application starts it will display Online in the output  as soon as it is connected to a neighbor; when it is completely alone it will produce Offline in the output.

 

The complete program

using System;

using System.Collections.Generic;

using System.ServiceModel;

using System.ServiceModel.Channels;

using System.Text;

namespace HelloMesh

{

  [ServiceContract(Namespace = "urn:uuid:F0E619F9-3AB7-4b9d-A009-269B381C6C85/", CallbackContract = typeof(IHelloMesh))]

  interface IHelloMesh

  {

    [OperationContract(IsOneWay = true)]

    void Say(string message);

  }

  partial class HelloProxy : System.ServiceModel.DuplexClientBase<IHelloMesh>, IHelloMesh

  {

    public HelloProxy(InstanceContext inputInstance, string name, EventHandler online, EventHandler offline)

           : base(inputInstance, name)

    {

      IOnlineStatus status = base.InnerChannel.GetProperty<IOnlineStatus>();

      status.Online += online;

      status.Offline += offline;

      base.InnerDuplexChannel.Open();

    }

    public HelloProxy(InstanceContext inputInstance, string name)

           : base(inputInstance, name)

    {

      base.InnerDuplexChannel.Open();

    }

    public void Say(string message)

    {

      base.InnerProxy.Say(message);

    }

  }

  class HelloMesh : IHelloMesh

  {

    public void Say(string message)

    {

      Console.WriteLine("Say : {0}", message);

    }

  }

  class Program

  {

    static void Online(object o, EventArgs args)

    {

      Console.WriteLine("Online");

    }

    static void Offline(object o, EventArgs args)

    {

      Console.WriteLine("Offline");

    }

    static void Main(string[] args)

    {

      InstanceContext instanceContext = new InstanceContext(new HelloMesh());

      using (HelloProxy hello = new HelloProxy(instanceContext, "HelloEndpoint", Online, Offline))

      {

        string msg = "";

        while (msg != "q")

        {

          msg = Console.ReadLine();

  hello.Say(msg);

        }

        hello.Close();

      }

    }

  }

}

The config is unchanged from before and looks like:

<?xml version="1.0" encoding="utf-8" ?>

<configuration xmlns="https://schemas.microsoft.com/.NetConfiguration/v2.0">

<system.serviceModel>

<client>

<endpoint name="HelloEndpoint"

address="net.p2p://hellomesh/hellomesh"

binding="netPeerTcpBinding"

bindingConfiguration="Binding1"

contract="HelloMesh.IHelloMesh">

</endpoint>

</client>

<bindings>

<netPeerTcpBinding>

<binding name="Binding1"

port="5182">

<security mode="None"/>

</binding>

</netPeerTcpBinding>

</bindings>

</system.serviceModel>

</configuration>

 

Next:

Possibly:

   Structured data (DataContracts and Peer Channel)

   Sending a message only to your nearest neighbor (Message Filters) !!!!!

   Channels Input/Output/Duplex  and Peer Channel