diff --git a/docs/capabilities.md b/docs/capabilities.md index 12ed3c4cb9..dbadbd1739 100644 --- a/docs/capabilities.md +++ b/docs/capabilities.md @@ -188,6 +188,7 @@ * `config => conversations => retention-instant-meetings` (local) - Number of days before an instant meeting conversation is deleted (`0` = disabled) * `config => conversations => retention-phone` (local) - Number of days before an inactive incoming or outgoing phone conversation is deleted (`0` = disabled) * `config => call => predefined-backgrounds-v2` (local) - Whether virtual backgrounds should be read from the theming directory +* `config => experiments => enabled` (local) - Bit flag of enabled experiments for clients * `dashboard-event-rooms` (local) - Whether Talk APIs offer functionality for Dashboard requests * `mutual-calendar-events` (local) - Whether Talk APIs offer mutual calendar events for 1:1 rooms * `upcoming-reminders` (local) - Whether the API to list upcoming reminders exists diff --git a/docs/settings.md b/docs/settings.md index 84148cfeef..a4c4351a3a 100644 --- a/docs/settings.md +++ b/docs/settings.md @@ -102,6 +102,8 @@ Legend: | `retention_event_rooms` | int | `28` | No | | Retention period of event conversations in days (`0` means no-retention) | | `retention_phone_rooms` | int | `7` | No | | Retention period of phone dial-in and dial-out conversations in days (`0` means no-retention) | | `retention_instant_meetings` | int | `1` | No | | Retention period of instant meetings in days (`0` means no-retention) | +| `experiments_users` | int | `0` | Yes | | Bit flag of experiments that should be enabled for logged-in users on this server (see [Experiments](#experiments) below) | +| `experiments_guests` | int | `0` | Yes | | Bit flag of experiments that should be enabled for guests on this server (see [Experiments](#experiments) below) | | `grid_videos_limit_enforced` | string
`yes` or `no` | `no` | No | | Whether the number of grid videos should be enforced | | `changelog` | string
`yes` or `no` | `yes` | No | | Whether the changelog conversation is updated with new features on major releases | | `has_reference_id` | string
`yes` or `no` | `no` | Yes | | Indicator whether the clients can use the reference value to identify their message, will be automatically set to `yes` when the repair steps are executed | @@ -128,3 +130,11 @@ Legend: | `backgrounds_branded_for_guests` | string
`1` or `0` | `0` | No | | Whether guests are allowed to use the virtual backgrounds provided via `themes/talk-backgrounds/` | | `backgrounds_default_for_users` | string
`1` or `0` | `1` | No | | Whether users are allowed to use the default virtual backgrounds provided by the releases | | `backgrounds_upload_users` | string
`1` or `0` | `1` | No | | Whether users are allowed to upload custom virtual backgrounds and choose from their Nextcloud Files | + +## Experiments + +Features that can be toggled on-off with the `experiments_users` and `experiments_guests` bit flags: + +| Bit | Status | Introduced | Ended | Description | +|-----|--------|----------------------------------|-------|-----------------------------------------------------------------------------------------------------------------------------| +| 1 | Active | Web 21.1.0
Desktop 1.2.2-beta | - | Instead of refreshing the participant list repeatingly during calls, the data is generated from received signaling messages | diff --git a/lib/Capabilities.php b/lib/Capabilities.php index 73ca815de1..194c1ff401 100644 --- a/lib/Capabilities.php +++ b/lib/Capabilities.php @@ -193,6 +193,9 @@ class Capabilities implements IPublicCapability { 'session-ping-limit', 'hello-v2-token-key', ], + 'experiments' => [ + 'enabled', + ], ]; protected ICache $talkCache; @@ -277,6 +280,9 @@ class Capabilities implements IPublicCapability { 'session-ping-limit' => max(0, (int)$this->serverConfig->getAppValue('spreed', 'session-ping-limit', '200')), // 'hello-v2-token-key' => string, ], + 'experiments' => [ + 'enabled' => max(0, $this->appConfig->getAppValueInt($user instanceof IUser ? 'experiments_users' : 'experiments_guests')), + ], ], 'config-local' => self::LOCAL_CONFIGS, 'version' => $this->appManager->getAppVersion('spreed'), diff --git a/lib/Controller/RoomController.php b/lib/Controller/RoomController.php index cba46422ae..de634542c2 100644 --- a/lib/Controller/RoomController.php +++ b/lib/Controller/RoomController.php @@ -190,6 +190,12 @@ class RoomController extends AEnvironmentAwareOCSController { $this->config->getAppValue('spreed', 'federation_allowed_groups', '[]'), ]; + if ($this->userId !== null) { + $values[] = $this->appConfig->getAppValueInt('experiments_users'); + } else { + $values[] = $this->appConfig->getAppValueInt('experiments_guests'); + } + return [ 'X-Nextcloud-Talk-Hash' => sha1(implode('#', $values)), ]; diff --git a/lib/ResponseDefinitions.php b/lib/ResponseDefinitions.php index ed4c28a784..8b96a68f5b 100644 --- a/lib/ResponseDefinitions.php +++ b/lib/ResponseDefinitions.php @@ -497,6 +497,9 @@ namespace OCA\Talk; * session-ping-limit: int, * hello-v2-token-key?: string, * }, + * experiments: array{ + * enabled: non-negative-int, + * }, * }, * config-local: array>, * version: string, diff --git a/openapi-administration.json b/openapi-administration.json index a15b611f13..45525338ff 100644 --- a/openapi-administration.json +++ b/openapi-administration.json @@ -120,7 +120,8 @@ "conversations", "federation", "previews", - "signaling" + "signaling", + "experiments" ], "properties": { "attachments": { @@ -349,6 +350,19 @@ "type": "string" } } + }, + "experiments": { + "type": "object", + "required": [ + "enabled" + ], + "properties": { + "enabled": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } } } }, diff --git a/openapi-backend-recording.json b/openapi-backend-recording.json index 4a87c1fc61..17f5b9dcdd 100644 --- a/openapi-backend-recording.json +++ b/openapi-backend-recording.json @@ -53,7 +53,8 @@ "conversations", "federation", "previews", - "signaling" + "signaling", + "experiments" ], "properties": { "attachments": { @@ -282,6 +283,19 @@ "type": "string" } } + }, + "experiments": { + "type": "object", + "required": [ + "enabled" + ], + "properties": { + "enabled": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } } } }, diff --git a/openapi-backend-signaling.json b/openapi-backend-signaling.json index cb0fdc3080..83591942fd 100644 --- a/openapi-backend-signaling.json +++ b/openapi-backend-signaling.json @@ -53,7 +53,8 @@ "conversations", "federation", "previews", - "signaling" + "signaling", + "experiments" ], "properties": { "attachments": { @@ -282,6 +283,19 @@ "type": "string" } } + }, + "experiments": { + "type": "object", + "required": [ + "enabled" + ], + "properties": { + "enabled": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } } } }, diff --git a/openapi-backend-sipbridge.json b/openapi-backend-sipbridge.json index f011dcd64b..d0ef358218 100644 --- a/openapi-backend-sipbridge.json +++ b/openapi-backend-sipbridge.json @@ -96,7 +96,8 @@ "conversations", "federation", "previews", - "signaling" + "signaling", + "experiments" ], "properties": { "attachments": { @@ -325,6 +326,19 @@ "type": "string" } } + }, + "experiments": { + "type": "object", + "required": [ + "enabled" + ], + "properties": { + "enabled": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } } } }, diff --git a/openapi-bots.json b/openapi-bots.json index 5f9062ebfd..5a529fd3bc 100644 --- a/openapi-bots.json +++ b/openapi-bots.json @@ -53,7 +53,8 @@ "conversations", "federation", "previews", - "signaling" + "signaling", + "experiments" ], "properties": { "attachments": { @@ -282,6 +283,19 @@ "type": "string" } } + }, + "experiments": { + "type": "object", + "required": [ + "enabled" + ], + "properties": { + "enabled": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } } } }, diff --git a/openapi-federation.json b/openapi-federation.json index 9828ec19c5..015c90b509 100644 --- a/openapi-federation.json +++ b/openapi-federation.json @@ -96,7 +96,8 @@ "conversations", "federation", "previews", - "signaling" + "signaling", + "experiments" ], "properties": { "attachments": { @@ -325,6 +326,19 @@ "type": "string" } } + }, + "experiments": { + "type": "object", + "required": [ + "enabled" + ], + "properties": { + "enabled": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } } } }, diff --git a/openapi-full.json b/openapi-full.json index fd9f8a407a..fd2af93a6d 100644 --- a/openapi-full.json +++ b/openapi-full.json @@ -254,7 +254,8 @@ "conversations", "federation", "previews", - "signaling" + "signaling", + "experiments" ], "properties": { "attachments": { @@ -483,6 +484,19 @@ "type": "string" } } + }, + "experiments": { + "type": "object", + "required": [ + "enabled" + ], + "properties": { + "enabled": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } } } }, diff --git a/openapi.json b/openapi.json index cda328e506..67fa443fb4 100644 --- a/openapi.json +++ b/openapi.json @@ -213,7 +213,8 @@ "conversations", "federation", "previews", - "signaling" + "signaling", + "experiments" ], "properties": { "attachments": { @@ -442,6 +443,19 @@ "type": "string" } } + }, + "experiments": { + "type": "object", + "required": [ + "enabled" + ], + "properties": { + "enabled": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } } } }, diff --git a/src/__mocks__/capabilities.ts b/src/__mocks__/capabilities.ts index 48fc9036bc..798ae1567a 100644 --- a/src/__mocks__/capabilities.ts +++ b/src/__mocks__/capabilities.ts @@ -178,6 +178,9 @@ export const mockedCapabilities: Capabilities = { 'session-ping-limit': 200, 'hello-v2-token-key': '123', }, + experiments: { + enabled: 0, + }, }, 'config-local': { attachments: [ @@ -215,6 +218,9 @@ export const mockedCapabilities: Capabilities = { 'session-ping-limit', 'hello-v2-token-key', ], + experiments: [ + 'enabled', + ], }, version: '20.0.0-dev.0', } diff --git a/src/types/openapi/openapi-administration.ts b/src/types/openapi/openapi-administration.ts index f07945cba8..4d77d785f6 100644 --- a/src/types/openapi/openapi-administration.ts +++ b/src/types/openapi/openapi-administration.ts @@ -278,6 +278,10 @@ export type components = { "session-ping-limit": number; "hello-v2-token-key"?: string; }; + experiments: { + /** Format: int64 */ + enabled: number; + }; }; "config-local": { [key: string]: string[]; diff --git a/src/types/openapi/openapi-backend-recording.ts b/src/types/openapi/openapi-backend-recording.ts index aa90fe07a9..964854ca67 100644 --- a/src/types/openapi/openapi-backend-recording.ts +++ b/src/types/openapi/openapi-backend-recording.ts @@ -112,6 +112,10 @@ export type components = { "session-ping-limit": number; "hello-v2-token-key"?: string; }; + experiments: { + /** Format: int64 */ + enabled: number; + }; }; "config-local": { [key: string]: string[]; diff --git a/src/types/openapi/openapi-backend-signaling.ts b/src/types/openapi/openapi-backend-signaling.ts index 458a23c11c..89555db4dd 100644 --- a/src/types/openapi/openapi-backend-signaling.ts +++ b/src/types/openapi/openapi-backend-signaling.ts @@ -98,6 +98,10 @@ export type components = { "session-ping-limit": number; "hello-v2-token-key"?: string; }; + experiments: { + /** Format: int64 */ + enabled: number; + }; }; "config-local": { [key: string]: string[]; diff --git a/src/types/openapi/openapi-backend-sipbridge.ts b/src/types/openapi/openapi-backend-sipbridge.ts index 675d655d27..49abf3f1f9 100644 --- a/src/types/openapi/openapi-backend-sipbridge.ts +++ b/src/types/openapi/openapi-backend-sipbridge.ts @@ -213,6 +213,10 @@ export type components = { "session-ping-limit": number; "hello-v2-token-key"?: string; }; + experiments: { + /** Format: int64 */ + enabled: number; + }; }; "config-local": { [key: string]: string[]; diff --git a/src/types/openapi/openapi-bots.ts b/src/types/openapi/openapi-bots.ts index c7d3b0f5f7..ed9382a174 100644 --- a/src/types/openapi/openapi-bots.ts +++ b/src/types/openapi/openapi-bots.ts @@ -116,6 +116,10 @@ export type components = { "session-ping-limit": number; "hello-v2-token-key"?: string; }; + experiments: { + /** Format: int64 */ + enabled: number; + }; }; "config-local": { [key: string]: string[]; diff --git a/src/types/openapi/openapi-federation.ts b/src/types/openapi/openapi-federation.ts index 81f3dd82a9..9539e8e2f8 100644 --- a/src/types/openapi/openapi-federation.ts +++ b/src/types/openapi/openapi-federation.ts @@ -224,6 +224,10 @@ export type components = { "session-ping-limit": number; "hello-v2-token-key"?: string; }; + experiments: { + /** Format: int64 */ + enabled: number; + }; }; "config-local": { [key: string]: string[]; diff --git a/src/types/openapi/openapi-full.ts b/src/types/openapi/openapi-full.ts index e95af6dc34..6091d318d3 100644 --- a/src/types/openapi/openapi-full.ts +++ b/src/types/openapi/openapi-full.ts @@ -2234,6 +2234,10 @@ export type components = { "session-ping-limit": number; "hello-v2-token-key"?: string; }; + experiments: { + /** Format: int64 */ + enabled: number; + }; }; "config-local": { [key: string]: string[]; diff --git a/src/types/openapi/openapi.ts b/src/types/openapi/openapi.ts index c33c9522d2..080fd159ac 100644 --- a/src/types/openapi/openapi.ts +++ b/src/types/openapi/openapi.ts @@ -1712,6 +1712,10 @@ export type components = { "session-ping-limit": number; "hello-v2-token-key"?: string; }; + experiments: { + /** Format: int64 */ + enabled: number; + }; }; "config-local": { [key: string]: string[]; diff --git a/tests/php/CapabilitiesTest.php b/tests/php/CapabilitiesTest.php index 0a2efe7da8..0be528c9fb 100644 --- a/tests/php/CapabilitiesTest.php +++ b/tests/php/CapabilitiesTest.php @@ -115,6 +115,7 @@ class CapabilitiesTest extends TestCase { ['retention_event_rooms', 28, 28], ['retention_phone_rooms', 7, 7], ['retention_instant_meetings', 1, 1], + ['experiments_guests', 0, 0], ]); $this->assertInstanceOf(IPublicCapability::class, $capabilities); @@ -195,6 +196,9 @@ class CapabilitiesTest extends TestCase { 'signaling' => [ 'session-ping-limit' => 200, ], + 'experiments' => [ + 'enabled' => 0, + ], ], 'config-local' => Capabilities::LOCAL_CONFIGS, 'version' => '1.2.3', @@ -280,6 +284,7 @@ class CapabilitiesTest extends TestCase { ['retention_event_rooms', 28, 28], ['retention_phone_rooms', 7, 7], ['retention_instant_meetings', 1, 1], + ['experiments_users', 0, 0], ]); $this->assertInstanceOf(IPublicCapability::class, $capabilities); @@ -363,6 +368,9 @@ class CapabilitiesTest extends TestCase { 'signaling' => [ 'session-ping-limit' => 50, ], + 'experiments' => [ + 'enabled' => 0, + ], ], 'config-local' => Capabilities::LOCAL_CONFIGS, 'version' => '1.2.3',