# SignalR

## System-defined events

Portos API triggers following system-defined events, which can be handled in client applications:

| Event             | Event name                 | Description                                                    |
| ----------------- | -------------------------- | -------------------------------------------------------------- |
| Resource changed  | `portos.resources.changed` | Raised when resource is changed (created, updated or deleted). |
| License activated | `portos.licence.activated` | Raised when Portos license is activated.                       |

## Receiving Events from Portos API

To receive events from the Portos API, the client application must follow these steps:

1. [Configure authentication](#client-authentication) when communicating with SignalR server.
2. [Register an event Handler](#register-event-handler): specify the client application method to invoke when a notification is sent from the Portos API.
3. [Start the connection](#start-the-connection) to SignalR server.
4. [Subscribe to Events](#subscribe-to-events) using the `Subscribe` method, so the Portos API will deliver notifications to the client application.

{% hint style="info" %}
The code examples below uses JavaScript and [Microsoft's SignalR library](https://learn.microsoft.com/en-us/aspnet/core/signalr/javascript-client). You can install it using npm:

<pre class="language-sh"><code class="lang-sh"><strong>npm install @microsoft/signalr
</strong></code></pre>

{% endhint %}

## Client authentication

When communicating with SignalR server, client application must be authenticated, as described in [Authentication](https://developers.portos.sk/authentication) section. Obtained accces token must be used when communication with notification server.

```javascript
const token = "YOUR_BEARER_TOKEN"; // Replace with your actual token
const serverAddress = "SERVER_ADDRESS"; // Replace with your actual server addess, e.g. http://localhost:3000

const connection = new signalR.HubConnectionBuilder()
    .withUrl(serverAddress + "/signalr/v1/mainHub", {
        accessTokenFactory: () => token
    })
    .build();
```

## Register Event Handler

Use the `connection.on` method to subscribe to the notification events. When a notification is received, the callback function will be executed, and you can handle the notification (e.g., update the UI).

```javascript
connection.on("OnEvent", function (message) {
    // Handle the notification (e.g., update UI)
    if (message.e == "portos.resources.changed") {
        // Resource has been changed
    } else if (message.e == "portos.licence.activated") {
        // Product license has been activated
        const newLicense = message.p;
    }
});
```

The incoming notification is represented by `Notification` class, described below.

#### Notification

| Property name | Type                                                                                                  | Description                                                                                           |
| ------------- | ----------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| `e`           | `string`                                                                                              | Event name, as listed in [System-defined events](#system-defined-events).                             |
| `s`           | [`NotificationSender`](#notificationsender)                                                           | Information about sender, who sends the message (usually, the server/API).                            |
| `r`           | `string?`                                                                                             | Optional notification reference identifier.                                                           |
| `ca`          | `DateTime`                                                                                            | "Created At" ISO8601-formatted string representing date and time of notification creation.            |
| `ea`          | `DateTime?`                                                                                           | "Expires At" Optional ISO8601-formatted string representing date and time of notification expiration. |
| `p`           | [`License`](https://developers.portos.sk/data-models#license) `\| ResourceChangedNotificationPayload` | The notification payload. Based on event, payload may vary.                                           |

#### NotificationSender

| Property name | Type                                                                | Description                                                             |
| ------------- | ------------------------------------------------------------------- | ----------------------------------------------------------------------- |
| `c`           | `string`                                                            | Connection identifier.                                                  |
| `u`           | [`NotificationSenderUserIdentity`](#notificationsenderuseridentity) | Information about sender, who performs action resulting in given event. |

#### NotificationSenderUserIdentity

| Property name | Type      | Description                                                                                                          |
| ------------- | --------- | -------------------------------------------------------------------------------------------------------------------- |
| `u`           | `string`  | Unique user name or "System" for system events.                                                                      |
| `d`           | `string`  | Name of device, on which user operates on. Or "System" for system events.                                            |
| `f`           | `string?` | <p>Feature name.<br>Specified if source of event is not user, but system module (feature), a.k.a "virtual user".</p> |

#### ResourceChangedNotificationPayload

| Property name | Type                            | Description                                                                                 |
| ------------- | ------------------------------- | ------------------------------------------------------------------------------------------- |
| `u`           | [`UserIdentity`](#useridentity) |                                                                                             |
| `n`           | `string`                        | One of system-defined [resource names](https://developers.portos.sk/resource-names).        |
| `a`           | `number`                        | <p>Numeric identifier for resource action.<br>1 = Created<br>2 = Updated<br>3 = Deleted</p> |
| `i`           | [`ResourceInfo`](#resourceinfo) | Information about changed resource.                                                         |
| `r`           | `object[]`                      | Collection of affected resources.                                                           |

#### UserIdentity

<table><thead><tr><th width="231.99999999999997">Property name</th><th width="146">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>u</code></td><td><code>string</code></td><td>Unique user identifier.</td></tr><tr><td><code>d</code></td><td><code>string</code></td><td>User display name.</td></tr><tr><td><code>f</code></td><td><code>string?</code></td><td>Name of "feature" (has value only for virtual users).</td></tr></tbody></table>

#### ResourceInfo

<table><thead><tr><th width="231.99999999999997">Property name</th><th width="146">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>i</code></td><td><code>string</code></td><td>Unique resource identifier (e.g. database ID).</td></tr><tr><td><code>n</code></td><td><code>string</code></td><td><a href="../resource-names">Resource name</a>.</td></tr><tr><td><code>v</code></td><td><code>number?</code></td><td>Version of resource.</td></tr></tbody></table>

Example payload for resource changed notification:

```json
{
  "e": "portos.resources.changed", // event name
  "s": { // sender who sends the notification
    "c": "connection-identifier",
    "u": {
      "u": "SYSTEM", // unique user name
      "d": "SYSTEM", // device name
      "f": null // feature name
    }    
  },
  "r": null, // reference ID
  "ca": "2024-07-01T12:51:52.558Z", // created at
  "ea": null, // expires at
  "p": { // notification payload
    "u": { // user who performed action resulting in resource change
      "u": "999", // unique user name
      "d": "BackOffice", // device name
      "f": null // feature name
    },
    "n": "tickets", // resource name
    "a": 1, // action (1 = created, 2 = updated, 3 = deleted)
    "i": { // resource info
      "i": "573f4511088c772684a738f8", // resource ID
      "n": "tickets", // resource name
      "v": 7 // resource version
    },
    "r": [
      { ... }  // the ticket object
    ]
  }
}
```

## Start the connection

To start the connection, await the result of the `start` method call.

```javascript
// Start the connection
await connection.start();
```

## Subscribe to Events

To subscribe to Portos events, a client application must send a "Subscribe" message containing a payload with the subscription details. In the payload, the client application specifies which [system-defined events](#system-defined-events) to subscribe to.

### Subscribe to Resource Changed Event

To subscribe to resource change events, your client application must set `portos.resources.changed` in the payload property's `e` (event name). Optionally, you can also specify a collection of resources. Please refer to the table below:

| Property name | Type                                                              | Description                                                                                                            |
| ------------- | ----------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| `e`           | `string`                                                          | The event name. Set to `portos.resources.changed`                                                                      |
| `r`           | [`SubscriptionRequestResource`](#subscriptionrequestresource)`[]` | Optional collection of resources that is client application subscribing to. Leave empty to subscribe to all resources. |

#### SubscriptionRequestResource

| Property name | Type       | Description                                                                                                                                                                                                                 |
| ------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `n`           | `string`   | One of system-defined [resource names](https://developers.portos.sk/resource-names).                                                                                                                                        |
| `a`           | `string[]` | <p>Optional collection of actions that is client application subscribing to. Leave empty to subscribe to all actions. Allowed values:<br><br>- <code>created</code><br>- <code>updated</code><br>- <code>deleted</code></p> |

Example:

<pre class="language-javascript"><code class="lang-javascript">// Prepare the subscription payload
const subscriptionPayload = {
<strong>    e: "portos.resources.changed", // event name
</strong>    r: [ // optional collection of resources
        {
            n: "devices", // resource name
            a: [ // optional collection of actions
                "created",
                "updated",
                "deleted"
            ]
        }
    ]
};

// Send the 'Subscribe' message with the payload
await connection.invoke("Subscribe", subscriptionPayload);
</code></pre>

### Subscribe to License activated event

To subscribe to license activated event, your client application must set `portos.licence.activated` in the payload property  `e` (event name).&#x20;

Example:

```javascript
// Prepare the subscription payload
const subscriptionPayload = {
    e: "portos.licence.activated" // event name
};

// Send the 'Subscribe' message with the payload
await connection.invoke("Subscribe", subscriptionPayload);
```

## Unsubscribe from Events

To unsubscribe, invoke the `Unsubscribe` method with the same parameters used for event subscription.

```javascript
// Prepare the same payload as for subscription
const payload = {
    e: "portos.licence.activated" // event name
};

// Send the 'Unsubscribe' message with the payload
await connection.invoke("Unsubscribe", payload);
```
