Skip to content

Commit

Permalink
Subscription IDs and subscription list
Browse files Browse the repository at this point in the history
  • Loading branch information
OrKoN committed Dec 4, 2024
1 parent 20f1248 commit 89afc76
Showing 1 changed file with 77 additions and 178 deletions.
255 changes: 77 additions & 178 deletions index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -706,30 +706,15 @@ occurred on the [=remote end=].
are run when multiple events are enabled at once, with lower integers
indicating steps that run earlier.

A [=BiDi session=] has a <dfn export for=event>global event set</dfn>
which is a [=/set=] containing the event names for events that are enabled for all
navigables. This initially contains the [=event name=] for events that
are <dfn export for=event>in the default event set</dfn>.

A [=BiDi session=] has a <dfn export for=event>navigable event map</dfn>,
which is a [=/map=] with [=/top-level traversable=] keys and values
that are a [=/set=] of [=event name=]s for events that are enabled in the given
navigable.

<div algorithm>

To obtain a list of <dfn>event enabled navigables</dfn> given
|session| and |event name|:

1. Let |navigables| be an empty [=/set=].
A [=BiDi session=] has a <dfn export for=event>subscriptions</dfn>
which is a [=/list=] of [=subscription=].

1. For each |navigable| → |events| of |session|'s [=navigable event map=]:
A <dfn for=event>subscription</dfn> is a [=/struct=] consisting of a
subscription id (a string), event names (a [=/list=] of event names) and
contexts (a [=/list=] of context ids).

1. If |events| contains |event name|, append |navigable| to |navigables|

1. Return |navigables|.

</div>
TODO: I think event names and contexts are better be sets.
TODO: lookup how struct fields are defined.

<div algorithm>

Expand Down Expand Up @@ -759,46 +744,23 @@ Note: |navigables| is a set because a [=shared worker=] can be associated

1. For each |navigable| of |navigables|, append |navigable|'s [=navigable/top-level traversable=] to |top-level traversables|.

1. Let |event map| be the [=navigable event map=] for |session|.
1. For each |subscription| in |session|'s [=subscriptions=]:

1. For each |navigable| of |top-level traversables|:
1. If |subscription|' event names is not an empty list and if
|subscription|' event names does not [=list/contains] |event name|, continue.
1. If |event map| [=map/contains=] |navigable|, let |navigable events|
be |event map|[|navigable|]. Otherwise let |navigable events| be null.
1. If |subscription|' contexts is an empty list,
return true.
1. If |navigable events| is not null, and |navigable events|
[=list/contains=] |event name|, return true.
1. For each |navigable| of |top-level traversables|:
1. If the [=global event set=] for |session| [=list/contains=] |event name| return
true.
1. If |subscription|' contexts [=list/contains] |navigable| [=navigable id=],
return true.

1. Return false.

</div>

<div algorithm>
To <dfn>obtain a set of event names</dfn> given an |name|:

1. Let |events| be an empty [=/set=].

1. If |name| contains a U+002E (period):

1. If |name| is the [=event name=] for an event, append |name| to |events|
and return [=success=] with data |events|.

1. Return an [=error=] with [=error code=] [=invalid argument=]

1. Otherwise |name| is interpreted as representing all the events in a
module. If |name| is not a [=module name=] return an [=error=] with
[=error code=] [=invalid argument=].

1. Append the [=event name=] for each [=event=] in the module with name |name| to
|events|.

1. Return [=success=] with data |events|.

</div>

# Transport # {#transport}

Message transport is provided using the WebSocket protocol.
Expand Down Expand Up @@ -1482,113 +1444,6 @@ To <dfn>cleanup remote end state</dfn>.

</div>

<div algorithm>
To <dfn>update the event map</dfn>, given
|session|, |requested event names|, |navigables|, and |enabled|:

Note: The return value of this algorithm is a map between event names and
navigables. When the events are being enabled, the navigables in the return value
are those for which the event are now enabled but were not previously. When
events are disabled, the return value is always empty.

1. Let |global event set| be a [=set/clone=] of the [=global event set=] for
|session|.

1. Let |event map| be a new [=/map=].

1. For each |key| → |value| of the [=navigable event map=] for
|session|:

1. Set |event map|[|key|] to a [=set/clone=] of |value|.

1. Let |event names| be an empty [=/set=].

1. For each entry |name| in |requested event names|,
let |event names| be the union of |event names| and the result of
[=trying=] to [=obtain a set of event names=] with |name|.

1. Let |enabled events| be a new [=/map=].

1. If |navigables| is null:

1. If |enabled| is true:

1. For each |event name| of |event names|:

1. If |global event set| doesn't contain |event name|:

1. Let |already enabled navigables| be the [=event enabled navigables=]
given |session| and |event name|.

1. Add |event name| to |global event set|.

1. For each |navigable| of |already enabled navigables|, remove |event
name| from |event map|[|navigable|].

1. Let |newly enabled contexts| be a list of all [=/top-level traversable=]
that are not contained in |already enabled navigables|,

1. Set |enabled events|[|event name|] to |newly enabled contexts|.

1. If |enabled| is false:

1. For each |event name| in |event names|:

1. If |global event set| [=list/contains=] |event name|, remove |event
name| from |global event set|. Otherwise return [=error=] with
[=error code=] [=invalid argument=].

1. Otherwise, if |navigables| is not null:

1. Let |targets| be an empty [=/map=].

1. For each |navigable id| in |navigables|:

1. Let |navigable| be the result of [=trying=] to [=get a navigable=]
with |navigable id|.

1. Let |top-level traversable| be the [=navigable/top-level traversable=] for |navigable|.

1. If |event map| does not contain |top-level traversable|, set |event
map|[|top-level traversable|] to a new [=/set=].

1. Set |targets|[|top-level traversable|] to |event map|[|top-level traversable|].

1. For each |event name| in |event names|:

1. If |enabled| is true and |global event set| contains |event name|, continue.

1. For each |navigable| → |target| in |targets|:

1. If |enabled| is true and |target| does not contain |event name|:

1. Add |event name| to |target|.

1. If |enabled events| does not contain |event name|, set |enabled
events|[|event name|] to a new [=/set=].

1. Append |navigable| to |enabled events|[|event name|].

1. If |enabled| is false:

1. If |target| contains |event name|, remove |event name| from
|target|. Otherwise return [=error=] with [=error code=] [=invalid
argument=].

1. Set the [=global event set=] for |session| to |global event set|.

1. Set the [=navigable event map=] for |session| to |event map|.

1. Return [=success=] with data |enabled events|.

Note: Implementations that do additional work when an event is enabled,
e.g. subscribing to the relevant engine-internal events, will likely perform
those additional steps when updating the event map. This specification uses
a model where hooks are always called and then the event map is used to
filter only those that ought to be returned to the local end.

</div>

### Types ### {#module-session-types}

#### The session.CapabilitiesRequest Type #### {#type-session-CapabilitiesRequest}
Expand Down Expand Up @@ -1733,6 +1588,14 @@ session.UserPromptHandlerType = "accept" / "dismiss" / "ignore";
The <code>session.UserPromptHandlerType</code> type represents the behavior
of the user prompt handler.

#### The session.Subscription Type #### {#type-session-Subscription}

<pre class="cddl remote-cddl local-cddl">
session.Subscription = text
</pre>

The <code>session.Subscription</code> type represents a unique subscription identifier.

#### The session.SubscriptionRequest Type #### {#type-session-SubscriptionRequest}

<pre class="cddl remote-cddl">
Expand All @@ -1745,6 +1608,17 @@ session.SubscriptionRequest = {
The <code>session.SubscriptionRequest</code> type represents a request to
subscribe to or unsubscribe from a specific set of events.

#### The session.UnsubscribeRequest Type #### {#type-session-UnsubscribeRequest}

<pre class="cddl remote-cddl">
session.UnsubscribeRequest = {
subscribtion: session.Subscription,
}
</pre>

The <code>session.UnsubscribeRequest</code> type represents a request to
usubscribe using a subscription ID.

### Commands ### {#module-session-commands}

#### The session.status Command #### {#command-session-status}
Expand Down Expand Up @@ -1938,8 +1812,10 @@ Issue: This needs to be generalized to work with realms too.
</dd>
<dt>Result Type</dt>
<dd>
<pre class="cddl">
EmptyResult
<pre class="cddl local-cddl">
session.SubscriptionRequestResult = {
subscription: session.Subscription,
}
</pre>
</dd>
</dl>
Expand All @@ -1950,19 +1826,31 @@ The [=remote end steps=] with |session| and |command parameters| are:
1. Let the |list of event names| be the value of the <code>events</code> field of
|command parameters|

1. Let the |list of navigables| be the value of the <code>contexts</code>
field of |command parameters| if it is present or null if it isn't.
1. Let the |list of context ids| be the value of the <code>contexts</code>
field of |command parameters| if it is present or an empty [=/list=] if it isn't.

1. Let |enabled events| be the result of [=trying=] to [=update the event map=]
with |session|, |list of event names| , |list of navigables| and
enabled true.
1. Let |subscription| be a [=subscription=] with subscription id set to the string representation of a UUID,
event names set to |list of event names|, contexts set to |list of context ids|.

1. Let |subscribe step events| be a new [=/map=].

1. For each |event name| → |navigables| in |enabled events|:
1. For each |event name| in the |list of event names|:

1. If the [=event=] with [=event name=] |event name| does not define [=remote end
subscribe steps=], continue;

1. Let |existing navigables| be a set of navigables for which either a global
subscription is defined or a subscription listing navigables's top-level navigable's id.

1. If the [=event=] with [=event name=] |event name| defines [=remote end
subscribe steps=], set |subscribe step events|[|event name|] to |navigables|.
TODO: define the step above better.

1. Let |newly subscribed navigables| be all top-level navigables if |list of context ids| is empty,
or navigables identified by ids in |list of context ids|.

1. Set |subscribe step events|[|event name|] to navigables that are included in |newly subscribed navigables|
and not included in |existing navigables|.

1. Append |subscription| to |session|'s [=subscriptions=].

1. [=map/Sort in ascending order=] |subscribe step events| using the following less
than algorithm given two entries with keys |event name one| and |event
Expand All @@ -1975,7 +1863,7 @@ The [=remote end steps=] with |session| and |command parameters| are:
1. Return true if |event one|'s [=subscribe priority=] is less than |event
two|'s subscribe priority, or false otherwise.

1. If |list of navigables| is null, let |include global| be true, otherwise let
1. If |list of context ids| is null, let |include global| be true, otherwise let
|include global| be false.

1. For each |event name| → |navigables| in |subscribe step events|:
Expand All @@ -2000,7 +1888,7 @@ Issue: This needs to be generalised to work with realms too.
<pre class="cddl remote-cddl">
session.Unsubscribe = (
method: "session.unsubscribe",
params: session.SubscriptionRequest
params: session.SubscriptionRequest / session.UnsubscribeRequest,
)
</pre>
</dd>
Expand All @@ -2015,14 +1903,25 @@ Issue: This needs to be generalised to work with realms too.
<div algorithm="remote end steps for session.unsubscribe">
The [=remote end steps=] with |session| and |command parameters| are:

1. Let the |list of event names| be the value of the <code>events</code> field of
|command parameters|.
1. If |command parameters| matches the session.SubscriptionRequest production:

1. Let the |list of event names| be the value of the <code>events</code> field of
|command parameters|.

1. Let the |list of contexts| be the value of the <code>contexts</code>
field of |command parameters| if it is present or an empty [=/list=] if it isn't.

1. Remove all subscriptions from |session|'s [=subscriptions=] whose event names is |list of event names|
and whose contexts is |list of contexts|.

TODO: define how to match subscriptions.

1. Otherwise:

1. Let the |list of contexts| be the value of the <code>contexts</code>
field of |command parameters| if it is present or null if it isn't.
1. Let the |subscription id| be |command parameters|[<code>subscription</code>].

1. [=Try=] to [=update the event map=] with |session|,
|list of event names|, |list of contexts| and enabled false.
1. Remove all subscribtions from |session|'s [=subscriptions=] whose subscription id
is |subscription id|.

1. Return [=success=] with data null.

Expand Down

0 comments on commit 89afc76

Please sign in to comment.