Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Describing a single WebSocket endpoint shared by multiple Things #1664

Open
benfrancis opened this issue Aug 15, 2022 · 6 comments
Open

Describing a single WebSocket endpoint shared by multiple Things #1664

benfrancis opened this issue Aug 15, 2022 · 6 comments
Labels
Defer to TD 2.0 Has Use Case Potential The use case can be extracted and explained

Comments

@benfrancis
Copy link
Member

benfrancis commented Aug 15, 2022

Further to the issue of how to describe a single WebSocket used by all operations on a Thing (see #1070 and #878), I'd like to introduce an additional use case where a single WebSocket endpoint is shared between multiple Things.

Use Case: A cloud service monitors data from buildings in order to store time-series data and generate analytics about how the buildings are being used.

Using the approach described in #1070 (comment) I believe it's possible to describe a single WebSocket endpoint for a Thing over which all property changes (observeproperty) and events (subscribeevent) can be sent. This still requires a separate WebSocket connection for every device in the building, e.g.

  • wss://mybuilding.com/things/sensor1
  • wss://mybuilding.com/things/sensor2
  • wss://mybuilding.com/things/sensor3
  • wss://mybuilding.com/things/sensor4
  • ...
  • wss://mybuilding.com/things/sensor999

For a building with hundreds of sensors, this will not scale very well.

It would be more efficient if the cloud service could maintain a single WebSocket connection with each building, over which all the events and property changes for all of the Things it exposes are streamed. E.g.

  • wss://mybuilding.com

Apart from WebThings Gateway which already provides this kind of single WebSocket endpoint, another real world example of this is the Urban Observatory API for the Urban Sciences Building at Newcastle University in the UK. There is a streaming API for this building which streams all changes in all properties over a single WebSocket connection in real time https://api.usb.urbanobservatory.ac.uk/live/

I can generate Thing Descriptions for each device, with a single WebSocket endpoint per device, but how would you go about describing the building as a whole and the top level endpoint for monitoring the whole building over a single connection?


A starting point might be the ThingDirectory schema and Directory Service API from the WoT Discovery specification, which provide way to describe and interact with a collection of Things. However, that API only provides access to the metadata (Thing Descriptions) of Things, not their data (via protocol bindings). Each Thing must be interacted with separately using the protocol bindings in their individual Thing Descriptions, which may come from different origins using different protocols.

In the case of a Web of Things Gateway which hosts the Thing Descriptions and API endpoints of a whole collection of Things itself, how could I describe a WebSocket endpoint on that gateway over which any operation can be carried out on any of the Things it exposes?

Some ideas that come to mind for describing this endpoint in a Thing Description of the gateway:

  • A top level Form with "href": "wss://..." and a sub-protocol designed for monitoring multiple Things with thing IDs in all of its message payloads - but what would be the value of the mandatory op member?
{
  "@type": "ThingDirectory",
  ...
  "forms": [
    {
      "href": "wss://mybuilding.com",
      "subprotocol": "webthing-gateway",
      "op": "?"
    }
  ]
}
  • A top level Link with href set to the WebSocket endpoint, but what value of rel would describe this relationship, and how would you define the subprotocol to use?
{
  "@type": "ThingDirectory",
  ...
  "links": [
    {
      "href": "wss://mybuilding.com",
      "rel": "?"
    }
  ]
}
  • ActionAffordances for subscribing to an event or observing a property of a Thing managed by the gateway (similar to the CRUD operations on Things in the Directory Service API), but what about all of the other possible operations?
{
  "@type": "ThingDirectory",
  ...
  "actions": {
    "subscribeToEventOfThing": {
      "input": {
        "type": "object",
        "properties": {
          "thingId": {"type": "string"},
          "eventName": {"type", "string"},
        }
      },
      "forms": [
        {
          "href": "wss://mybuilding.com",
          "subprotocol": "webthing-gateway",
          "op": "invokeaction"
        }
      ]
    },
    "observePropertyOfThing": {
      "input": {
        "type": "object",
        "properties": {
          "thingId": {"type": "string"},
          "propertyName": {"type", "string"},
        }
      },
      "forms": [
        {
          "href": "wss://mybuilding.com",
          "subprotocol": "webthing-gateway",
          "op": "invokeaction"
        }
      ]
    }
  }
}

How would you model this in a Thing Description?

@github-actions github-actions bot added the needs-triage Automatically added to new issues. TF should triage them with proper labels label Aug 15, 2022
@benfrancis
Copy link
Member Author

Thinking about this some more, I'm really struggling to think of a way to describe this single WebSocket endpoint which acts as a kind of proxy to other Things in a Thing Description.

Following the same logic as for multiple interaction affordances sharing the same WebSocket endpoint discussed in #1070 (comment), perhaps another approach is to simply:

  • Re-use the same WebSocket endpoint URL in the Forms of multiple Thing Descriptions
  • Make sure that all message payloads in the WebSocket sub-protocol include a Thing ID
  • Define as part of the sub-protocol that Consumers should re-use connections to the same wss:// URL

Having to parse every Form of every InteractionAffordance of every Thing is far less efficient than parsing a single Form of a single Thing, but it works around the problem of trying to describe a single proxy endpoint by just pooling connections instead. It also allows for more flexibility in Thing Descriptions where only a subset of InteractionAffordances may be available via the WebSocket endpoint.

What do you think?

@egekorkan egekorkan added Defer to TD 2.0 and removed needs-triage Automatically added to new issues. TF should triage them with proper labels labels Aug 16, 2022
@egekorkan
Copy link
Contributor

There are some previous discussions on this, I would hope to tackle them all in one shot in the next spec version

@benfrancis
Copy link
Member Author

I would hope to tackle them all in one shot in the next spec version

I agree, but it would also be good to get feedback from people on how you would model this in Thing Description 1.1, for those of us who can't wait ~2 years for the next version :)

@lu-zero
Copy link
Contributor

lu-zero commented Dec 8, 2022

Having to parse every Form of every InteractionAffordance of every Thing is far less efficient than parsing a single Form of a single Thing, but it works around the problem of trying to describe a single proxy endpoint by just pooling connections instead. It also allows for more flexibility in Thing Descriptions where only a subset of InteractionAffordances may be available via the WebSocket endpoint.

In 1.1 you may (ab)use the security layer and define how much of the path has to be multiplexed there and then describe the forms as if they weren't multiplexed. A consumer that doesn't care then uses the non-multiplexed path, the consumer that knows about that "security" layer can opt to use it and rely on the information there to go from non-multiplexed to multiplexed.

You probably want to always have a fallback consumers that do not grok multiplexed websocket would rather use anyway.

@benfrancis
Copy link
Member Author

@lu-zero Interesting. Can you provide an example, because I'm not exactly clear on how that mechanism would work.

How would it be different than a Consumer just knowing to re-use WebSocket connections to the same URL?

Security does add complexity here, since it's technically possible that the same Consumer might open multiple WebSockets using different security credentials which provide access to a different sub-set of Things.

@lu-zero
Copy link
Contributor

lu-zero commented Dec 15, 2022

Currently the Security elements are the only ones that apply an arbitrary transformation to the href present in the form.

That assuming you want to be able to degrade that way.
Alternatively you extend the protocol binding with a subprotocol + custom element, I guess?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Defer to TD 2.0 Has Use Case Potential The use case can be extracted and explained
Projects
None yet
Development

No branches or pull requests

4 participants