2023-11-28 13:18:25 +00:00
|
|
|
import type { Accessor, JSX } from 'solid-js'
|
|
|
|
|
|
|
|
import { fetchEventSource } from '@microsoft/fetch-event-source'
|
|
|
|
import { createContext, useContext, createSignal, createEffect } from 'solid-js'
|
2023-11-28 15:36:00 +00:00
|
|
|
|
2023-11-28 13:18:25 +00:00
|
|
|
import { useSession } from './session'
|
2023-12-03 10:22:42 +00:00
|
|
|
import { useAuthorizer } from './authorizer'
|
2023-11-28 13:18:25 +00:00
|
|
|
|
|
|
|
export interface SSEMessage {
|
|
|
|
id: string
|
|
|
|
entity: string
|
|
|
|
action: string
|
|
|
|
payload: any // Author | Shout | Reaction | Message
|
|
|
|
created_at?: number // unixtime x1000
|
|
|
|
seen?: boolean
|
|
|
|
}
|
|
|
|
|
|
|
|
type MessageHandler = (m: SSEMessage) => void
|
|
|
|
|
|
|
|
export interface ConnectContextType {
|
|
|
|
addHandler: (handler: MessageHandler) => void
|
|
|
|
connected: Accessor<boolean>
|
|
|
|
}
|
|
|
|
|
|
|
|
const ConnectContext = createContext<ConnectContextType>()
|
|
|
|
|
|
|
|
export const ConnectProvider = (props: { children: JSX.Element }) => {
|
|
|
|
const [messageHandlers, setHandlers] = createSignal<Array<MessageHandler>>([])
|
|
|
|
// const [messages, setMessages] = createSignal<Array<SSEMessage>>([]);
|
|
|
|
|
|
|
|
const [connected, setConnected] = createSignal(false)
|
2023-12-03 10:22:42 +00:00
|
|
|
const {
|
|
|
|
isAuthenticated,
|
|
|
|
actions: { getToken },
|
|
|
|
} = useSession()
|
2023-11-28 13:18:25 +00:00
|
|
|
|
|
|
|
const addHandler = (handler: MessageHandler) => {
|
|
|
|
setHandlers((hhh) => [...hhh, handler])
|
|
|
|
}
|
2023-12-03 16:41:59 +00:00
|
|
|
const [retried, setRetried] = createSignal<number>(0)
|
2023-11-28 13:18:25 +00:00
|
|
|
const listen = () => {
|
2023-12-13 23:56:44 +00:00
|
|
|
const token = getToken()
|
|
|
|
console.log(`[context.connect] token: ${token}`)
|
|
|
|
if (token && !connected() && retried() < 4) {
|
|
|
|
fetchEventSource('https://connect.discours.io', {
|
|
|
|
method: 'GET',
|
|
|
|
headers: {
|
|
|
|
'Content-Type': 'application/json',
|
|
|
|
Authorization: token,
|
|
|
|
},
|
|
|
|
onmessage(event) {
|
|
|
|
const m: SSEMessage = JSON.parse(event.data)
|
|
|
|
console.log('[context.connect] Received message:', m)
|
2023-11-28 13:18:25 +00:00
|
|
|
|
2023-12-13 23:56:44 +00:00
|
|
|
// Iterate over all registered handlers and call them
|
|
|
|
messageHandlers().forEach((handler) => handler(m))
|
|
|
|
},
|
|
|
|
onclose() {
|
|
|
|
console.log('[context.connect] sse connection closed by server')
|
|
|
|
setConnected(false)
|
|
|
|
},
|
|
|
|
onerror(err) {
|
|
|
|
console.error('[context.connect] sse connection error', err)
|
2023-12-08 11:49:50 +00:00
|
|
|
setRetried((r) => r + 1)
|
2023-12-13 23:56:44 +00:00
|
|
|
setConnected(false)
|
|
|
|
throw new Error(err) // NOTE: simple hack to close the connection
|
|
|
|
},
|
|
|
|
})
|
2023-11-28 13:18:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
createEffect(() => {
|
|
|
|
if (isAuthenticated() && !connected()) {
|
|
|
|
listen()
|
|
|
|
setConnected(true)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
const value: ConnectContextType = { addHandler, connected }
|
|
|
|
|
|
|
|
return <ConnectContext.Provider value={value}>{props.children}</ConnectContext.Provider>
|
|
|
|
}
|
|
|
|
|
|
|
|
export const useConnect = () => useContext(ConnectContext)
|