2025-05-05 19:13:01 +07:00
|
|
|
import { ToastActionCreators } from '@revenge-mod/discord/actions'
|
2025-06-16 22:56:07 +07:00
|
|
|
import { TypedEventEmitter } from '@revenge-mod/discord/common/utils'
|
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
|
|
|
}
|
|
|
|
|
|
2025-06-16 22:56:07 +07:00
|
|
|
const events = new TypedEventEmitter<{
|
|
|
|
|
connect: []
|
|
|
|
|
disconnect: []
|
|
|
|
|
error: [unknown]
|
|
|
|
|
}>()
|
2025-05-05 19:13:01 +07:00
|
|
|
|
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-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-16 22:56:07 +07:00
|
|
|
const ws = (RDTContext.ws = new WebSocket(`ws://${RDTContext.addr}`))
|
2025-05-05 19:13:01 +07:00
|
|
|
|
2025-06-16 22:56:07 +07:00
|
|
|
ws.addEventListener('open', () => {
|
2025-06-09 23:35:23 +07:00
|
|
|
RDTContext.con = true
|
2025-06-16 22:56:07 +07:00
|
|
|
events.emit('connect')
|
2025-05-05 19:13:01 +07:00
|
|
|
})
|
|
|
|
|
|
2025-06-16 22:56:07 +07:00
|
|
|
ws.addEventListener('close', () => {
|
2025-05-05 19:13:01 +07:00
|
|
|
cleanup()
|
2025-06-16 22:56:07 +07:00
|
|
|
events.emit('disconnect')
|
2025-05-05 19:13:01 +07:00
|
|
|
})
|
|
|
|
|
|
2025-06-16 22:56:07 +07:00
|
|
|
ws.addEventListener('error', e => {
|
2025-05-05 19:13:01 +07:00
|
|
|
cleanup()
|
2025-06-16 22:56:07 +07:00
|
|
|
events.emit('error', e)
|
|
|
|
|
|
|
|
|
|
const err = (e as { message: string }).message ?? getErrorStack(e)
|
|
|
|
|
api.logger.error('React DevTools error:', err)
|
|
|
|
|
|
|
|
|
|
ToastActionCreators.open({
|
|
|
|
|
key: 'REACT_DEVTOOLS_ERROR',
|
|
|
|
|
IconComponent: CircleXIcon,
|
|
|
|
|
content: err,
|
|
|
|
|
})
|
2025-05-05 19:13:01 +07:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
__REACT_DEVTOOLS__!.exports.connectToDevTools({
|
2025-06-16 22:56:07 +07:00
|
|
|
websocket: ws,
|
2025-05-05 19:13:01 +07:00
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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-06-16 22:56:07 +07:00
|
|
|
events.on('connect', rerender)
|
|
|
|
|
events.on('disconnect', rerender)
|
2025-05-05 19:13:01 +07:00
|
|
|
|
|
|
|
|
return () => {
|
2025-06-16 22:56:07 +07:00
|
|
|
events.off('connect', rerender)
|
|
|
|
|
events.off('disconnect', rerender)
|
2025-05-05 19:13:01 +07:00
|
|
|
}
|
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
|
|
|
}
|