tldraw/state/coop/client-pusher.ts

124 lines
3 KiB
TypeScript
Raw Normal View History

2021-06-28 20:45:06 +00:00
import Pusher from 'pusher-js'
import * as PusherTypes from 'pusher-js'
import state from 'state/state'
import { Shape } from 'types'
class RoomClient {
room: string
pusher: Pusher
2021-06-28 22:22:23 +00:00
channel: PusherTypes.PresenceChannel
2021-06-28 20:45:06 +00:00
lastCursorEventTime = 0
2021-06-28 22:22:23 +00:00
id: string
2021-06-28 20:45:06 +00:00
constructor() {
// Create pusher instance and bind events
2021-06-28 22:22:23 +00:00
this.pusher = new Pusher('5dc87c88b8684bda655a', {
cluster: 'eu',
authEndpoint: 'http://localhost:3000/api/pusher-auth',
})
2021-06-28 20:45:06 +00:00
this.pusher.connection.bind('connecting', () =>
state.send('RT_CHANGED_STATUS', { status: 'connecting' })
)
this.pusher.connection.bind('connected', () =>
state.send('RT_CHANGED_STATUS', { status: 'connected' })
)
this.pusher.connection.bind('unavailable', () =>
state.send('RT_CHANGED_STATUS', { status: 'unavailable' })
)
2021-06-28 22:22:23 +00:00
this.pusher.connection.bind('failed', () => {
2021-06-28 20:45:06 +00:00
state.send('RT_CHANGED_STATUS', { status: 'failed' })
2021-06-28 22:22:23 +00:00
})
2021-06-28 20:45:06 +00:00
2021-06-28 22:22:23 +00:00
this.pusher.connection.bind('disconnected', () => {
2021-06-28 20:45:06 +00:00
state.send('RT_CHANGED_STATUS', { status: 'disconnected' })
2021-06-28 22:22:23 +00:00
})
2021-06-28 20:45:06 +00:00
}
2021-06-28 22:22:23 +00:00
connect(roomId: string) {
this.room = 'presence-' + roomId
2021-06-28 20:45:06 +00:00
// Subscribe to channel
2021-06-28 22:22:23 +00:00
this.channel = this.pusher.subscribe(
this.room
) as PusherTypes.PresenceChannel
2021-06-28 20:45:06 +00:00
2021-06-28 22:22:23 +00:00
this.channel.bind('pusher:subscription_error', (err: string) => {
console.warn(err)
2021-06-28 20:45:06 +00:00
state.send('RT_CHANGED_STATUS', { status: 'subscription-error' })
})
this.channel.bind('pusher:subscription_succeeded', () => {
2021-06-28 22:22:23 +00:00
const me = this.channel.members.me
const userId = me.id
this.id = userId
2021-06-28 20:45:06 +00:00
state.send('RT_CHANGED_STATUS', { status: 'subscribed' })
})
this.channel.bind(
'created_shape',
(payload: { id: string; pageId: string; shape: Shape }) => {
2021-06-28 22:22:23 +00:00
if (payload.id === this.id) return
2021-06-28 20:45:06 +00:00
state.send('RT_CREATED_SHAPE', payload)
}
)
this.channel.bind(
'deleted_shape',
(payload: { id: string; pageId: string; shape: Shape }) => {
2021-06-28 22:22:23 +00:00
if (payload.id === this.id) return
2021-06-28 20:45:06 +00:00
state.send('RT_DELETED_SHAPE', payload)
}
)
this.channel.bind(
'edited_shape',
(payload: { id: string; pageId: string; change: Partial<Shape> }) => {
2021-06-28 22:22:23 +00:00
if (payload.id === this.id) return
2021-06-28 20:45:06 +00:00
state.send('RT_EDITED_SHAPE', payload)
}
)
this.channel.bind(
2021-06-28 22:22:23 +00:00
'client-moved-cursor',
2021-06-28 20:45:06 +00:00
(payload: { id: string; pageId: string; point: number[] }) => {
if (payload.id === this.id) return
state.send('RT_MOVED_CURSOR', payload)
}
)
}
disconnect() {
this.pusher.unsubscribe(this.room)
}
reconnect() {
this.pusher.subscribe(this.room)
}
moveCursor(pageId: string, point: number[]) {
if (!this.channel) return
const now = Date.now()
2021-06-28 22:22:23 +00:00
if (now - this.lastCursorEventTime > 200) {
2021-06-28 20:45:06 +00:00
this.lastCursorEventTime = now
2021-06-28 22:22:23 +00:00
this.channel?.trigger('client-moved-cursor', {
2021-06-28 20:45:06 +00:00
id: this.id,
pageId,
point,
})
}
}
}
export default new RoomClient()