实时快速入门
学习如何构建multiplayer.dev,这是一个合作应用,它展示了使用实时的广播、Presence和Postgres CDC。
安装supabase-js
客户端#
npm install @supabase/supabase-js
光标位置
广播允许一个客户端发送消息,多个客户端接收消息。广播的消息是短暂的。它们不会被持久化到数据库中,而是直接通过实时服务器转发。这对于发送像光标位置这样的信息是很理想的,因为最小的延迟是很重要的,但持久化则不是。
在multiplayer.dev中,客户端的光标位置被发送到房间里的其他客户端。然而,在这个例子中,光标位置将是随机生成的。
你需要从你的项目的API设置中获得公共的anon
访问令牌。然后你就可以设置Supabase客户端,并开始发送一个客户端的光标位置到通道room1
中的其他客户端。
1const { createClient } = require('@supabase/supabase-js')
2
3const supabase = createClient('https://your-project-ref.supabase.co', 'anon-key', {
4 realtime: {
5 params: {
6 eventsPerSecond: 10,
7 },
8 },
9})
10
11// Channel name can be any string.
12// Create channels with the same name for both the broadcasting and receiving clients.
13const channel = supabase.channel('room1')
14
15// Subscribe registers your client with the server
16channel.subscribe((status) => {
17 if (status === 'SUBSCRIBED') {
18 // now you can start broadcasting cursor positions
19 setInterval(() => {
20 channel.send({
21 type: 'broadcast',
22 event: 'cursor-pos',
23 payload: { x: Math.random(), y: Math.random() },
24 })
25 console.log(status)
26 }, 100)
27 }
28})
info
JavaScript客户端有一个默认的速率限制,即每100毫秒一个实时事件,由eventsPerSecond
配置。
另一个客户端可以订阅频道room1
并接收游标位置。
1// Supabase client setup
2
3// Listen to broadcast messages.
4supabase
5 .channel('room1')
6 .on('broadcast', { event: 'cursor-pos' }, (payload) => console.log(payload))
7 .subscribe((status) => {
8 if (status === 'SUBSCRIBED') {
9 // your callback function will now be called with the messages broadcast by the other client
10 }
11 })
info
type
必须是 broadcast
,event
必须与订阅该频道的客户相匹配。
往返延时
你也可以配置通道,使服务器必须返回一个确认函,表明它收到了 "广播 "信息。如果你想测量往返的延迟,这很有用。
1// Supabase client setup
2
3const channel = supabase.channel('calc-latency', {
4 config: {
5 broadcast: { ack: true },
6 },
7})
8
9channel.subscribe(async (status) => {
10 if (status === 'SUBSCRIBED') {
11 const begin = performance.now()
12
13 await channel.send({
14 type: 'broadcast',
15 event: 'latency',
16 payload: {},
17 })
18
19 const end = performance.now()
20
21 console.log(`Latency is ${end - begin} milliseconds`)
22 }
23})
跟踪和显示哪些用户在线
Presence存储和同步各客户端的共享状态。每当共享状态发生变化时,就会触发sync
事件。join
事件在新客户加入频道时被触发,leave
事件在客户离开时被触发。
每个客户端可以使用通道的track
方法来存储共享状态中的对象。每个客户端只能跟踪一个对象,如果track
被同一个客户端再次调用,那么新的对象就会覆盖共享状态中先前跟踪的对象。你可以使用一个客户端来跟踪和显示在线的用户。
1// Supabase client setup
2
3const channel = supabase.channel('online-users', {
4 config: {
5 presence: {
6 key: 'user1',
7 },
8 },
9})
10
11channel.on('presence', { event: 'sync' }, () => {
12 console.log('Online users: ', channel.presenceState())
13})
14
15channel.on('presence', { event: 'join' }, ({ newPresences }) => {
16 console.log('New users have joined: ', newPresences)
17})
18
19channel.on('presence', { event: 'leave' }, ({ leftPresences }) => {
20 console.log('Users have left: ', newPresences)
21})
22
23channel.subscribe(async (status) => {
24 if (status === 'SUBSCRIBED') {
25 const status = await channel.track({ online_at: new Date().toISOString() })
26 console.log(status)
27 }
28})
然后,您可以使用其他客户端将其他用户添加到频道的存在状态:
1// Supabase client setup
2
3const channel = supabase.channel('online-users', {
4 config: {
5 presence: {
6 key: 'user2',
7 },
8 },
9})
10
11// Presence event handlers setup
12
13channel.subscribe(async (status) => {
14 if (status === 'SUBSCRIBED') {
15 const status = await channel.track({ online_at: new Date().toISOString() })
16 console.log(status)
17 }
18})
如果一个频道在没有存在密钥的情况下被设置,服务器会生成一个随机的UUID。type
必须是presence
,event
必须是sync
,join
,或leave
。
插入和接收持久的信息
Postgres Change Data Capture (CDC)使你的客户能够插入、更新或删除数据库记录,并将这些变化发送给客户。创建一个messages
表来跟踪用户在特定房间创建的消息。
1create table messages ( 2 id serial primary key, 3 message text, 4 user_id text, 5 room_id text, 6 created_at timestamptz default now() 7) 8 9alter table messages enable row level security; 10 11create policy "anon_ins_policy" 12ON messages 13for insert 14to anon 15with check (true); 16 17create policy "anon_sel_policy" 18ON messages 19for select 20to anon 21using (true);
如果它还不存在,创建一个supabase_realtime
发布,并将messages
表添加到该出发布中。
1begin;
2 -- remove the supabase_realtime publication
3 drop publication if exists supabase_realtime;
4
5 -- re-create the supabase_realtime publication with no tables and only for insert
6 create publication supabase_realtime with (publish = 'insert');
7commit;
8
9-- add a table to the publication
10alter publication supabase_realtime add table messages;
然后你可以让客户端监听特定房间的messages
表的变化,并发送和接收持久化的信息。
1// Supabase client setup
2
3const channel = supabase.channel('db-messages')
4
5const roomId = 'room1'
6const userId = 'user1'
7
8channel.on(
9 'postgres_changes',
10 {
11 event: 'INSERT',
12 schema: 'public',
13 table: 'messages',
14 filter: `room_id=eq.${roomId}`,
15 },
16 (payload) => console.log(payload)
17)
18
19channel.subscribe(async (status) => {
20 if (status === 'SUBSCRIBED') {
21 const res = await supabase.from('messages').insert({
22 room_id: roomId,
23 user_id: userId,
24 message: 'Welcome to Realtime!',
25 })
26 console.log(res)
27 }
28})