Use only WS for machine chat subscriptions
This commit is contained in:
parent
d2108ce16b
commit
988bf25010
2 changed files with 26 additions and 127 deletions
|
|
@ -98,69 +98,15 @@ export async function subscribeMachineUpdates(
|
|||
onError?: (error: Error) => void
|
||||
): Promise<() => void> {
|
||||
const { client, token } = await ensureClient()
|
||||
let stopped = false
|
||||
let pollTimer: ReturnType<typeof setInterval> | null = null
|
||||
|
||||
const stopPoll = () => {
|
||||
if (pollTimer) {
|
||||
clearInterval(pollTimer)
|
||||
pollTimer = null
|
||||
}
|
||||
}
|
||||
|
||||
const startPoll = async () => {
|
||||
stopPoll()
|
||||
try {
|
||||
const { apiBaseUrl } = await getMachineStoreConfig()
|
||||
const poll = async () => {
|
||||
try {
|
||||
const res = await fetch(`${apiBaseUrl}/api/machines/chat/poll`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ machineToken: token }),
|
||||
})
|
||||
if (!res.ok) throw new Error(`poll failed: ${res.status}`)
|
||||
const data = (await res.json()) as MachineUpdatePayload
|
||||
if (!stopped) callback(data)
|
||||
} catch (err) {
|
||||
if (!stopped) onError?.(err as Error)
|
||||
}
|
||||
}
|
||||
await poll()
|
||||
pollTimer = setInterval(poll, 4000)
|
||||
} catch (err) {
|
||||
onError?.(err as Error)
|
||||
}
|
||||
}
|
||||
|
||||
const sub = client.onUpdate(
|
||||
FN_CHECK_UPDATES as unknown as FunctionReference<"query">,
|
||||
{ machineToken: token },
|
||||
(value) => {
|
||||
stopPoll()
|
||||
callback(value)
|
||||
},
|
||||
(err) => {
|
||||
onError?.(err)
|
||||
startPoll().catch(() => {
|
||||
// erro já reportado via onError
|
||||
})
|
||||
}
|
||||
(value) => callback(value),
|
||||
(err) => onError?.(err)
|
||||
)
|
||||
|
||||
// fallback caso a inscrição falhe imediatamente
|
||||
setTimeout(() => {
|
||||
if (stopped) return
|
||||
// Se não houver mensagens recebidas pelo WS em 3s, inicia polling
|
||||
// (o callback do WS encerra o polling caso volte a funcionar)
|
||||
startPoll().catch(() => {
|
||||
// erro já reportado via onError
|
||||
})
|
||||
}, 3000)
|
||||
|
||||
return () => {
|
||||
stopped = true
|
||||
stopPoll()
|
||||
sub.unsubscribe()
|
||||
}
|
||||
}
|
||||
|
|
@ -171,53 +117,6 @@ export async function subscribeMachineMessages(
|
|||
onError?: (error: Error) => void
|
||||
): Promise<() => void> {
|
||||
const { client, token } = await ensureClient()
|
||||
let stopped = false
|
||||
let pollTimer: ReturnType<typeof setInterval> | null = null
|
||||
let lastSince = 0
|
||||
|
||||
const stopPoll = () => {
|
||||
if (pollTimer) {
|
||||
clearInterval(pollTimer)
|
||||
pollTimer = null
|
||||
}
|
||||
}
|
||||
|
||||
const startPoll = async () => {
|
||||
stopPoll()
|
||||
try {
|
||||
const { apiBaseUrl } = await getMachineStoreConfig()
|
||||
const poll = async () => {
|
||||
try {
|
||||
const res = await fetch(`${apiBaseUrl}/api/machines/chat/messages`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
action: "list",
|
||||
machineToken: token,
|
||||
ticketId,
|
||||
since: lastSince || undefined,
|
||||
}),
|
||||
})
|
||||
if (!res.ok) throw new Error(`messages poll failed: ${res.status}`)
|
||||
const data = (await res.json()) as MessagesPayload
|
||||
if (!stopped) {
|
||||
callback(data)
|
||||
const newest = (data.messages as ChatMessage[]).reduce(
|
||||
(max: number, msg: ChatMessage) => Math.max(max, msg.createdAt),
|
||||
lastSince
|
||||
)
|
||||
lastSince = newest
|
||||
}
|
||||
} catch (err) {
|
||||
if (!stopped) onError?.(err as Error)
|
||||
}
|
||||
}
|
||||
await poll()
|
||||
pollTimer = setInterval(poll, 4000)
|
||||
} catch (err) {
|
||||
onError?.(err as Error)
|
||||
}
|
||||
}
|
||||
|
||||
const sub = client.onUpdate(
|
||||
FN_LIST_MESSAGES as unknown as FunctionReference<"query">,
|
||||
|
|
@ -225,33 +124,11 @@ export async function subscribeMachineMessages(
|
|||
machineToken: token,
|
||||
ticketId,
|
||||
},
|
||||
(value) => {
|
||||
stopPoll()
|
||||
callback(value)
|
||||
const newest = (value.messages as ChatMessage[]).reduce(
|
||||
(max: number, msg: ChatMessage) => Math.max(max, msg.createdAt),
|
||||
lastSince
|
||||
)
|
||||
lastSince = newest
|
||||
},
|
||||
(err) => {
|
||||
onError?.(err)
|
||||
startPoll().catch(() => {
|
||||
// erro já reportado via onError
|
||||
})
|
||||
}
|
||||
(value) => callback(value),
|
||||
(err) => onError?.(err)
|
||||
)
|
||||
|
||||
setTimeout(() => {
|
||||
if (stopped) return
|
||||
startPoll().catch(() => {
|
||||
// erro já reportado via onError
|
||||
})
|
||||
}, 3000)
|
||||
|
||||
return () => {
|
||||
stopped = true
|
||||
stopPoll()
|
||||
sub.unsubscribe()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -179,6 +179,28 @@ export function TicketChatPanel({ ticketId }: TicketChatPanelProps) {
|
|||
toast.error(`Mensagem muito longa (max. ${MAX_MESSAGE_LENGTH} caracteres).`)
|
||||
return
|
||||
}
|
||||
|
||||
// Garantir que a sessão de chat ao vivo exista antes de enviar
|
||||
if (liveChat?.hasMachine && !hasActiveSession) {
|
||||
try {
|
||||
await startLiveChat({
|
||||
ticketId: ticketId as Id<"tickets">,
|
||||
actorId: viewerId as Id<"users">,
|
||||
})
|
||||
} catch (error: unknown) {
|
||||
const message = (() => {
|
||||
if (error instanceof Error) {
|
||||
const errorMsg = error.message.toLowerCase()
|
||||
if (errorMsg.includes("offline")) return "Máquina offline. Aguarde a máquina ficar online para iniciar o chat."
|
||||
if (errorMsg.includes("não encontrad") || errorMsg.includes("not found")) return "Máquina não encontrada"
|
||||
}
|
||||
return "Não foi possível iniciar o chat ao vivo."
|
||||
})()
|
||||
toast.error(message, { id: "live-chat" })
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
setIsSending(true)
|
||||
try {
|
||||
await postChatMessage({
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue