Skip to content

Commit 7b2d949

Browse files
committed
Version bump to 5.0.0
1 parent 4320475 commit 7b2d949

File tree

6 files changed

+183
-34
lines changed

6 files changed

+183
-34
lines changed

CHANGELOG.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,22 @@
11
# Changelog
22

3+
## 5.0.0 - 2023-01-31
4+
5+
- Re: [#21](https://github.com/supabase-community/realtime-csharp/pull/21) Provide API for `presence`, `broadcast` and `postgres_changes`
6+
- [Major, New] `Channel.PostgresChanges` event will receive the wildcard `*` changes event, not `Channel.OnMessage`.
7+
- [Major] `Channel.OnInsert`, `Channel.OnUpdate`, and `Channel.OnDelete` now conform to the server's payload of `Response.Payload.**Data**`
8+
- [Major] `Channel.OnInsert`, `Channel.OnUpdate`, and `Channel.OnDelete` now return `PostgresChangesEventArgs`
9+
- [Minor] Rename `Channel` to `RealtimeChannel`
10+
- Supports better handling of disconnects in `RealtimeSocket` and adds a `Client.OnReconnect` event.
11+
- [Minor] Moves `ChannelOptions` to `Channel.ChannelOptions`
12+
- [Minor] Moves `ChannelStateChangedEventArgs` to `Channel.ChannelStateChangedEventArgs`
13+
- [Minor] Moves `Push` to `Channel.Push`
14+
- [Minor] Moves `Channel.ChannelState` to `Constants.ChannelState`
15+
- [Minor] Moves `SocketResponse`, `SocketRequest`, `SocketResponsePayload`, `SocketResponseEventArgs`, and `SocketStateChangedEventArgs` to `Socket` namespace.
16+
- [New] Adds `RealtimeBroadcast`
17+
- [New] Adds `RealtimePresence`
18+
- [Improvement] Better handling of disconnection/reconnection
19+
320
## 4.0.1 - 2022-11-08
421

522
- Bugfixes on previous release.

Examples/PresenceExample/Pages/Index.razor

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414
<PageTitle>Realtime Example</PageTitle>
1515

1616
<div class="flex justify-between">
17-
<div class="dark:bg-brand-1200 bg-scale-200 border border-scale-500 dark:border-scale-300 p-3 rounded-md space-y-8 transition-all max-h-[70px] duration-500 overflow-hidden shadow-2xl dark:shadow-lg">
17+
<div class="bg-gray-200 border border-scale-500 dark:border-scale-300 p-3 rounded-md space-y-8 transition-all max-h-[70px] duration-500 overflow-hidden shadow-2xl dark:shadow-lg">
1818
<a href="https://github.com/supabase-community/supabase-csharp">
19-
<img class="sm:w-300 xs:w-200 w-auto h-full" src="/logo.png" />
19+
<img class="w-full md:w-48 h-full" src="/logo.png" />
2020
</a>
2121
</div>
2222

Examples/PresenceExample/wwwroot/index.html

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,14 @@
1111
<script src="https://cdn.tailwindcss.com?plugins=typography"></script>
1212
</head>
1313

14-
<body class="bg-white dark:bg-neutral-900 text-black dark:text-white">
14+
<body class="bg-neutral-900 text-white">
1515
<div id="app">
1616
<svg class="loading-progress">
1717
<circle r="40%" cx="50%" cy="50%" />
1818
<circle r="40%" cx="50%" cy="50%" />
1919
</svg>
2020
<div class="loading-progress-text"></div>
2121
</div>
22-
23-
<div id="blazor-error-ui">
24-
An unhandled error has occurred.
25-
<a href="" class="reload">Reload</a>
26-
<a class="dismiss">🗙</a>
27-
</div>
2822
<script src="_framework/blazor.webassembly.js"></script>
2923
<script src="/tailwind.config.js"></script>
3024
<script src="/JSInterop.js"></script>

README.md

Lines changed: 159 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,29 +10,29 @@
1010

1111
---
1212

13-
## BREAKING CHANGES MOVING FROM v3.x.x to v4.x.x
14-
15-
- `Client` is no longer a singleton class.
16-
- `Channel` has a new constructor that uses `ChannelOptions`
17-
- `Channel.Parameters` has been changed in favor of `Channel.Options`
18-
- `Channel` and `Push` are now directly dependent on having `Socket` and `SerializerSettings` passed in as opposed to referencing the `Singleton` instance.
19-
- All publicly facing classes (that offer functionality) now include an Interface.
20-
21-
In reality, not much should affect the developer as most of these classes/methods are only being referenced internally by the `Client`. The removal of the Singleton aspect may offer some design changes for those leveraging this library by itself (as opposed to using it only in supabase-csharp.)
22-
23-
```c#
24-
// What was:
25-
var client = Supabase.Realtime.Client.Initialize(options);
26-
await client.ConnectAsync()
27-
28-
// Becomes:
29-
var client = new Client(options);
30-
await client.ConnectAsync()
31-
```
13+
## BREAKING CHANGES MOVING FROM v4.x.x to v5.x.x
14+
15+
**See realtime-csharp in action [here](https://multiplayer-csharp.azurewebsites.net/).**
16+
17+
## Changes:
18+
19+
- [Major, New] `Channel.PostgresChanges` event will receive the wildcard `*` changes event, not `Channel.OnMessage`.
20+
- [Major] `Channel.OnInsert`, `Channel.OnUpdate`, and `Channel.OnDelete` now conform to the server's payload of `Response.Payload.**Data**`
21+
- [Major] `Channel.OnInsert`, `Channel.OnUpdate`, and `Channel.OnDelete` now return `PostgresChangesEventArgs`
22+
- [Minor] Rename `Channel` to `RealtimeChannel`
23+
- Supports better handling of disconnects in `RealtimeSocket` and adds a `Client.OnReconnect` event.
24+
- [Minor] Moves `ChannelOptions` to `Channel.ChannelOptions`
25+
- [Minor] Moves `ChannelStateChangedEventArgs` to `Channel.ChannelStateChangedEventArgs`
26+
- [Minor] Moves `Push` to `Channel.Push`
27+
- [Minor] Moves `Channel.ChannelState` to `Constants.ChannelState`
28+
- [Minor] Moves `SocketResponse`, `SocketRequest`, `SocketResponsePayload`, `SocketResponseEventArgs`, and `SocketStateChangedEventArgs` to `Socket` namespace.
29+
- [New] Adds `RealtimeBroadcast`
30+
- [New] Adds `RealtimePresence`
31+
- [Improvement] Better handling of disconnection/reconnection
3232

3333
---
3434

35-
Realtime-csharp is written as a client library for [supabase/realtime](https://github.com/supabase/realtime).
35+
`realtime-csharp` is written as a client library for [supabase/realtime](https://github.com/supabase/realtime).
3636

3737
Documentation can be found [here](https://supabase-community.github.io/realtime-csharp/api/Supabase.Realtime.Client.html).
3838

@@ -59,12 +59,13 @@ channel.OnUpdate += (sender, args) => Console.WriteLine("Item updated: " + args.
5959
channel.OnDelete += (sender, args) => Console.WriteLine("Item deleted");
6060

6161
// Callback for any event, INSERT, UPDATE, or DELETE
62-
channel.OnMessage += (sender, args) => Debug.WriteLine(args.Message.Event);
62+
channel.OnPostgresChange += (sender, args) => Debug.WriteLine(args.Message.Event);
6363

6464
await channel.Subscribe();
6565
```
6666

6767
Leveraging `Postgrest.BaseModel`s, one ought to be able to coerce SocketResponse Records into their associated models by calling:
68+
6869
```c#
6970
// ...
7071
var channel = client.Channel("realtime", "public", "users");
@@ -76,6 +77,143 @@ channel.OnInsert += (sender, args) => {
7677
await channel.Subscribe();
7778
```
7879

80+
## Broadcast
81+
82+
"Broadcast follows the publish-subscribe pattern where a client publishes messages to a channel with a unique identifier. For example, a user could send a message to a channel with id room-1.
83+
84+
Other clients can elect to receive the message in real-time by subscribing to the channel with id room-1. If these clients are online and subscribed then they will receive the message.
85+
86+
Broadcast works by connecting your client to the nearest Realtime server, which will communicate with other servers to relay messages to other clients.
87+
88+
A common use-case is sharing a user's cursor position with other clients in an online game."
89+
90+
[Find more information here](https://supabase.com/docs/guides/realtime#broadcast)
91+
92+
**Given the following model (`CursorBroadcast`):**
93+
94+
```c#
95+
class MouseBroadcast : BaseBroadcast<MouseStatus> { }
96+
class MouseStatus
97+
{
98+
[JsonProperty("mouseX")]
99+
public float MouseX { get; set; }
100+
101+
[JsonProperty("mouseY")]
102+
public float MouseY { get; set; }
103+
104+
[JsonProperty("userId")]
105+
public string UserId { get; set; }
106+
}
107+
```
108+
109+
**Listen for typed broadcast events**:
110+
111+
```c#
112+
var channel = supabase.Realtime.Channel("cursor");
113+
114+
var broadcast = channel.Register<MouseBroadcast>(false, true);
115+
broadcast<MouseBroadcast>().OnBroadcast += (sender, args) =>
116+
{
117+
var state = broadcast.Current();
118+
Debug.WriteLine($"{state.Payload}: {state.Payload.MouseX}:{state.Payload.MouseY}");
119+
};
120+
await channel.Subscribe();
121+
```
122+
123+
**Broadcast an event**:
124+
125+
```c#
126+
var channel = supabase.Realtime.Channel("cursor");
127+
var data = new CursorBroadcast { Event = "cursor", Payload = new MouseStatus { MouseX = 123, MouseY = 456 } };
128+
channel.Send(ChannelType.Broadcast, data);
129+
```
130+
131+
## Presence
132+
133+
"Presence utilizes an in-memory conflict-free replicated data type (CRDT) to track and synchronize shared state in an eventually consistent manner. It computes the difference between existing state and new state changes and sends the necessary updates to clients via Broadcast.
134+
135+
When a new client subscribes to a channel, it will immediately receive the channel's latest state in a single message instead of waiting for all other clients to send their individual states.
136+
137+
Clients are free to come-and-go as they please, and as long as they are all subscribed to the same channel then they will all have the same Presence state as each other.
138+
139+
The neat thing about Presence is that if a client is suddenly disconnected (for example, they go offline), their state will be automatically removed from the shared state. If you've ever tried to build an “I'm online” feature which handles unexpected disconnects, you'll appreciate how useful this is."
140+
141+
[Find more information here](https://supabase.com/docs/guides/realtime#presence)
142+
143+
**Given the following model: (`UserPresence`)**
144+
145+
```c#
146+
class UserPresence: BasePresence
147+
{
148+
[JsonProperty("lastSeen")]
149+
public DateTime LastSeen { get; set; }
150+
}
151+
```
152+
153+
**Listen for typed presence events**:
154+
155+
```c#
156+
var presenceId = Guid.NewGuid().ToString();
157+
158+
var channel = supabase.Realtime.Channel("last-seen");
159+
var presence = channel.Register<UserPresence>(presenceId);
160+
presence.OnSync += (sender, args) =>
161+
{
162+
foreach (var state in presence.CurrentState)
163+
{
164+
var userId = state.Key;
165+
var lastSeen = state.Value.First().LastSeen;
166+
Debug.WriteLine($"{userId}: {lastSeen}");
167+
}
168+
};
169+
await channel.Subscribe();
170+
```
171+
172+
**Track a user presence event**:
173+
174+
```c#
175+
var presenceId = Guid.NewGuid().ToString();
176+
var channel = supabase.Realtime.Channel("last-seen");
177+
178+
var presence = channel.Register<UserPresence>(presenceId);
179+
presence.Track(new UserPresence { LastSeen = DateTime.Now });
180+
```
181+
182+
## Postgres Changes
183+
184+
"Postgres Changes enable you to listen to database changes and have them broadcast to authorized clients based on [Row Level Security (RLS)](https://supabase.com/docs/guides/auth/row-level-security) policies.
185+
186+
This works by Realtime polling your database's logical replication slot for changes, passing those changes to the [apply_rls](https://github.com/supabase/walrus#reading-wal) SQL function to determine which clients have permission, and then using Broadcast to send those changes to clients.
187+
188+
Realtime requires a publication called `supabase_realtime` to determine which tables to poll. You must add tables to this publication prior to clients subscribing to channels that want to listen for database changes.
189+
190+
We strongly encourage you to enable RLS on your database tables and have RLS policies in place to prevent unauthorized parties from accessing your data."
191+
192+
[Find More Information here](https://supabase.com/docs/guides/realtime#postgres-changes)
193+
194+
**Using the new `Register` method:**
195+
196+
```c#
197+
var channel = supabase.Realtime.Channel("public-users");
198+
channel.Register(new PostgresChangesOptions("public", "users"));
199+
channel.PostgresChanges += (sender, args) =>
200+
{
201+
switch (args.Response.Data.Type)
202+
{
203+
case EventType.Insert:
204+
// Handle user created
205+
break;
206+
case EventType.Update:
207+
// Handle user updated
208+
break;
209+
case EventType.Delete:
210+
// Handle user deleted
211+
break;
212+
}
213+
};
214+
await channel.Subscribe();
215+
```
216+
79217
## Status
80218

81219
- [x] Client Connects to Websocket

Realtime/Realtime.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,16 @@
1616
<Summary>Realtime-csharp is written as a client library for supabase/realtime.</Summary>
1717
<PackageTags>supabase, realtime, phoenix</PackageTags>
1818
<Title>realtime-csharp</Title>
19-
<PackageVersion>4.0.1</PackageVersion>
20-
<ReleaseVersion>4.0.1</ReleaseVersion>
19+
<PackageVersion>5.0.0</PackageVersion>
20+
<ReleaseVersion>5.0.0</ReleaseVersion>
2121
</PropertyGroup>
2222
<PropertyGroup>
2323
<Nullable>enable</Nullable>
2424
<LangVersion>latest</LangVersion>
2525
<WarningsAsErrors>CS8600;CS8602;CS8603</WarningsAsErrors>
2626
</PropertyGroup>
2727
<PropertyGroup Condition=" '$(Version)' == '' ">
28-
<VersionPrefix Condition=" '$(VersionPrefix)' == '' ">4.0.1</VersionPrefix>
28+
<VersionPrefix Condition=" '$(VersionPrefix)' == '' ">5.0.0</VersionPrefix>
2929
<VersionSuffix Condition=" '$(VersionSuffix)' == '' ">
3030
</VersionSuffix>
3131
<Version Condition=" '$(VersionSuffix)' != '' ">$(VersionPrefix)-$(VersionSuffix)</Version>

RealtimeTests/RealtimeTests.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<TargetFramework>netcoreapp3.1</TargetFramework>
55

66
<IsPackable>false</IsPackable>
7-
<ReleaseVersion>4.0.1</ReleaseVersion>
7+
<ReleaseVersion>5.0.0</ReleaseVersion>
88
</PropertyGroup>
99

1010
<PropertyGroup>

0 commit comments

Comments
 (0)