Skip to content
Merged
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
26 changes: 26 additions & 0 deletions MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,32 @@ channel.subscribe(const Duration(seconds: 10));
All channel streams complete when the channel closes, so `await for` loops and `onDone` handlers
end on their own once the channel is gone.

### `RealtimePresence` is internal

`RealtimePresence` and its helper types (`PresenceOptions`, `PresenceEvents`, `PresenceChooser`,
`PresenceOnJoinCallback`, `PresenceOnLeaveCallback`) are now `@internal`, along with the
`RealtimeChannel.presence` field. They were presence bookkeeping that leaked into the public API,
and registering a callback through `channel.presence.onJoin(...)` silently disabled the channel's
own presence events, because the channel's forwarders occupied the same single callback slot.

Everything the class offered is available on the channel:

```dart
// Before
channel.presence.onJoin((key, current, joined) { /* ... */ });
channel.presence.onLeave((key, current, left) { /* ... */ });
channel.presence.onSync(() { /* ... */ });
final state = channel.presence.state;

// After
channel.onPresenceJoin.listen((payload) { /* ... */ });
channel.onPresenceLeave.listen((payload) { /* ... */ });
channel.onPresenceSync.listen((payload) { /* ... */ });
final state = channel.presenceState();
```

The `Presence` payload class is unchanged and stays public.

### Plural enum names singularized

A Dart enum type names one value rather than the set, so its name should be singular. Five enums
Expand Down
2 changes: 1 addition & 1 deletion packages/realtime_client/lib/realtime_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ export 'src/constants.dart'
SocketState;
export 'src/realtime_channel.dart';
export 'src/realtime_client.dart';
export 'src/realtime_presence.dart';
export 'src/realtime_presence.dart' show Presence;
export 'src/transformers.dart' show PostgresColumn, PostgresType;
export 'src/types.dart' hide ChannelFilter, RealtimeListenType;
2 changes: 2 additions & 0 deletions packages/realtime_client/lib/src/realtime_channel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'package:meta/meta.dart';
import 'package:realtime_client/realtime_client.dart';
import 'package:realtime_client/src/constants.dart';
import 'package:realtime_client/src/push.dart';
import 'package:realtime_client/src/realtime_presence.dart';
import 'package:realtime_client/src/retry_timer.dart';
import 'package:realtime_client/src/transformers.dart';
import 'package:realtime_client/src/types.dart';
Expand All @@ -22,6 +23,7 @@ class RealtimeChannel {
late Push joinPush;
late RetryTimer _rejoinTimer;
List<Push> _pushBuffer = [];
@internal
late RealtimePresence presence;
@internal
late final String broadcastEndpointURL;
Expand Down
27 changes: 22 additions & 5 deletions packages/realtime_client/lib/src/realtime_presence.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'package:meta/meta.dart';
import 'package:realtime_client/realtime_client.dart';
import 'package:realtime_client/src/types.dart';

Expand Down Expand Up @@ -36,27 +37,43 @@ class Presence {
String toString() => 'Presence(presenceRef: $presenceRef, payload: $payload)';
}

@internal
typedef PresenceChooser<T> = T Function(String key, dynamic presence);

@internal
typedef PresenceOnJoinCallback =
void Function(String? key, dynamic currentPresences, dynamic newPresences);

@internal
typedef PresenceOnLeaveCallback =
void Function(String? key, dynamic currentPresences, dynamic newPresences);

class PresenceOpts {
@internal
class PresenceOptions {
final PresenceEvents events;

const PresenceOpts({required this.events});
const PresenceOptions({required this.events});
}

@internal
class PresenceEvents {
final String state;
final String diff;

const PresenceEvents({required this.state, required this.diff});
}

/// Internal bookkeeping for the presence state of a [RealtimeChannel].
///
/// Not part of the public API: the [onJoin], [onLeave], and [onSync] setters
/// hold a single callback slot each, and the [RealtimePresence] constructor
/// installs the forwarders that feed the channel presence streams through
/// them, so replacing a callback silently disables those streams.
///
/// To observe presence, listen to [RealtimeChannel.onPresenceSync],
/// [RealtimeChannel.onPresenceJoin], and [RealtimeChannel.onPresenceLeave],
/// and read the current state with [RealtimeChannel.presenceState].
@internal
class RealtimePresence {
Map<String, List<Presence>> state = <String, List<Presence>>{};
List<Map<String, dynamic>> pendingDiffs = [];
Expand All @@ -73,11 +90,11 @@ class RealtimePresence {
///
/// `channel` - The RealtimeChannel
///
/// `opts` - The options, for example `PresenceOpts(events:
/// `options` - The options, for example `PresenceOptions(events:
/// PresenceEvents(state: 'state', diff: 'diff'))`
RealtimePresence(this.channel, [PresenceOpts? opts]) {
RealtimePresence(this.channel, [PresenceOptions? options]) {
final events =
opts?.events ??
options?.events ??
PresenceEvents(state: 'presence_state', diff: 'presence_diff');

channel.onEvents(events.state, ChannelFilter(), (newState, [_]) {
Expand Down
25 changes: 0 additions & 25 deletions sdk-compliance.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1769,17 +1769,7 @@ features:
- RealtimeChannel.onPresenceJoin
- RealtimeChannel.onPresenceLeave
supporting_symbols:
- PresenceChooser
- PresenceEvent
- PresenceEvents
- PresenceEvents.PresenceEvents
- PresenceEvents.diff
- PresenceEvents.state
- PresenceOnJoinCallback
- PresenceOnLeaveCallback
- PresenceOpts
- PresenceOpts.PresenceOpts
- PresenceOpts.events
- RealtimePresenceJoinPayload
- RealtimePresenceJoinPayload.RealtimePresenceJoinPayload
- RealtimePresenceJoinPayload.currentPresences
Expand Down Expand Up @@ -1847,21 +1837,6 @@ features:
- Presence.payload
- Presence.presenceRef
- Presence.toString
- RealtimeChannel.presence
- RealtimePresence
- RealtimePresence.RealtimePresence
- RealtimePresence.caller
- RealtimePresence.channel
- RealtimePresence.inPendingSyncState
- RealtimePresence.joinRef
- RealtimePresence.list
- RealtimePresence.onJoin
- RealtimePresence.onLeave
- RealtimePresence.onSync
- RealtimePresence.pendingDiffs
- RealtimePresence.state
- RealtimePresence.syncDiff
- RealtimePresence.syncState
- SinglePresenceState
- SinglePresenceState.SinglePresenceState
- SinglePresenceState.key
Expand Down