157 lines
4.8 KiB
TypeScript
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,
|
|
}
|
|
}
|