hololake-system-architecture/product-source/hololake-platform/src/hooks/useGuanghuRouter.ts

157 lines
4.8 KiB
TypeScript

import { useCallback, useEffect, useState } from 'react'
import { invoke } from '@tauri-apps/api/core'
import { isTauri } from '../mock-tauri'
import { trackEvent } from '../lib/telemetry'
import {
INITIAL_GUANGHU_ROUTER_STATE,
markGuanghuAuthorizationApproved,
reduceGuanghuRouterEvent,
type GuanghuAuthorizationCard,
type GuanghuRouterState,
} from '../lib/guanghuRouter'
const ROUTER_EVENT = 'guanghu-router-event'
function initialRouterState(): GuanghuRouterState {
if (
import.meta.env.DEV
&& typeof window !== 'undefined'
&& new URLSearchParams(window.location.search).get('world-preview') === 'online'
) {
return {
cards: [],
error: null,
latestReceipt: {
connection_id: 'local-visual-preview',
node_id: 'JD-FD-PRIMARY',
receipt_id: 'local-visual-preview',
state: 'online',
},
status: 'online',
}
}
return INITIAL_GUANGHU_ROUTER_STATE
}
function errorText(error: unknown): string {
return error instanceof Error ? error.message : String(error)
}
export function useGuanghuRouter(): {
approve: (card: GuanghuAuthorizationCard) => Promise<void>
connect: () => Promise<void>
disconnect: () => Promise<void>
probeRepository: (repositoryPath: string) => Promise<unknown>
requestRepositoryUpload: (repositoryPath: string) => Promise<unknown>
state: GuanghuRouterState
} {
const [state, setState] = useState<GuanghuRouterState>(initialRouterState)
useEffect(() => {
if (!isTauri()) return
let active = true
let unlisten: (() => void) | null = null
void import('@tauri-apps/api/event').then(({ listen }) => (
listen<unknown>(ROUTER_EVENT, event => {
if (active) setState(current => reduceGuanghuRouterEvent(current, event.payload))
})
)).then(stop => {
if (active) unlisten = stop
else stop()
}).catch(error => {
if (active) {
setState(current => ({
...current,
error: `guanghu_router_event_listener_failed: ${errorText(error)}`,
status: 'error',
}))
}
})
return () => {
active = false
unlisten?.()
}
}, [])
const connect = useCallback(async () => {
if (!isTauri()) {
setState(current => ({
...current,
error: 'guanghu_router_desktop_runtime_required',
status: 'error',
}))
return
}
setState(current => ({ ...current, error: null, status: 'connecting' }))
trackEvent('guanghu_router_connect_requested', { node: 'JD-FD-PRIMARY' })
try {
const event = await invoke<unknown>('guanghu_router_connect')
setState(current => reduceGuanghuRouterEvent(current, event))
trackEvent('guanghu_router_connect_completed', { node: 'JD-FD-PRIMARY', result: 'online' })
} catch (error) {
const reason = errorText(error)
setState(current => ({ ...current, error: reason, status: 'error' }))
trackEvent('guanghu_router_connect_completed', { node: 'JD-FD-PRIMARY', result: 'error', reason })
}
}, [])
const disconnect = useCallback(async () => {
if (!isTauri()) return
try {
await invoke('guanghu_router_disconnect')
setState(current => ({ ...current, error: null, status: 'offline' }))
trackEvent('guanghu_router_disconnected', { node: 'JD-FD-PRIMARY' })
} catch (error) {
setState(current => ({ ...current, error: errorText(error), status: 'error' }))
}
}, [])
const approve = useCallback(async (card: GuanghuAuthorizationCard) => {
if (!isTauri()) return
try {
const response = await invoke<unknown>('guanghu_router_approve', {
digest: card.digest,
workorderId: card.workorder.id,
})
setState(current => markGuanghuAuthorizationApproved(
current,
card.workorder.id,
response,
))
trackEvent('guanghu_router_authorization_decided', {
action: card.workorder.action,
node: card.workorder.target,
result: 'approved',
scope: card.workorder.scope,
})
} catch (error) {
setState(current => ({ ...current, error: errorText(error) }))
}
}, [])
const probeRepository = useCallback(async (repositoryPath: string) => {
if (!isTauri()) throw new Error('guanghu_router_desktop_runtime_required')
return invoke<unknown>('guanghu_router_probe_repository', { repositoryPath })
}, [])
const requestRepositoryUpload = useCallback(async (repositoryPath: string) => {
if (!isTauri()) throw new Error('guanghu_router_desktop_runtime_required')
const response = await invoke<unknown>('guanghu_router_request_repository_upload', {
repositoryPath,
})
trackEvent('guanghu_router_repository_upload_requested', {
node: 'JD-FD-PRIMARY',
repositoryPath,
})
return response
}, [])
return {
approve,
connect,
disconnect,
probeRepository,
requestRepositoryUpload,
state,
}
}