@supabase/realtime-js
Version:
Listen to realtime updates to your PostgreSQL database
131 lines (112 loc) • 2.93 kB
text/typescript
import { DEFAULT_TIMEOUT } from '../lib/constants'
import type RealtimeChannel from '../RealtimeChannel'
export default class Push {
sent: boolean = false
timeoutTimer: number | undefined = undefined
ref: string = ''
receivedResp: {
status: string
response: { [key: string]: any }
} | null = null
recHooks: {
status: string
callback: Function
}[] = []
refEvent: string | null = null
/**
* Initializes the Push
*
* @param channel The Channel
* @param event The event, for example `"phx_join"`
* @param payload The payload, for example `{user_id: 123}`
* @param timeout The push timeout in milliseconds
*/
constructor(
public channel: RealtimeChannel,
public event: string,
public payload: { [key: string]: any } = {},
public timeout: number = DEFAULT_TIMEOUT
) {}
resend(timeout: number) {
this.timeout = timeout
this._cancelRefEvent()
this.ref = ''
this.refEvent = null
this.receivedResp = null
this.sent = false
this.send()
}
send() {
if (this._hasReceived('timeout')) {
return
}
this.startTimeout()
this.sent = true
this.channel.socket.push({
topic: this.channel.topic,
event: this.event,
payload: this.payload,
ref: this.ref,
join_ref: this.channel._joinRef(),
})
}
updatePayload(payload: { [key: string]: any }): void {
this.payload = { ...this.payload, ...payload }
}
receive(status: string, callback: Function) {
if (this._hasReceived(status)) {
callback(this.receivedResp?.response)
}
this.recHooks.push({ status, callback })
return this
}
startTimeout() {
if (this.timeoutTimer) {
return
}
this.ref = this.channel.socket._makeRef()
this.refEvent = this.channel._replyEventName(this.ref)
const callback = (payload: any) => {
this._cancelRefEvent()
this._cancelTimeout()
this.receivedResp = payload
this._matchReceive(payload)
}
this.channel._on(this.refEvent, {}, callback)
this.timeoutTimer = <any>setTimeout(() => {
this.trigger('timeout', {})
}, this.timeout)
}
trigger(status: string, response: any) {
if (this.refEvent)
this.channel._trigger(this.refEvent, { status, response })
}
destroy() {
this._cancelRefEvent()
this._cancelTimeout()
}
private _cancelRefEvent() {
if (!this.refEvent) {
return
}
this.channel._off(this.refEvent, {})
}
private _cancelTimeout() {
clearTimeout(this.timeoutTimer)
this.timeoutTimer = undefined
}
private _matchReceive({
status,
response,
}: {
status: string
response: Function
}) {
this.recHooks
.filter((h) => h.status === status)
.forEach((h) => h.callback(response))
}
private _hasReceived(status: string) {
return this.receivedResp && this.receivedResp.status === status
}
}