Skip to content

Commit

Permalink
Merge pull request #31 from Cynerd/hide-signals
Browse files Browse the repository at this point in the history
Hide signals
  • Loading branch information
fvacek authored Mar 8, 2024
2 parents d2afe6a + e1b6214 commit 1e10df9
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 99 deletions.
2 changes: 1 addition & 1 deletion src/rpcmessage.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ Error codes
| 9 | `Unknown` | Used if error failure can't be determined (use only if absolutely necessary)
| 10 | `LoginRequired` | Method call without previous successful login.
| 11 | `UserIDRequired` | Method call requires UserID to be present in the request message. Send it again with UserID.
| 12 | `NotCallable` | Generated when `RpcRequest` is received for signal
| 12 | `NotImplemented` | Can be used if method is valid but not implemented for what ever reason.
| 32 | `UserCode` |

**Examples**
Expand Down
42 changes: 38 additions & 4 deletions src/rpcmethods/app.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ these additions you can use this number.

## `.app:name`

| Name | SHV Path | Signature | Flags | Access |
|-----------|----------|-------------|--------|--------|
| Name | SHV Path | Signature | Flags | Access |
|--------|----------|-------------|--------|--------|
| `name` | `.app` | `ret(void)` | Getter | Browse |

This method must provide the name of the application, or at least the SHV
Expand All @@ -63,14 +63,18 @@ implementation used in the application.

## `.app:version`

| Name | SHV Path | Signature | Flags | Access |
|--------------|----------|-------------|--------|--------|
| Name | SHV Path | Signature | Flags | Access |
|-----------|----------|-------------|--------|--------|
| `version` | `.app` | `ret(void)` | Getter | Browse |

This method must provide the application version, or at least the SHV
implementation used in the application (must be consistent with information in
`.app:appName`).

| Parameter | Result |
|-----------|--------|
| Null | String |

```
=> <id:42, method:"version", path:".app">i{}
<= <id:42>i{2:"1.4.2-s5vehx"}
Expand All @@ -94,3 +98,33 @@ well as to keep connection in case of SHV Broker.
=> <id:42, method:"ping", path:".app">i{}
<= <id:42>i{}
```

## `.app:date`

| Name | SHV Path | Signature | Flags | Access |
|--------|----------|-------------|-------|--------|
| `date` | `.app` | `ret(void)` | | Browse |

This is an optional method that provides access to the date and time this
application is using (that includes time zone). Applications running on systems
without RTC are expected to implement this method. You must implement this any
time methods this application provides to SHV works with date and time.

You should use this to detect time shift between your time and time of the
device you are talking to. Date and time sent by device will be relative to this
one and thus even if it has wrong time set you have change to calculate the
correct one. The same applies the other way around, but in general such methods
should be avoided.

Note that there is unspecified overhead of SHV RPC network in up to seconds for
transferring messages and thus precision of comparison with local time must
consider this.

| Parameter | Result |
|-----------|----------|
| Null | DateTime |

```
=> <id:42, method:"date", path:".app">i{}
<= <id:42>i{2:d"2017-05-03T15:52:31.123"}
```
116 changes: 50 additions & 66 deletions src/rpcmethods/discovery.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,31 +12,28 @@ associated with it.
This method needs to be implemented for every node (that is every valid SHV
path). It provides a way to list all available methods and signals of the node.

| Parameter | Result |
|-----------------|-------------------------------------------------------------------------------------------------|
| Null \| `false` | [i{1:String, 2:Int<0,15>, 2:String, 4:String, 5:String}, ...] |
| `true` | [{"name":String, "flags":Int<0,31>, "param":String, "result":String, "access":String ...}, ...] |
| String | i{1:String, 2:Int<0,15>, 3:String, 4:String, 5:String} |
| Parameter | Result |
|---------------------------|---------------|
| Null \| `false` \| `true` | [i{...}, ...] |
| String | Bool |

This method can be called with or without parameter. The valid parameters are:

* *Null* or `false` and in such case all methods are listed with their info in
*IMap*.
* `true` is same as `false` or *Null* with exception that result is expected to
be *Map* instead of *IMap*. That allows custom extension that is beneficial in
some cases. The implementations that do not support this extension are allowed
to return *IMap* just like for *Null* or `false`.
* *String* with possible method name for which info should be provided. *Null*
is provided if there is no such method.

The method info in both *IMap* and *Map* must contain these fields:

* `"name"` for *Map* and `1` for *IMap* with string containing method's name.
* `"flags"` for *Map* and `2` for *IMap* needs to have integer value assembled
from the following ones:
* `1` (`1 << 0`) specifies that this is a signal and thus can't be explicitly
called but rather it gets automatically emitted on some event. Requests sent
to this name must result in `NotCallable` error.
* *Null* or `false` and in such case all methods are listed with their info.
* `true` is same as `false` or *Null* with exception that result can also
contain extra map.
* *String* with possible method name for which `true` is returned if node has
such method and `false` if there is no such method.

The method info in *IMap* must contain these fields:

* `1`: string containing method's name. This must be unique name for single
node. It is not allowed to provide multiple descriptions with same name for
the same node.
* `2`: is integer value flag assembled from the following values:
* `1` (`1 << 0`) no longer used and reserved for compatibility reasons. In the
past it signaled that name is not callable. New implementations should
ignore method descriptions with this bit set.
* `2` (`1 << 1`) specifies that method is a getter. This method must be
callable without side effects without any parameter.
* `4` (`1 << 2`) specifies that method is a setter. This method must be
Expand All @@ -52,59 +49,42 @@ The method info in both *IMap* and *Map* must contain these fields:
because first execution will invalidate the submit ID and thus prevents
re-execution.
* `32` (`1 << 5`) specifies that method requires ClientID to be called.
* `"param"` for *Map* and `3` for *IMap* with *String* name of the parameter
type as value. It can be missing or have value `null` instead of *String* if
method takes no parameter (or `null`).
* `"result"` for *Map* and `4` for *IMap* with *String* name of the provided
value type as value. It can be missing or have value `null` instead of
*String* if method provides no value (or `null`).
* `"access"` for *Map* and `5` for *IMap* that is used to inform about minimal
access level needed to invoke the method. If client has lower access level
than request to this method is going to result in an error. Note that actual
user's access level is defined by SHV broker and deduced by potentially
complex rule set. The allowed values are:
* `"bws"` (browse) is the lowest access level allowing to discover SHV nodes
and methods.
* `"rd"` (read) allows reading of values.
* `"wr"` (write) allows setting values.
* `"cmd"` (command) allows performing a commanding operation.
* `"cfg"` (config) allows changing configuration values.
* `"srv"` (service) allows access to the service info.
* `"ssrv` (super service) allows access to the service info that can't be
included for what ever reason in `"srv"`.
* `"dev"` (develop) is the highest common access level. Methods with this
access level provide access to the functionality that is needed only for
testing and development.
* `"su"` (admin) is the absolutely highest access level. It is commonly not
used for the method access limitation because this level should not be
commonly assigned. It serves as a special management access level as well
as broker to broker level.
* `"source"` for *Map* and `6` for *IMap* that informs about source method for
this signal (*String*). It must be used alongside with flag `1`. The multiple
sources can be specified in list (*List* of *String*). This signal must be
always emitted with one of these sources set.
Calling this method without it should result in `UserIDRequired` error.
* `3`: defines parameter type for the requests. Type is a *String* identifier.
It can be missing or have value *Null* instead of *String* if method takes no
parameter (or only *Null*).
* `4`: defines result type for the responses. The is a *String* identifier. It
can be missing or have value *Null* instead of *String* if method provides no
value (or only *Null*).
* `5`: specifies minimal access level needed to call this method as *Int*. The
allowed values can be found in table in [RpcMessage](../rpcmesasge.md)
article.
* `6`: is used for signals associated with this method. Signals have their names
and type identifier for value they carry. They are specified as a *Map* from
signal's name to *String* type identifier. It is allowed to use *Null* instead
of *String* for type and in such case type is the method's result type (of
course field `4` must be defined).
* `63` extra *Map* that can contain anything you want. It is provided only if
`true` is passed as argument and can be used to provide additional
implementation specific info for this method.

Examples of `dir` requests:

```
=> <id:42, method:"dir", path:"">i{}
<= <id:42>i{2:[i{1:"dir", 2:0, 3:"idir", 4:"odir", 5:"bws"},i{1:"ls", 2:0, 3:"idir", 4:"odir", 5:"bws", 6:"lsmod"}]}
<= <id:42>i{2:[i{1:"dir", 2:0, 3:"idir", 4:"odir", 5:1},i{1:"ls", 2:0, 3:"ils", 4:"ols", 5:1, 6:{"lsmod":"olsmod"}}]}
```
```
=> <id:43, method:"dir", path:"test/path">i{1:false}
<= <id:43>i{2:[i{1:"dir", 2:0, 3:"idir", 4:"odir", 5:"bws"},i{1:"ls", 2:0, 3:"idir", 4:"odir", 5:"bws", 6:"lsmod"},{1:"get", 2:2, 3:"iget" e:"String", 5:"rd", 6:"chng"}]}
<= <id:43>i{2:[i{1:"dir", 2:0, 3:"idir", 4:"odir", 5:1},i{1:"ls", 2:0, 3:"ils", 4:"ols", 5:1, 6:{"lsmod":"olsmod"}},{1:"get", 2:2, 3:"iget", 4:"String", 5:8, 6:{"chng":null}}]}
```
```
=> <id:44, method:"dir", path:"test/path">i{1:"get"}
<= <id:44>i{2:i{1:"get", 2:2, 3:"iget" 4:"String", 5:"rd", 6:"chng"}}
<= <id:44>i{2:true}
```
```
=> <id:44, method:"dir", path:"test/path">i{1:"nonexistent"}
<= <id:44>i{2:null}
```
```
=> <id:43, method:"dir", path:"test/path">i{1:true}
<= <id:43>i{2:[{"name":"dir", "flags":0, "param":"idir", "result":"odir", "access":"bws"},i{"name":"ls", "flags":0, "param":"idir", "result":"odir", "access":"bws"},{"name":"get", "flags":2, "param":"iget" "result":"String", "access":"rd", "signal":"chng"}]}
<= <id:44>i{2:false}
```

The previous version (before SHV RPC 3.0) supported both *Null* and *String* but
Expand All @@ -114,6 +94,14 @@ list (with one or no maps). Even older implementations provided list of lists
support all existing devices should support both of the old representations as
well as the latest one.

The compatibility mapping between *IMap* keys and historical *Map* is:

| IMap key | Map key |
|----------|-----------------------------------------------------------------------------------|
| `1` | `"name"` |
| `2` | `"flags"` |
| `5` | `"access"` or `"accessGrant"` but value is string like for `Access` in RpcMessage |

## `*:ls`

| Name | SHV Path | Signature | Flags | Signal | Access |
Expand Down Expand Up @@ -155,11 +143,7 @@ The previous versions (before SHV RPC 0.1) supported *Null* argument but not
discouraged to be used by new clients. The *Null* variant is fully backward
compatible.

## `*:lsmod`

| Name | SHV Path | Signature | Flags | Source | Access |
|---------|----------|-------------|--------|--------|--------|
| `lsmod` | Any | `ret(void)` | Signal | `ls` | Browse |
### Signal `lsmod`

The signal that has to be sent if there is change in the result of the `*:ls`
method. This includes case when new nodes are added as well as when nodes are
Expand Down
2 changes: 1 addition & 1 deletion src/rpcmethods/file.md
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,6 @@ outside file boundary.
The parameter is sequence of bytes to be appended to the file.

```
=> <id:42, method:"truncate", path:"test/file">i{1:1024}
=> <id:42, method:"truncate", path:"test/file">i{1:b"Some text..."}
<= <id:42>i{}
```
51 changes: 24 additions & 27 deletions src/rpcmethods/property.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,30 @@ specified age the value can be served from cache.
<= <id:42>i{2:"Cached"}
```

### Signal `*chng`

Value change can be optionally signaled with signal. It is used when you have
desire to get info about value change without polling. Note that signal might
not be emitted just on value change (that means old value can be same as the new
one) and it might not be emitted on some value changes (for example if change
was under some notification deadband level). To get latest value you should
always use `*:get` instead of waiting for `*chng` signal but if you receive
`*chng` then you can save yourself a `*:get` call.

The signal name can be either just `chng` or any name with that as suffix (such
as `fchng`).

The `*chng` needs to provide the same value as `*:get` would, which is value
associated with the SHV path.

| Value |
|-------|
| Any |

```
<= <signal:"chng", path:"test/property", source:"get">i{1:"Hello World"}
## `*:set`
| Name | SHV Path | Signature | Flags | Access |
Expand All @@ -58,30 +82,3 @@ reference is read-write property and real value is read-only one.
=> <id:42, method:"set", path:"test/property">i{1:"Hello World"}
<= <id:42>i{}
```

## `*:*chng`

| Name | SHV Path | Signature | Flags | Source | Access |
|---------|----------|-------------|--------|--------|--------|
| `*chng` | Any | `ret(void)` | Signal | `get` | Read |

This is signal, and thus it gets emitted on its own and can't be called. It is
used when you have desire to get info about value change without polling. Note
that signal might not be emitted just on value change (that means old value can
be same as the new one) and it might not be emitted on some value changes (for
example if change was under some notification deadband level). To get latest
value you should always use `*:get` instead of waiting for `*:*chng` signal but
if you receive `*:*chng` then you can save yourself a `*:get` call.

The signal name can be either just `chng` or any name with that as suffix (such
as `fchng`).

The `*:*chng` needs to provide the same value as `*:get` would, which is value
associated with the SHV path.

| Value |
|-------|
| Any |

```
<= <signal:"chng", path:"test/property", source:"get">i{1:"Hello World"}

0 comments on commit 1e10df9

Please sign in to comment.