Kate
1 year ago
committed by
GitHub
24 changed files with 104913 additions and 6737 deletions
@ -0,0 +1 @@ |
|||||||
|
Subproject commit ec8eb42fe3ef5d0f0247a3fd078099e49d0140c3 |
@ -0,0 +1,14 @@ |
|||||||
|
// coverage:ignore-file |
||||||
|
import 'package:nextcloud/src/api/spreed.openapi.dart'; |
||||||
|
import 'package:nextcloud/src/client.dart'; |
||||||
|
|
||||||
|
export 'src/api/spreed.openapi.dart'; |
||||||
|
export 'src/helpers/spreed.dart'; |
||||||
|
|
||||||
|
// ignore: public_member_api_docs |
||||||
|
extension SpreedExtension on NextcloudClient { |
||||||
|
static final _spreed = Expando<Client>(); |
||||||
|
|
||||||
|
/// Client for the spreed APIs |
||||||
|
Client get spreed => _spreed[this] ??= Client.fromClient(this); |
||||||
|
} |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,203 @@ |
|||||||
|
import 'package:nextcloud/nextcloud.dart'; |
||||||
|
import 'package:nextcloud/src/api/core.openapi.dart' as core; |
||||||
|
import 'package:nextcloud/src/api/spreed.openapi.dart' as spreed; |
||||||
|
import 'package:version/version.dart'; |
||||||
|
|
||||||
|
/// The version of the spreed app that is supported. |
||||||
|
const supportedVersion = 17; |
||||||
|
|
||||||
|
/// Extension for checking whether spreed is supported. |
||||||
|
extension SpreedVersionSupported on spreed.Client { |
||||||
|
/// Checks whether the spreed app installed on the server is supported by this client. |
||||||
|
/// |
||||||
|
/// Also returns the supported version number. |
||||||
|
VersionSupported<int> isSupported(final core.OcsGetCapabilitiesResponseApplicationJson_Ocs_Data capabilities) { |
||||||
|
final version = capabilities.capabilities.spreedPublicCapabilities?.spreedPublicCapabilities0?.spreed.version; |
||||||
|
return ( |
||||||
|
isSupported: version != null && Version.parse(version).major == supportedVersion, |
||||||
|
minimumVersion: supportedVersion, |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Conversation types. |
||||||
|
/// |
||||||
|
/// Use [value] to get the integer representation that is used in the API. |
||||||
|
/// See https://github.com/nextcloud/spreed/blob/master/lib/Room.php. |
||||||
|
enum RoomType { |
||||||
|
/// Room between two participants. |
||||||
|
oneToOne, |
||||||
|
|
||||||
|
/// Room with multiple participants. |
||||||
|
group, |
||||||
|
|
||||||
|
/// Public room with multiple participants. |
||||||
|
public, |
||||||
|
|
||||||
|
/// Room with the changelog bots that posts a message when a new Talk release was installed. |
||||||
|
changelog, |
||||||
|
|
||||||
|
/// Room that previously was a [oneToOne]. The user has been deleted on the server or removed from all rooms. |
||||||
|
oneToOneFormer, |
||||||
|
|
||||||
|
/// Room to send messages to yourself for note keeping. |
||||||
|
noteToSelf; |
||||||
|
|
||||||
|
/// Integer representation of the [ParticipantType]. |
||||||
|
int get value => index + 1; |
||||||
|
} |
||||||
|
|
||||||
|
/// Types of chat messages. |
||||||
|
/// |
||||||
|
/// Use [name] to get the string representation that is used in the API. |
||||||
|
/// See https://github.com/nextcloud/spreed/blob/master/lib/Chat/ChatManager.php. |
||||||
|
enum MessageType { |
||||||
|
/// Message. |
||||||
|
comment, |
||||||
|
|
||||||
|
/// Message from the system. |
||||||
|
system, |
||||||
|
|
||||||
|
/// An object shared to the room. |
||||||
|
// ignore: constant_identifier_names |
||||||
|
object_shared, |
||||||
|
|
||||||
|
/// Message from a command. |
||||||
|
command, |
||||||
|
|
||||||
|
/// Deleted message. |
||||||
|
// ignore: constant_identifier_names |
||||||
|
comment_deleted, |
||||||
|
|
||||||
|
/// Emoji reaction. |
||||||
|
reaction, |
||||||
|
|
||||||
|
/// Deleted emoji reaction. |
||||||
|
// ignore: constant_identifier_names |
||||||
|
reaction_deleted; |
||||||
|
} |
||||||
|
|
||||||
|
/// Actor types of chat messages. |
||||||
|
/// |
||||||
|
/// Use [name] to get the string representation that is used in the API. |
||||||
|
/// See https://github.com/nextcloud/spreed/blob/master/lib/Model/Attendee.php. |
||||||
|
enum ActorType { |
||||||
|
/// Logged-in users. |
||||||
|
users, |
||||||
|
|
||||||
|
/// Groups. |
||||||
|
groups, |
||||||
|
|
||||||
|
/// Guest users. |
||||||
|
guests, |
||||||
|
|
||||||
|
/// E-mails. |
||||||
|
emails, |
||||||
|
|
||||||
|
/// Circles. |
||||||
|
circles, |
||||||
|
|
||||||
|
/// Users whose messages are bridged in by the Matterbridge integration. |
||||||
|
bridged, |
||||||
|
|
||||||
|
/// Used by commands and the changelog conversation. |
||||||
|
bots, |
||||||
|
|
||||||
|
/// Users from other instances. |
||||||
|
// ignore: constant_identifier_names |
||||||
|
federated_users, |
||||||
|
|
||||||
|
/// Users from SIP. |
||||||
|
phones; |
||||||
|
} |
||||||
|
|
||||||
|
/// Participant types. |
||||||
|
/// |
||||||
|
/// Use [value] to get the integer representation that is used in the API. |
||||||
|
/// See https://github.com/nextcloud/spreed/blob/master/lib/Participant.php. |
||||||
|
enum ParticipantType { |
||||||
|
/// Owner. |
||||||
|
owner, |
||||||
|
|
||||||
|
/// Moderator. |
||||||
|
moderator, |
||||||
|
|
||||||
|
/// User. |
||||||
|
user, |
||||||
|
|
||||||
|
/// Guest. |
||||||
|
guest, |
||||||
|
|
||||||
|
/// User following a public link. |
||||||
|
userFollowingPublicLink, |
||||||
|
|
||||||
|
/// Guest with moderator permissions. |
||||||
|
guestWithModeratorPermissions; |
||||||
|
|
||||||
|
/// Integer representation of the [ParticipantType]. |
||||||
|
int get value => index + 1; |
||||||
|
} |
||||||
|
|
||||||
|
/// Attendee permissions. |
||||||
|
/// |
||||||
|
/// Use [fromValue] to convert the integer representation into this enum representation. |
||||||
|
/// Use [value] to get the integer representation that is used in the API. |
||||||
|
/// Use [ParticipantPermissionsValue.value] to convert multiple [ParticipantPermission] into the integer representation. |
||||||
|
/// |
||||||
|
/// See https://github.com/nextcloud/spreed/blob/master/lib/Model/Attendee.php. |
||||||
|
enum ParticipantPermission { |
||||||
|
/// Default permissions. |
||||||
|
$default, |
||||||
|
|
||||||
|
/// Custom permissions. |
||||||
|
custom, |
||||||
|
|
||||||
|
/// Start call. |
||||||
|
startCall, |
||||||
|
|
||||||
|
/// Join call. |
||||||
|
joinCall, |
||||||
|
|
||||||
|
/// Can ignore lobby. |
||||||
|
canIgnoreLobby, |
||||||
|
|
||||||
|
/// Can publish audio stream. |
||||||
|
canPublishAudio, |
||||||
|
|
||||||
|
/// Can publish video stream. |
||||||
|
canPublishVideo, |
||||||
|
|
||||||
|
/// Can publish screen sharing stream. |
||||||
|
canScreenShare, |
||||||
|
|
||||||
|
/// Can post chat message, share items and do reactions. |
||||||
|
canSendMessageAndShareAndReact; |
||||||
|
|
||||||
|
/// Integer representation of the [ParticipantPermission]. |
||||||
|
int get value => index == 0 ? 0 : 1 << (index - 1); |
||||||
|
|
||||||
|
/// Converts the integer representation of multiple [ParticipantPermission]s to the corresponding [ParticipantPermission]s. |
||||||
|
static Set<ParticipantPermission> fromValue(final int value) { |
||||||
|
final permissions = <ParticipantPermission>{}; |
||||||
|
|
||||||
|
var v = value; |
||||||
|
for (var i = 1; i <= ParticipantPermission.values.length - 1; i++) { |
||||||
|
if (v.isOdd) { |
||||||
|
permissions.add(ParticipantPermission.values[i]); |
||||||
|
} |
||||||
|
v = v >> 1; |
||||||
|
} |
||||||
|
|
||||||
|
if (permissions.isEmpty) { |
||||||
|
permissions.add(ParticipantPermission.$default); |
||||||
|
} |
||||||
|
|
||||||
|
return permissions; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Extension for the integer representation of multiple [ParticipantPermission]s. |
||||||
|
extension ParticipantPermissionsValue on Set<ParticipantPermission> { |
||||||
|
/// Gets the integer representation of multiple [ParticipantPermission]s. |
||||||
|
int get value => map((final p) => p.value).reduce((final a, final b) => a | b); |
||||||
|
} |
@ -0,0 +1,88 @@ |
|||||||
|
[ |
||||||
|
{ |
||||||
|
"op": "replace", |
||||||
|
"path": "/components/schemas/PublicCapabilities/oneOf/0/properties/spreed/properties/config/properties/call/required", |
||||||
|
"value": [ |
||||||
|
"enabled", |
||||||
|
"breakout-rooms", |
||||||
|
"recording", |
||||||
|
"supported-reactions", |
||||||
|
"predefined-backgrounds", |
||||||
|
"can-upload-background" |
||||||
|
] |
||||||
|
}, |
||||||
|
{ |
||||||
|
"op": "replace", |
||||||
|
"path": "/components/schemas/PublicCapabilities/oneOf/0/properties/spreed/properties/config/properties/chat/required", |
||||||
|
"value": [ |
||||||
|
"max-length", |
||||||
|
"read-privacy", |
||||||
|
"typing-privacy" |
||||||
|
] |
||||||
|
}, |
||||||
|
{ |
||||||
|
"op": "add", |
||||||
|
"path": "/components/schemas/PublicCapabilities/oneOf/0/properties/spreed/properties/config/properties/chat/properties/translations", |
||||||
|
"value": { |
||||||
|
"type": "array", |
||||||
|
"items": { |
||||||
|
"type": "string" |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"op": "replace", |
||||||
|
"path": "/components/schemas/Room/required", |
||||||
|
"value": [ |
||||||
|
"actorId", |
||||||
|
"actorType", |
||||||
|
"attendeeId", |
||||||
|
"attendeePermissions", |
||||||
|
"attendeePin", |
||||||
|
"avatarVersion", |
||||||
|
"breakoutRoomMode", |
||||||
|
"breakoutRoomStatus", |
||||||
|
"callFlag", |
||||||
|
"callPermissions", |
||||||
|
"callRecording", |
||||||
|
"callStartTime", |
||||||
|
"canDeleteConversation", |
||||||
|
"canEnableSIP", |
||||||
|
"canLeaveConversation", |
||||||
|
"canStartCall", |
||||||
|
"defaultPermissions", |
||||||
|
"description", |
||||||
|
"displayName", |
||||||
|
"hasCall", |
||||||
|
"hasPassword", |
||||||
|
"id", |
||||||
|
"isCustomAvatar", |
||||||
|
"isFavorite", |
||||||
|
"lastActivity", |
||||||
|
"lastCommonReadMessage", |
||||||
|
"lastMessage", |
||||||
|
"lastPing", |
||||||
|
"lastReadMessage", |
||||||
|
"listable", |
||||||
|
"lobbyState", |
||||||
|
"lobbyTimer", |
||||||
|
"messageExpiration", |
||||||
|
"name", |
||||||
|
"notificationCalls", |
||||||
|
"notificationLevel", |
||||||
|
"objectId", |
||||||
|
"objectType", |
||||||
|
"participantFlags", |
||||||
|
"participantType", |
||||||
|
"permissions", |
||||||
|
"readOnly", |
||||||
|
"sessionId", |
||||||
|
"sipEnabled", |
||||||
|
"token", |
||||||
|
"type", |
||||||
|
"unreadMention", |
||||||
|
"unreadMentionDirect", |
||||||
|
"unreadMessages" |
||||||
|
] |
||||||
|
} |
||||||
|
] |
@ -0,0 +1,12 @@ |
|||||||
|
[ |
||||||
|
{ |
||||||
|
"op": "move", |
||||||
|
"from": "/components/schemas/PublicCapabilities/oneOf", |
||||||
|
"path": "/components/schemas/PublicCapabilities/anyOf" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"op": "move", |
||||||
|
"from": "/components/schemas/Room/properties/lastMessage/oneOf", |
||||||
|
"path": "/components/schemas/Room/properties/lastMessage/anyOf" |
||||||
|
} |
||||||
|
] |
@ -0,0 +1,423 @@ |
|||||||
|
import 'dart:async'; |
||||||
|
import 'dart:convert'; |
||||||
|
|
||||||
|
import 'package:built_value/json_object.dart'; |
||||||
|
import 'package:nextcloud/core.dart' as core; |
||||||
|
import 'package:nextcloud/spreed.dart' as spreed; |
||||||
|
import 'package:test/test.dart'; |
||||||
|
|
||||||
|
import 'helper.dart'; |
||||||
|
|
||||||
|
void main() { |
||||||
|
group( |
||||||
|
'spreed', |
||||||
|
() { |
||||||
|
late DockerImage image; |
||||||
|
setUpAll(() async => image = await getDockerImage()); |
||||||
|
|
||||||
|
late DockerContainer container; |
||||||
|
late TestNextcloudClient client1; |
||||||
|
setUp(() async { |
||||||
|
container = await getDockerContainer( |
||||||
|
image, |
||||||
|
useApache: true, |
||||||
|
); |
||||||
|
client1 = await getTestClient(container); |
||||||
|
}); |
||||||
|
tearDown(() => container.destroy()); |
||||||
|
|
||||||
|
Future<spreed.Room> createTestRoom() async => (await client1.spreed.room.createRoom( |
||||||
|
roomType: spreed.RoomType.public.value, |
||||||
|
roomName: 'Test', |
||||||
|
)) |
||||||
|
.body |
||||||
|
.ocs |
||||||
|
.data; |
||||||
|
|
||||||
|
group('Helpers', () { |
||||||
|
test('Is supported', () async { |
||||||
|
final response = await client1.core.ocs.getCapabilities(); |
||||||
|
expect(response.statusCode, 200); |
||||||
|
expect(() => response.headers, isA<void>()); |
||||||
|
|
||||||
|
final result = client1.spreed.isSupported(response.body.ocs.data); |
||||||
|
expect(result.isSupported, isTrue); |
||||||
|
}); |
||||||
|
|
||||||
|
test('Participant permissions', () async { |
||||||
|
expect(spreed.ParticipantPermission.$default.value, 0); |
||||||
|
expect(spreed.ParticipantPermission.fromValue(0), {spreed.ParticipantPermission.$default}); |
||||||
|
expect({spreed.ParticipantPermission.$default}.value, 0); |
||||||
|
|
||||||
|
expect(spreed.ParticipantPermission.custom.value, 1); |
||||||
|
expect(spreed.ParticipantPermission.canSendMessageAndShareAndReact.value, 128); |
||||||
|
expect(spreed.ParticipantPermission.fromValue(129), { |
||||||
|
spreed.ParticipantPermission.custom, |
||||||
|
spreed.ParticipantPermission.canSendMessageAndShareAndReact, |
||||||
|
}); |
||||||
|
expect( |
||||||
|
{ |
||||||
|
spreed.ParticipantPermission.custom, |
||||||
|
spreed.ParticipantPermission.canSendMessageAndShareAndReact, |
||||||
|
}.value, |
||||||
|
129, |
||||||
|
); |
||||||
|
}); |
||||||
|
}); |
||||||
|
|
||||||
|
group('Room', () { |
||||||
|
test('Get rooms', () async { |
||||||
|
final response = await client1.spreed.room.getRooms(); |
||||||
|
expect(response.body.ocs.data, hasLength(1)); |
||||||
|
expect(response.body.ocs.data[0].id, 1); |
||||||
|
expect(response.body.ocs.data[0].token, isNotEmpty); |
||||||
|
expect(response.body.ocs.data[0].type, spreed.RoomType.changelog.value); |
||||||
|
expect(response.body.ocs.data[0].name, 'user1'); |
||||||
|
expect(response.body.ocs.data[0].displayName, 'Talk updates ✅'); |
||||||
|
expect(response.body.ocs.data[0].participantType, spreed.ParticipantType.user.value); |
||||||
|
expect(spreed.ParticipantPermission.fromValue(response.body.ocs.data[0].permissions), { |
||||||
|
spreed.ParticipantPermission.startCall, |
||||||
|
spreed.ParticipantPermission.joinCall, |
||||||
|
spreed.ParticipantPermission.canPublishAudio, |
||||||
|
spreed.ParticipantPermission.canPublishVideo, |
||||||
|
spreed.ParticipantPermission.canScreenShare, |
||||||
|
spreed.ParticipantPermission.canSendMessageAndShareAndReact, |
||||||
|
}); |
||||||
|
}); |
||||||
|
|
||||||
|
test('Session', () async { |
||||||
|
var room = await createTestRoom(); |
||||||
|
expect(room.sessionId, '0'); |
||||||
|
|
||||||
|
final response = await client1.spreed.room.joinRoom(token: room.token); |
||||||
|
expect(response.body.ocs.data.id, room.id); |
||||||
|
expect(response.body.ocs.data.sessionId, isNot(room.sessionId)); |
||||||
|
|
||||||
|
room = (await client1.spreed.room.getSingleRoom(token: room.token)).body.ocs.data; |
||||||
|
expect(room.sessionId, response.body.ocs.data.sessionId); |
||||||
|
|
||||||
|
await client1.spreed.room.leaveRoom(token: room.token); |
||||||
|
room = (await client1.spreed.room.getSingleRoom(token: room.token)).body.ocs.data; |
||||||
|
expect(room.sessionId, '0'); |
||||||
|
}); |
||||||
|
|
||||||
|
group('Create room', () { |
||||||
|
test('One-to-One', () async { |
||||||
|
final response = await client1.spreed.room.createRoom( |
||||||
|
roomType: spreed.RoomType.oneToOne.value, |
||||||
|
invite: 'user2', |
||||||
|
); |
||||||
|
expect(response.body.ocs.data.id, 1); |
||||||
|
expect(response.body.ocs.data.token, isNotEmpty); |
||||||
|
expect(response.body.ocs.data.type, spreed.RoomType.oneToOne.value); |
||||||
|
expect(response.body.ocs.data.name, 'user2'); |
||||||
|
expect(response.body.ocs.data.displayName, 'User Two'); |
||||||
|
expect(response.body.ocs.data.participantType, spreed.ParticipantType.owner.value); |
||||||
|
expect(spreed.ParticipantPermission.fromValue(response.body.ocs.data.permissions), { |
||||||
|
spreed.ParticipantPermission.startCall, |
||||||
|
spreed.ParticipantPermission.joinCall, |
||||||
|
spreed.ParticipantPermission.canIgnoreLobby, |
||||||
|
spreed.ParticipantPermission.canPublishAudio, |
||||||
|
spreed.ParticipantPermission.canPublishVideo, |
||||||
|
spreed.ParticipantPermission.canScreenShare, |
||||||
|
spreed.ParticipantPermission.canSendMessageAndShareAndReact, |
||||||
|
}); |
||||||
|
}); |
||||||
|
|
||||||
|
test('Group', () async { |
||||||
|
final response = await client1.spreed.room.createRoom( |
||||||
|
roomType: spreed.RoomType.group.value, |
||||||
|
invite: 'admin', |
||||||
|
); |
||||||
|
expect(response.body.ocs.data.id, 1); |
||||||
|
expect(response.body.ocs.data.token, isNotEmpty); |
||||||
|
expect(response.body.ocs.data.type, spreed.RoomType.group.value); |
||||||
|
expect(response.body.ocs.data.name, 'admin'); |
||||||
|
expect(response.body.ocs.data.displayName, 'admin'); |
||||||
|
expect(response.body.ocs.data.participantType, spreed.ParticipantType.owner.value); |
||||||
|
expect(spreed.ParticipantPermission.fromValue(response.body.ocs.data.permissions), { |
||||||
|
spreed.ParticipantPermission.startCall, |
||||||
|
spreed.ParticipantPermission.joinCall, |
||||||
|
spreed.ParticipantPermission.canIgnoreLobby, |
||||||
|
spreed.ParticipantPermission.canPublishAudio, |
||||||
|
spreed.ParticipantPermission.canPublishVideo, |
||||||
|
spreed.ParticipantPermission.canScreenShare, |
||||||
|
spreed.ParticipantPermission.canSendMessageAndShareAndReact, |
||||||
|
}); |
||||||
|
}); |
||||||
|
|
||||||
|
test('Public', () async { |
||||||
|
final response = await client1.spreed.room.createRoom( |
||||||
|
roomType: spreed.RoomType.public.value, |
||||||
|
roomName: 'abc', |
||||||
|
); |
||||||
|
expect(response.body.ocs.data.id, 1); |
||||||
|
expect(response.body.ocs.data.token, isNotEmpty); |
||||||
|
expect(response.body.ocs.data.type, spreed.RoomType.public.value); |
||||||
|
expect(response.body.ocs.data.name, 'abc'); |
||||||
|
expect(response.body.ocs.data.displayName, 'abc'); |
||||||
|
expect(response.body.ocs.data.participantType, spreed.ParticipantType.owner.value); |
||||||
|
expect(spreed.ParticipantPermission.fromValue(response.body.ocs.data.permissions), { |
||||||
|
spreed.ParticipantPermission.startCall, |
||||||
|
spreed.ParticipantPermission.joinCall, |
||||||
|
spreed.ParticipantPermission.canIgnoreLobby, |
||||||
|
spreed.ParticipantPermission.canPublishAudio, |
||||||
|
spreed.ParticipantPermission.canPublishVideo, |
||||||
|
spreed.ParticipantPermission.canScreenShare, |
||||||
|
spreed.ParticipantPermission.canSendMessageAndShareAndReact, |
||||||
|
}); |
||||||
|
}); |
||||||
|
}); |
||||||
|
}); |
||||||
|
|
||||||
|
group('Chat', () { |
||||||
|
test('Send message', () async { |
||||||
|
final startTime = DateTime.now(); |
||||||
|
final room = (await client1.spreed.room.createRoom( |
||||||
|
roomType: spreed.RoomType.oneToOne.value, |
||||||
|
invite: 'user2', |
||||||
|
)) |
||||||
|
.body |
||||||
|
.ocs |
||||||
|
.data; |
||||||
|
|
||||||
|
final response = await client1.spreed.chat.sendMessage( |
||||||
|
token: room.token, |
||||||
|
message: 'bla', |
||||||
|
); |
||||||
|
expect(response.body.ocs.data!.id, 2); |
||||||
|
expect(response.body.ocs.data!.actorType, spreed.ActorType.users.name); |
||||||
|
expect(response.body.ocs.data!.actorId, 'user1'); |
||||||
|
expect(response.body.ocs.data!.actorDisplayName, 'User One'); |
||||||
|
expectDateInReasonableTimeRange( |
||||||
|
DateTime.fromMillisecondsSinceEpoch(response.body.ocs.data!.timestamp * 1000), |
||||||
|
startTime, |
||||||
|
); |
||||||
|
expect(response.body.ocs.data!.message, 'bla'); |
||||||
|
expect(response.body.ocs.data!.messageType, spreed.MessageType.comment.name); |
||||||
|
}); |
||||||
|
|
||||||
|
group('Get messages', () { |
||||||
|
test('Directly', () async { |
||||||
|
final startTime = DateTime.now(); |
||||||
|
final room = (await client1.spreed.room.createRoom( |
||||||
|
roomType: spreed.RoomType.oneToOne.value, |
||||||
|
invite: 'user2', |
||||||
|
)) |
||||||
|
.body |
||||||
|
.ocs |
||||||
|
.data; |
||||||
|
await client1.spreed.chat.sendMessage( |
||||||
|
token: room.token, |
||||||
|
message: '123', |
||||||
|
replyTo: (await client1.spreed.chat.sendMessage( |
||||||
|
token: room.token, |
||||||
|
message: 'bla', |
||||||
|
)) |
||||||
|
.body |
||||||
|
.ocs |
||||||
|
.data! |
||||||
|
.id, |
||||||
|
); |
||||||
|
|
||||||
|
final response = await client1.spreed.chat.receiveMessages( |
||||||
|
token: room.token, |
||||||
|
lookIntoFuture: 0, |
||||||
|
); |
||||||
|
expect(response.headers.xChatLastGiven, '1'); |
||||||
|
expect(response.headers.xChatLastCommonRead, '1'); |
||||||
|
|
||||||
|
expect(response.body.ocs.data, hasLength(3)); |
||||||
|
|
||||||
|
expect(response.body.ocs.data[0].id, 3); |
||||||
|
expect(response.body.ocs.data[0].actorType, spreed.ActorType.users.name); |
||||||
|
expect(response.body.ocs.data[0].actorId, 'user1'); |
||||||
|
expect(response.body.ocs.data[0].actorDisplayName, 'User One'); |
||||||
|
expectDateInReasonableTimeRange( |
||||||
|
DateTime.fromMillisecondsSinceEpoch(response.body.ocs.data[0].timestamp * 1000), |
||||||
|
startTime, |
||||||
|
); |
||||||
|
expect(response.body.ocs.data[0].message, '123'); |
||||||
|
expect(response.body.ocs.data[0].messageType, spreed.MessageType.comment.name); |
||||||
|
|
||||||
|
expect(response.body.ocs.data[0].parent!.id, 2); |
||||||
|
expect(response.body.ocs.data[0].parent!.actorType, spreed.ActorType.users.name); |
||||||
|
expect(response.body.ocs.data[0].parent!.actorId, 'user1'); |
||||||
|
expect(response.body.ocs.data[0].parent!.actorDisplayName, 'User One'); |
||||||
|
expectDateInReasonableTimeRange( |
||||||
|
DateTime.fromMillisecondsSinceEpoch(response.body.ocs.data[0].parent!.timestamp * 1000), |
||||||
|
startTime, |
||||||
|
); |
||||||
|
expect(response.body.ocs.data[0].parent!.message, 'bla'); |
||||||
|
expect(response.body.ocs.data[0].parent!.messageType, spreed.MessageType.comment.name); |
||||||
|
|
||||||
|
expect(response.body.ocs.data[1].id, 2); |
||||||
|
expect(response.body.ocs.data[1].actorType, spreed.ActorType.users.name); |
||||||
|
expect(response.body.ocs.data[1].actorId, 'user1'); |
||||||
|
expect(response.body.ocs.data[1].actorDisplayName, 'User One'); |
||||||
|
expectDateInReasonableTimeRange( |
||||||
|
DateTime.fromMillisecondsSinceEpoch(response.body.ocs.data[1].timestamp * 1000), |
||||||
|
startTime, |
||||||
|
); |
||||||
|
expect(response.body.ocs.data[1].message, 'bla'); |
||||||
|
expect(response.body.ocs.data[1].messageType, spreed.MessageType.comment.name); |
||||||
|
|
||||||
|
expect(response.body.ocs.data[2].id, 1); |
||||||
|
expect(response.body.ocs.data[2].actorType, spreed.ActorType.users.name); |
||||||
|
expect(response.body.ocs.data[2].actorId, 'user1'); |
||||||
|
expect(response.body.ocs.data[2].actorDisplayName, 'User One'); |
||||||
|
expectDateInReasonableTimeRange( |
||||||
|
DateTime.fromMillisecondsSinceEpoch(response.body.ocs.data[2].timestamp * 1000), |
||||||
|
startTime, |
||||||
|
); |
||||||
|
expect(response.body.ocs.data[2].message, 'You created the conversation'); |
||||||
|
expect(response.body.ocs.data[2].systemMessage, 'conversation_created'); |
||||||
|
expect(response.body.ocs.data[2].messageType, spreed.MessageType.system.name); |
||||||
|
}); |
||||||
|
|
||||||
|
test('Polling', () async { |
||||||
|
final startTime = DateTime.now(); |
||||||
|
|
||||||
|
final room = await createTestRoom(); |
||||||
|
final message = (await client1.spreed.chat.sendMessage( |
||||||
|
token: room.token, |
||||||
|
message: 'bla', |
||||||
|
)) |
||||||
|
.body |
||||||
|
.ocs |
||||||
|
.data!; |
||||||
|
unawaited( |
||||||
|
Future<void>.delayed(const Duration(seconds: 1)).then((final _) async { |
||||||
|
await client1.spreed.chat.sendMessage( |
||||||
|
token: room.token, |
||||||
|
message: '123', |
||||||
|
); |
||||||
|
}), |
||||||
|
); |
||||||
|
|
||||||
|
final response = await client1.spreed.chat.receiveMessages( |
||||||
|
token: room.token, |
||||||
|
lookIntoFuture: 1, |
||||||
|
timeout: 3, |
||||||
|
lastKnownMessageId: message.id, |
||||||
|
); |
||||||
|
expect(response.body.ocs.data, hasLength(1)); |
||||||
|
expect(response.body.ocs.data[0].id, 3); |
||||||
|
expect(response.body.ocs.data[0].actorType, spreed.ActorType.users.name); |
||||||
|
expect(response.body.ocs.data[0].actorId, 'user1'); |
||||||
|
expect(response.body.ocs.data[0].actorDisplayName, 'User One'); |
||||||
|
expectDateInReasonableTimeRange( |
||||||
|
DateTime.fromMillisecondsSinceEpoch(response.body.ocs.data[0].timestamp * 1000), |
||||||
|
startTime, |
||||||
|
); |
||||||
|
expect(response.body.ocs.data[0].message, '123'); |
||||||
|
expect(response.body.ocs.data[0].messageType, spreed.MessageType.comment.name); |
||||||
|
}); |
||||||
|
}); |
||||||
|
}); |
||||||
|
|
||||||
|
group('Call', () { |
||||||
|
test('Start and end call', () async { |
||||||
|
var room = await createTestRoom(); |
||||||
|
expect(room.hasCall, isFalse); |
||||||
|
room = (await client1.spreed.room.joinRoom(token: room.token)).body.ocs.data; |
||||||
|
|
||||||
|
await client1.spreed.call.joinCall(token: room.token); |
||||||
|
room = (await client1.spreed.room.getSingleRoom(token: room.token)).body.ocs.data; |
||||||
|
expect(room.hasCall, isTrue); |
||||||
|
|
||||||
|
await client1.spreed.call.leaveCall(token: room.token); |
||||||
|
room = (await client1.spreed.room.getSingleRoom(token: room.token)).body.ocs.data; |
||||||
|
expect(room.hasCall, isFalse); |
||||||
|
}); |
||||||
|
}); |
||||||
|
|
||||||
|
group('Signaling', () { |
||||||
|
test('Get settings', () async { |
||||||
|
final room = await createTestRoom(); |
||||||
|
|
||||||
|
final response = await client1.spreed.signaling.getSettings(token: room.token); |
||||||
|
expect(response.body.ocs.data.signalingMode, 'internal'); |
||||||
|
expect(response.body.ocs.data.userId, 'user1'); |
||||||
|
expect(response.body.ocs.data.hideWarning, false); |
||||||
|
expect(response.body.ocs.data.server, ''); |
||||||
|
expect(response.body.ocs.data.ticket, contains(':user1:')); |
||||||
|
expect(response.body.ocs.data.helloAuthParams.$10.userid, 'user1'); |
||||||
|
expect(response.body.ocs.data.helloAuthParams.$10.ticket, contains(':user1:')); |
||||||
|
expect(response.body.ocs.data.helloAuthParams.$20.token.split('').where((final x) => x == '.'), hasLength(2)); |
||||||
|
expect(response.body.ocs.data.stunservers, hasLength(1)); |
||||||
|
expect(response.body.ocs.data.stunservers[0].urls, hasLength(1)); |
||||||
|
expect(response.body.ocs.data.stunservers[0].urls[0], 'stun:stun.nextcloud.com:443'); |
||||||
|
expect(response.body.ocs.data.turnservers, hasLength(1)); |
||||||
|
expect(response.body.ocs.data.turnservers[0].urls, hasLength(4)); |
||||||
|
expect( |
||||||
|
response.body.ocs.data.turnservers[0].urls[0], |
||||||
|
'turn:staticauth.openrelay.metered.ca:443?transport=udp', |
||||||
|
); |
||||||
|
expect( |
||||||
|
response.body.ocs.data.turnservers[0].urls[1], |
||||||
|
'turn:staticauth.openrelay.metered.ca:443?transport=tcp', |
||||||
|
); |
||||||
|
expect( |
||||||
|
response.body.ocs.data.turnservers[0].urls[2], |
||||||
|
'turns:staticauth.openrelay.metered.ca:443?transport=udp', |
||||||
|
); |
||||||
|
expect( |
||||||
|
response.body.ocs.data.turnservers[0].urls[3], |
||||||
|
'turns:staticauth.openrelay.metered.ca:443?transport=tcp', |
||||||
|
); |
||||||
|
expect(response.body.ocs.data.turnservers[0].username, isNotEmpty); |
||||||
|
expect((response.body.ocs.data.turnservers[0].credential as StringJsonObject).asString, isNotEmpty); |
||||||
|
expect(response.body.ocs.data.sipDialinInfo, ''); |
||||||
|
}); |
||||||
|
|
||||||
|
test('Send and receive messages', () async { |
||||||
|
final room = (await client1.spreed.room.createRoom( |
||||||
|
roomType: spreed.RoomType.oneToOne.value, |
||||||
|
invite: 'user2', |
||||||
|
)) |
||||||
|
.body |
||||||
|
.ocs |
||||||
|
.data; |
||||||
|
|
||||||
|
final room1 = (await client1.spreed.room.joinRoom(token: room.token)).body.ocs.data; |
||||||
|
await client1.spreed.call.joinCall(token: room.token); |
||||||
|
|
||||||
|
final client2 = await getTestClient( |
||||||
|
container, |
||||||
|
username: 'user2', |
||||||
|
); |
||||||
|
|
||||||
|
final room2 = (await client2.spreed.room.joinRoom(token: room.token)).body.ocs.data; |
||||||
|
await client2.spreed.call.joinCall(token: room.token); |
||||||
|
|
||||||
|
await client1.spreed.signaling.sendMessages( |
||||||
|
token: room.token, |
||||||
|
messages: json.encode([ |
||||||
|
{ |
||||||
|
'ev': 'message', |
||||||
|
'sessionId': room1.sessionId, |
||||||
|
'fn': json.encode({ |
||||||
|
'to': room2.sessionId, |
||||||
|
}), |
||||||
|
}, |
||||||
|
]), |
||||||
|
); |
||||||
|
|
||||||
|
await Future<void>.delayed(const Duration(seconds: 1)); |
||||||
|
|
||||||
|
final messages = (await client2.spreed.signaling.pullMessages(token: room.token)).body.ocs.data; |
||||||
|
expect(messages, hasLength(2)); |
||||||
|
expect(messages[0].type, 'message'); |
||||||
|
expect(json.decode(messages[0].data.string!), {'to': room2.sessionId, 'from': room1.sessionId}); |
||||||
|
expect(messages[1].type, 'usersInRoom'); |
||||||
|
expect(messages[1].data.builtListSignalingSession, hasLength(2)); |
||||||
|
expect(messages[1].data.builtListSignalingSession![0].userId, 'user1'); |
||||||
|
expect(messages[1].data.builtListSignalingSession![1].userId, 'user2'); |
||||||
|
}); |
||||||
|
}); |
||||||
|
}, |
||||||
|
retry: retryCount, |
||||||
|
timeout: timeout, |
||||||
|
); |
||||||
|
} |
Loading…
Reference in new issue