Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 12 Next »

Note: this page is inspired by (and often copied verbatim from) the original fourth lesson, Lesson: Pico to Pico Subscriptions.

Learning Objectives

After completing this lesson, you will be able to do the following:

  • Understand pico-to-pico relationships and subscriptions
  • Use the developer tools to manage pico subscriptions
  • Link two or more picos with a subscription programmatically and have them interact. 

Prerequisites 

You should have already completed the following lessons:

Subscriptions

Subscriptions play an important role in building systems of picos. In Pico-Based Systems Lesson, you created child picos. If the parent-child relationship were the only one that existed, we could create hierarchies of picos, but not peer-to-peer systems of picos. Subscriptions allow us to establish relationships between any two picos. 

A subscription represents a relationship between two picos. It has a name and two channels, one from each pico participating in the subscription to the other. Each side in the subscription can be given a role to further identify the purpose of the subscription. 

Subscriptions Using the UI

To be written...

Managing Subscriptions Programmatically

Wrangler provides functions, actions, and rules for managing subscriptions from within your KRL code.

The following sequence diagram illustrates a point at which a subscription will be needed. You will recall from the previous lesson that the section collection pico may handle the event section needed. Once the section pico is ready, the section collection pico could assign it a new channel and send the ECI to it's parent, the registration pico. Similarly (code left as an exercise) the student collection pico could inform it's parent (also the registration pico) of a private ECI for the appropriate student pico. Having both ECI's, the registration pico could introduce the two picos to each other, so that they now share a subscription. This introduction, and the creation of the subscription, are represented by blue arrows.

"Stu" represents the pico for the student "Alice" and "Sec" represents the pico for section "A". Remember that there might be thousands of students and thousands of sections, of which this diagram shows only one of each.

We saw in the previous lesson, that when the section collection pico handles the event section needed, it may be able to provide it immediately, because it already exists, or we may need to create and initialize a new pico before it becomes available. This is illustrated by the note "possible creation of pico Sec". Also, we saw that the section pico might write its roster to the database and then ask to be deleted (by sending the event section offline to the section collection pico. This is illustrated by the note "possible end of pico(s)". Similar remarks hold for student picos.

Pico to pico subscriptions

In this section, we'll use a simpler example. Here the owner pico has three child picos, as shown by the familiar black parent-child edges. However, the "Mischief Pico" needs to communicate with the other two picos.

The subscriptions which we will create to enable this pico to pico communication are shown as dashed magenta lines. (This diagram is available at localhost:8080/?subscr (added to the node pico engine in version 0.5.8))

Engine Compatibility

Very soon, the ability to manage subscriptions will be built-in to every pico. Right now, you will need to install the ruleset with RID "Subscriptions" into the three picos which will participate in subscriptions. This can be done in the Rulesets tab of each pico, by clicking on the "install ruleset" button beside the dropdown when it shows "Subscriptions".

Later we will show how to write KRL code to initiate a subscription. For now, we will create a subscription manually (using a RESTful interface such as the Postman REST client, or curl, or the browser–in this example we'll use the browser).

Prepare a URL like this one in your browser (the line breaks shown here are for readability–your URL will not contain line breaks):

http://localhost:8080/sky/event/cj0dea39q0001khpqy4su0ru3/subscr/wrangler/subscription?
name=thing1&
name_space=mischief&
my_role=controller&
subscriber_role=thing&
channel_type=subscription&
attrs=&
subscriber_eci=cj0dea81g0003khpqy7j9knqz

Your URL will be different because the ECI to which the event is sent (in the example, cj0dea39q0001khpqy4su0ru3) needs to be replaced by the main ECI of your Mischief Pico, and the subscriber_eci parameter needs to indicate the ECI of your Thing1 Pico.

A subscription has a name within a name_space, and we indicate the role that the picos involved in the subscription will each play (my_role and subscriber_role).

When you visit this URL, the wrangler/subscription event will be sent to the Mischief Pico and the subscription will be created. This will result in each of the two picos involved having a subscription. Each of them will also have a new channel, especially created for use with the subscription. Here is the new channel created for the Thing1 pico:

Repeat the process for the Thing2 pico. If we were now to query the Mischief Pico to see its subscriptions, using a URL like

http://localhost:8080/sky/cloud/cj0dea39q0001khpqy4su0ru3/Subscriptions/getSubscriptions

we would see that it participates in two subscriptions:

{
  "mischief:thing1": {
    "eci": "cj0deky300006khpqn7ucdvhj",
    "name": "mischief:thing1",
    "type": "subscription",
    "attributes": {
      "subscription_name": "thing1",
      "name_space": "mischief",
      "relationship": "controller<->thing",
      "my_role": "controller",
      "subscriber_role": "thing",
      "subscriber_eci": "cj0dea81g0003khpqy7j9knqz",
      "status": "outbound",
      "attributes": ""
    }
  },
  "mischief:thing2": {
    "eci": "cj0devoqc0008khpqenjg11xc",
    "name": "mischief:thing2",
    "type": "subscription",
    "attributes": {
      "subscription_name": "thing2",
      "name_space": "mischief",
      "relationship": "controller<->thing",
      "my_role": "controller",
      "subscriber_role": "thing",
      "subscriber_eci": "cj0deacyn0005khpq8q0qk080",
      "status": "outbound",
      "attributes": ""
    }
  }
}

Similarly, the Thing1 Pico participates in just one subscription. Doing the same sky/cloud query to its ECI will show something like this:

{
  "mischief:thing1": {
    "eci": "cj0deky3l0007khpqdmo4037y",
    "name": "mischief:thing1",
    "type": "subscription",
    "attributes": {
      "subscription_name": "thing1",
      "name_space": "mischief",
      "relationship": "thing<->controller",
      "my_role": "thing",
      "subscriber_role": "controller",
      "outbound_eci": "cj0deky300006khpqn7ucdvhj",
      "status": "inbound",
      "attributes": ""
    }
  }
}

There is one step remaining in the subscription process. Just because a pico offers a subscription to your pico doesn't mean that your pico is forced to accept it. This is manifest by the "status" of the subscriptions. For the originating pico, the status is "outbound" (short for outbound, pending), and for the other pico, the status is "inbound" (i.e. inbound, pending).

In fact, after the pending subscriptions were created, the Subscriptions rule for wrangler/subscription raises the wrangler event "inbound_pending_subscription_added" passing along all of the attributes. It is up to your pico to react by either accepting or rejecting. This cookbook example shows how to write a rule that auto-approves subscriptions. Generally, promiscuously approving pending subscriptions is a security risk, so most auto-approvals take place where something about the subscription requestor can be verified. For example, a child might be programmed to automatically approve subscription requests from its parent, after checking that the invitation came in on a channel that can be verified as being from the parent.

For now, to complete the manual process, we will send this sky/event to the Thing1 pico (line break added for readability–your URL will be all in one line):

http://localhost:8080/sky/event/cj0deky3l0007khpqdmo4037y/approve/wrangler/pending_subscription_approval?
subscription_name=mischief:thing1

Checking the Thing1 pico again, you will see that its one subscription now has the the status of "subscribed". At the same time, that subscription in the Mischief pico also now has the status of "subscribed".

Writing rules to manage subscriptions

Since most of the heavy lifting is done by the Subscriptions ruleset, it is easy to initiate, approve, and use subscriptions inside of your own rulesets.

Initiating subscriptions by introduction

It is possible to initiate a subscription with a rule running in a pico which has in its possession the ECI's of the two picos which need to be related by the subscription. For example, once we have set up the three child picos, Mischief, Thing1, and Thing2, we can install a ruleset into each of them. Simple examples are available in this repository.

The owner pico has all of the ECI's in its array of children (maintained by the io.picolabs.pico aka Wrangler ruleset), but it doesn't know which is which. So we added this rule to allow it to distinguish between the Mischief pico and the thing picos.

  rule mischief_who {
    select when mischief who
    pre {
      mischief = event:attr("eci")
      things = wrangler:children().map(function(v){v.eci})
                                  .filter(function(v){v != mischief})
    }
    always {
      ent:mischief := mischief;
      ent:things := things
    }
  }

The ruleset for the Mischief pico sets up a button "mischief/identity" in that pico's Testing tab which will send this event to the owner pico.

Once the owner pico has all of the ECI's, the code to introduce the Mischief pico to each of the thing picos is straight-forward.

  rule mischief_subscriptions {
    select when mischief subscriptions
    pre {
      mischief = ent:mischief
      thing1 = ent:things[0]
      thing2 = ent:things[1]
    }
    if mischief && thing1 && thing2 then noop()
    fired {
      event:send(
        { "eci": mischief, "eid": "subscription",
          "domain": "wrangler", "type": "subscription",
          "attrs": { "name": "thing1",
                     "name_space": "mischief",
                     "my_role": "controller",
                     "subscriber_role": "thing",
                     "channel_type": "subscription",
                     "subscriber_eci": thing1 } } );
      event:send(
        { "eci": mischief, "eid": "subscription",
          "domain": "wrangler", "type": "subscription",
          "attrs": { "name": "thing2",
                     "name_space": "mischief",
                     "my_role": "controller",
                     "subscriber_role": "thing",
                     "channel_type": "subscription",
                     "subscriber_eci": thing2 } } )
    }
  }

The ruleset sets up a button in the owner pico's Testing tab, "mischief/subscriptions" to send the event that causes this rule to evaluate.

The final step is that a rule selecting on wrangler/inbound_pending_subscription_added in each of the thing picos will complete the subscription process.

Initiating subscriptions by direct request

Rather than having a third party initiate a subscription using an introduction, a pico can directly request a subscription. In this case, rather than use event:send, the pico would raise the event to itself, in the postlude block of one of its rules.

      raise wrangler event "subscription"
          with name = "thing1"
               name_space = "mischief"
               my_role = "controller"
               subscriber_role = "thing"
               channel_type = "subscription"
               subscriber_eci = thing1

As in the case of introductions, the other pico must have a rule selecting on wrangler/inbound_pending_subscription_added which will complete the subscription process by raising the wrangler/pending_subscription_approval event.


  • No labels