perf(island): ⚡ switch to websocket to check connection status changes
This commit is contained in:
parent
01f5986e0b
commit
8f223d34da
|
|
@ -1,52 +1,41 @@
|
||||||
import { type Signal, useSignal } from '@preact/signals'
|
import { type Signal, useComputed, useSignal } from '@preact/signals'
|
||||||
import { useEffect } from 'preact/hooks'
|
import { useEffect } from 'preact/hooks'
|
||||||
import { JSX } from 'preact'
|
import { IS_BROWSER } from '$fresh/runtime.ts'
|
||||||
import { requestApi } from ':src/utils.ts'
|
|
||||||
|
|
||||||
type NetworkConnection = {
|
|
||||||
addEventListener: (
|
|
||||||
type: 'change',
|
|
||||||
listener: (event: Event) => void | Promise<void>,
|
|
||||||
) => void
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function IsOnline(
|
export default function IsOnline(
|
||||||
{ online, offline }: { online?: string; offline: string },
|
{ online, offline }: { online?: string; offline: string },
|
||||||
) {
|
) {
|
||||||
const status = useSignal(online)
|
if (!IS_BROWSER) {
|
||||||
const connection = 'connection' in navigator
|
return <span class={'island__is_online'}>{offline}</span>
|
||||||
? navigator.connection as NetworkConnection
|
|
||||||
: null
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
// Update connection status on network changes
|
|
||||||
connection?.addEventListener('change', () => {
|
|
||||||
updateNetworkStatus(status, online, offline)
|
|
||||||
})
|
|
||||||
// Update connection status on 1st load
|
|
||||||
updateNetworkStatus(status, online, offline)
|
|
||||||
// Update connection status on interval (10s)
|
|
||||||
setInterval(() => updateNetworkStatus(status, online, offline), 10_000)
|
|
||||||
})
|
|
||||||
|
|
||||||
return <>{status}</>
|
|
||||||
}
|
|
||||||
|
|
||||||
async function updateNetworkStatus(
|
|
||||||
status: Signal<JSX.Element>,
|
|
||||||
online: string | undefined,
|
|
||||||
offline: string,
|
|
||||||
) {
|
|
||||||
const isOnline = await requestApi<void, boolean>(
|
|
||||||
'/serviceworker/is-online',
|
|
||||||
'POST',
|
|
||||||
).catch(() => false)
|
|
||||||
|
|
||||||
if (isOnline) {
|
|
||||||
status.value = online === undefined
|
|
||||||
? <span style={{ display: 'none' }}></span>
|
|
||||||
: <span>{online}</span>
|
|
||||||
} else {
|
|
||||||
status.value = <span class={'island__is_online'}>{offline}</span>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const status = useSignal(false)
|
||||||
|
const displayed = useComputed(() => {
|
||||||
|
if (status.value && online) {
|
||||||
|
return <span>{online}</span>
|
||||||
|
}
|
||||||
|
if (status.value) {
|
||||||
|
return <span style={{ display: 'none' }}></span>
|
||||||
|
}
|
||||||
|
return <span class={'island__is_online'}>{offline}</span>
|
||||||
|
})
|
||||||
|
useEffect(() => openSocket(status, { id: undefined }), [])
|
||||||
|
|
||||||
|
return <>{displayed}</>
|
||||||
|
}
|
||||||
|
|
||||||
|
function openSocket(status: Signal<boolean>, ref: { id: number | undefined }) {
|
||||||
|
const socket = new WebSocket(
|
||||||
|
`wss://${location.host}/api/serviceworker/is-online`,
|
||||||
|
)
|
||||||
|
socket.addEventListener('open', () => {
|
||||||
|
status.value = true
|
||||||
|
clearInterval(ref.id)
|
||||||
|
})
|
||||||
|
socket.addEventListener('close', () => {
|
||||||
|
status.value = false
|
||||||
|
// Try reconnect every 5s
|
||||||
|
const id = setInterval(() => openSocket(status, ref), 5_000)
|
||||||
|
ref.id = id
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,10 @@ export async function handler(request: Request, ctx: FreshContext) {
|
||||||
// Get response
|
// Get response
|
||||||
const response = await ctx.next()
|
const response = await ctx.next()
|
||||||
|
|
||||||
|
if (ctx.state?.skipMiddlewares) {
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
|
||||||
// Use custom middleware hooks
|
// Use custom middleware hooks
|
||||||
useSecurityHeaders(request, response, ctx)
|
useSecurityHeaders(request, response, ctx)
|
||||||
await useCsp(request, response, ctx)
|
await useCsp(request, response, ctx)
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import { SessionHandlers } from ':src/session/mod.ts'
|
import { SessionHandlers } from ':src/session/mod.ts'
|
||||||
import { respondApi } from ':src/utils.ts'
|
|
||||||
|
|
||||||
export const handler: SessionHandlers = {
|
export const handler: SessionHandlers = {
|
||||||
POST() {
|
GET(req: Request, ctx) {
|
||||||
// Check if server is online
|
const { response } = Deno.upgradeWebSocket(req)
|
||||||
return respondApi<'success', true>('success', true)
|
ctx.state.skipMiddlewares = true
|
||||||
|
return response
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue