Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .changes/simplify-session-e2ee
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
minor type="added" "Simplify enabling E2EE with Session API"
12 changes: 11 additions & 1 deletion lib/src/agent/session.dart
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ class Session extends DisposableChangeNotifier {
final _TokenSourceConfiguration _tokenSourceConfiguration;

final Agent _agent = Agent();
bool _isStarting = false;
Agent get agent => _agent;

SessionError? get error => _error;
Expand All @@ -175,12 +176,19 @@ class Session extends DisposableChangeNotifier {
EventsListener<RoomEvent>? _roomListener;
Timer? _agentTimeoutTimer;

/// Enables or disables end-to-end encryption for the session.
///
/// Requires that encryption was configured via [SessionOptions] (by passing
/// `encryption:`) or that the [Room] was created with [E2EEOptions].
Future<void> setEncryptionEnabled(bool enabled) => room.setE2EEEnabled(enabled);

/// Starts the session by fetching credentials and connecting to the room.
Future<void> start() async {
if (room.connectionState != ConnectionState.disconnected) {
if (_isStarting || room.connectionState != ConnectionState.disconnected) {
logger.info('Session.start() ignored: room already connecting or connected.');
return;
}
_isStarting = true;

_setError(null);
_agentTimeoutTimer?.cancel();
Expand Down Expand Up @@ -229,6 +237,8 @@ class Session extends DisposableChangeNotifier {
_setError(SessionError.connection(error));
_setConnectionState(ConnectionState.disconnected);
_agent.disconnected();
} finally {
_isStarting = false;
}
}

Expand Down
30 changes: 29 additions & 1 deletion lib/src/agent/session_options.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,16 @@
// limitations under the License.

import '../core/room.dart';
import '../e2ee/options.dart';
import '../options.dart';

/// Options for creating a [Session].
class SessionOptions {
/// The underlying [Room] used by the session.
///
/// If neither [room] nor [encryption] is provided, a default [Room] is
/// created. Passing both throws [ArgumentError] — configure E2EE on the
/// [Room] directly if you need a custom [Room] with encryption.
final Room room;

/// Whether to enable audio pre-connect with [PreConnectAudioBuffer].
Expand All @@ -30,11 +36,33 @@ class SessionOptions {
/// to a failed state.
final Duration agentConnectTimeout;

/// Creates [SessionOptions].
///
/// Pass [encryption] to configure end-to-end encryption on the internally
/// created [Room]. Use [E2EEOptions.sharedKey] for the common shared-key
/// case. For advanced setups (custom [RoomOptions], per-participant keys),
/// build a [Room] yourself and pass it via [room] instead.
///
/// Passing both [room] and [encryption] throws [ArgumentError].
SessionOptions({
Room? room,
E2EEOptions? encryption,
this.preConnectAudio = true,
this.agentConnectTimeout = const Duration(seconds: 20),
}) : room = room ?? Room();
}) : room = _buildRoom(room, encryption);

static Room _buildRoom(Room? room, E2EEOptions? encryption) {
if (room != null && encryption != null) {
throw ArgumentError(
'SessionOptions: pass either `room` or `encryption`, not both. '
'To use encryption with a custom Room, configure E2EE on the Room directly.',
);
}
if (encryption != null) {
return Room(roomOptions: RoomOptions(encryption: encryption));
}
return room ?? Room();
}
Comment on lines 47 to +65
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be a bad / nonsensical suggestion as I am not too familiar with typical flutter patterns, but would be worthwhile to get all session initialization (constructor and alternate constructor paths like the copyWith static method) going through the same core _ static method for initialization?


SessionOptions copyWith({
Room? room,
Expand Down
8 changes: 8 additions & 0 deletions lib/src/e2ee/options.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,12 @@ class E2EEOptions {
final BaseKeyProvider keyProvider;
final EncryptionType encryptionType = EncryptionType.kGcm;
const E2EEOptions({required this.keyProvider});

/// Creates [E2EEOptions] configured with a shared-key [BaseKeyProvider]
/// derived from the given passphrase.
static Future<E2EEOptions> sharedKey(String key) async {
final keyProvider = await BaseKeyProvider.create();
await keyProvider.setSharedKey(key);
return E2EEOptions(keyProvider: keyProvider);
}
}
Loading