2025-05-05 19:13:01 +07:00
|
|
|
import { ToastActionCreators } from '@revenge-mod/discord/actions'
|
2025-05-19 01:43:41 +07:00
|
|
|
import { lookupGeneratedIconComponent } from '@revenge-mod/utils/discord'
|
2025-05-05 19:13:01 +07:00
|
|
|
import { getErrorStack } from '@revenge-mod/utils/errors'
|
|
|
|
|
import { useReRender } from '@revenge-mod/utils/react'
|
2025-06-08 19:01:33 +07:00
|
|
|
import { useEffect } from 'react'
|
2025-05-18 22:24:48 +07:00
|
|
|
import { api } from '.'
|
2025-05-05 19:13:01 +07:00
|
|
|
|
2025-06-09 23:35:23 +07:00
|
|
|
export const RDTContext: {
|
2025-05-05 19:13:01 +07:00
|
|
|
ws: WebSocket | undefined
|
2025-06-09 23:35:23 +07:00
|
|
|
addr: string
|
|
|
|
|
con: boolean
|
|
|
|
|
active: boolean
|
2025-05-05 19:13:01 +07:00
|
|
|
} = {
|
2025-06-09 23:35:23 +07:00
|
|
|
active: Boolean(globalThis.__REACT_DEVTOOLS__),
|
2025-05-05 19:13:01 +07:00
|
|
|
ws: undefined,
|
2025-06-09 23:35:23 +07:00
|
|
|
addr: 'localhost:8097',
|
|
|
|
|
con: false,
|
2025-05-05 19:13:01 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type Subscription = (event: 1 | 2 | 3, err?: unknown) => void
|
|
|
|
|
const subscriptions: Set<Subscription> = new Set()
|
|
|
|
|
|
2025-06-03 16:24:58 +07:00
|
|
|
const CircleXIcon = lookupGeneratedIconComponent(
|
|
|
|
|
'CircleXIcon',
|
|
|
|
|
'CircleXIcon-secondary',
|
|
|
|
|
'CircleXIcon-primary',
|
|
|
|
|
)
|
2025-05-10 02:11:44 +07:00
|
|
|
|
2025-05-05 19:13:01 +07:00
|
|
|
subscriptions.add((e, err) => {
|
|
|
|
|
if (e === 3) {
|
2025-06-03 16:24:58 +07:00
|
|
|
const actualError =
|
|
|
|
|
(err as { message: string }).message ?? getErrorStack(err)
|
2025-05-05 19:13:01 +07:00
|
|
|
|
2025-05-18 22:24:48 +07:00
|
|
|
api.logger.error('React DevTools error:', actualError)
|
2025-05-10 02:11:44 +07:00
|
|
|
|
2025-05-05 19:13:01 +07:00
|
|
|
ToastActionCreators.open({
|
2025-05-22 02:48:54 +07:00
|
|
|
key: 'REACT_DEVTOOLS_ERROR',
|
2025-05-10 02:11:44 +07:00
|
|
|
IconComponent: CircleXIcon,
|
2025-05-05 19:13:01 +07:00
|
|
|
content: actualError,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
2025-06-09 23:35:23 +07:00
|
|
|
export function connect() {
|
|
|
|
|
if (!RDTContext.active || RDTContext.ws) return
|
2025-05-05 19:13:01 +07:00
|
|
|
|
2025-06-09 23:35:23 +07:00
|
|
|
const websocket = (RDTContext.ws = new WebSocket(`ws://${RDTContext.addr}`))
|
2025-05-05 19:13:01 +07:00
|
|
|
|
|
|
|
|
websocket.addEventListener('open', () => {
|
2025-06-09 23:35:23 +07:00
|
|
|
RDTContext.con = true
|
2025-05-05 19:13:01 +07:00
|
|
|
for (const sub of subscriptions) sub(1)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
websocket.addEventListener('close', () => {
|
|
|
|
|
cleanup()
|
|
|
|
|
for (const sub of subscriptions) sub(2)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
websocket.addEventListener('error', e => {
|
|
|
|
|
cleanup()
|
|
|
|
|
for (const sub of subscriptions) sub(3, e)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
__REACT_DEVTOOLS__!.exports.connectToDevTools({
|
|
|
|
|
websocket,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function cleanup() {
|
2025-06-09 23:35:23 +07:00
|
|
|
RDTContext.con = false
|
|
|
|
|
RDTContext.ws = undefined
|
2025-05-05 19:13:01 +07:00
|
|
|
}
|
|
|
|
|
|
2025-06-09 23:35:23 +07:00
|
|
|
export function disconnect() {
|
|
|
|
|
if (RDTContext.ws) RDTContext.ws.close()
|
2025-05-05 19:13:01 +07:00
|
|
|
}
|
|
|
|
|
|
2025-06-09 23:35:23 +07:00
|
|
|
export function useIsConnected() {
|
2025-05-05 19:13:01 +07:00
|
|
|
const rerender = useReRender()
|
|
|
|
|
|
2025-06-08 19:01:33 +07:00
|
|
|
useEffect(() => {
|
2025-05-05 19:13:01 +07:00
|
|
|
const sub: Subscription = e => (e === 1 || e === 2) && rerender()
|
|
|
|
|
subscriptions.add(sub)
|
|
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
|
subscriptions.delete(sub)
|
|
|
|
|
}
|
2025-06-08 19:01:33 +07:00
|
|
|
}, [rerender])
|
2025-05-05 19:13:01 +07:00
|
|
|
|
2025-06-09 23:35:23 +07:00
|
|
|
return RDTContext.con
|
2025-05-05 19:13:01 +07:00
|
|
|
}
|