import { useEffect, useRef, useState } from "react"
import { relayMessage, type MessageName, type PlasmoMessaging } from "./index"
import { listen as messageListen } from "./message"
import { listen as portListen } from "./port"
import { relay } from "./relay"
/**
* Used in any extension context to listen and send messages to background.
*/
export const useMessage = <RequestBody, ResponseBody>(
handler: PlasmoMessaging.Handler<string, RequestBody, ResponseBody>
) => {
const [data, setData] = useState<RequestBody>()
useEffect(
() =>
messageListen<RequestBody, ResponseBody>(async (req, res) => {
setData(req.body)
await handler(req, res)
}),
[handler]
)
return {
data
}
}
export const usePort: PlasmoMessaging.PortHook = (name) => {
const portRef = useRef<chrome.runtime.Port>(undefined)
const reconnectRef = useRef(0)
const [data, setData] = useState()
useEffect(() => {
if (!name) {
return null
}
const { port, disconnect } = portListen(
name,
(msg) => {
setData(msg)
},
() => {
reconnectRef.current = reconnectRef.current + 1
}
)
portRef.current = port
return disconnect
}, [
name,
reconnectRef.current // This is needed to force a new port ref
])
return {
data,
send: (body) => {
portRef.current.postMessage({
name,
body
})
},
listen: (handler) => portListen(name, handler)
}
}
/**
* TODO: Perhaps add a way to detect if this hook is being used inside CS?
*/
export function useMessageRelay<RequestBody = any>(
req: PlasmoMessaging.Request<MessageName, RequestBody>
) {
useEffect(() => relayMessage(req), [])
}
export const useRelay: PlasmoMessaging.RelayFx = (req, onMessage) => {
const relayRef = useRef<() => void>(undefined)
useEffect(() => {
relayRef.current = relay(req, onMessage)
return relayRef.current
}, [])
return () => relayRef.current?.()
}