import {
call as e,
put as t,
fork as o,
select as l,
spawn as a,
take as n,
join as r,
delay as i,
race as c,
} from "redux-saga/effects"
import { block as s } from "../../lib/effects"
import { first as d, isEmpty as y, last as m } from "../../lib/array"
import { logWarning as f, taskErrorSaga as u } from "../../error"
import {
getChatMessageCount as h,
fetchMessagesCmd as I,
reloadMessagesCmd as p,
subChatMessagesEvt as g,
setChatMessagesFetching as T,
getChatMessageSeqLoaded as w,
} from "../list-view"
import { isQueryValid as $, getQueryCount as L, hasQueryIntersection as k } from "../message"
import { createChatLoader as A } from "./loader"
import { createCtrlCtxRef as C } from "./loader-step"
import { LOADER_FAIL as N, PORTION_SIZE_MAX as O } from "./loader.constants"
import { isSeqInRange as v, noMessagesLoaded as x } from "../chat.model"
import { CHAT_WORKER as R } from "../chat.constant"
import { sharedCoreMessagesUpdate as B } from "../../api/data.action"
const q = 1e4,
E = 3e4
export const isUpdateChatMessagesByWorker = (e) => (t) => B.match(t) && t.payload.worker === e
export function* fetchCtrl({ name: o, ctxRef: l }) {
let a = 0
try {
;((a = yield e(l.waitStart)),
yield t(T({ name: o, status: !0, timestamp: a })),
yield i(q),
yield t(
f({
message: "chat loading slow",
stack: `runFetchWorker: <${o}>: callCount=${l.callCount}`,
}),
),
yield s())
} finally {
a && (yield t(T({ name: o, status: !1, timestamp: Date.now(), callCount: l.callCount })))
}
}
export function* chatCoreEventLoader(s, T) {
const B = { [R.INITIAL]: null, [R.TOP]: null, [R.BOTTOM]: null }
function q() {
;(B[R.INITIAL]?.cancel(), B[R.TOP]?.cancel(), B[R.BOTTOM]?.cancel())
}
let M = null
function* W({ name: s, loader: d }) {
B[s]?.isRunning() ||
(B[s] = yield a(function* () {
let a = null
try {
if (B[R.INITIAL]?.isRunning() && !(yield r(B[R.INITIAL]))) return
const m = C()
let u
a = yield o(fetchCtrl, { name: s, ctxRef: m })
do {
u = M
const o = yield l(w),
a = { gte: o.top, lte: o.bottom },
r = yield l(h),
[I, p] = yield c([e(d.fetch[s], { query: u, loaded: a, count: r, ctxRef: m }), i(E)])
p || I === N
? (p &&
(yield t(
f({ message: "chat loading cancelled", stack: `runFetchWorker: <${s}>` }),
)),
(u = null))
: y(I) ||
(yield t(T, { worker: s, events: I }), yield n(isUpdateChatMessagesByWorker(s)))
} while (u !== M)
} catch (e) {
yield u(`runFetchWorker <${s}>`, e)
} finally {
a?.cancel()
}
}))
}
const b = A({ roomId: s })
try {
for (;;) {
const r = yield n([I, p, g]),
i = yield l(w)
if (I.match(r)) M = r.payload
else if (p.match(r)) {
const e = r.payload
;(e && (M = e), q())
} else if (g.match(r)) {
if (!Array.isArray(r.payload) || !r.payload.length) continue
const e = d(r.payload),
o = m(r.payload)
if (!v(i, e?.seq) || !v(i, o?.seq)) continue
if (B[R.INITIAL]?.isRunning() || x(i)) continue
yield t(T, { worker: R.SUB, events: r.payload })
continue
}
if (!$(M)) {
M && (yield u("chatCoreEventLoader", `invalid query ${JSON.stringify(M)}`), (M = null))
continue
}
if (L(M) > 3 * O) {
const e = `loader: huge query ${JSON.stringify(M)}`
yield t(f({ message: e, stack: "chatCoreEventLoader" }))
}
const c = { gte: i.top, lte: i.bottom },
A = !k(M, c)
;(A && q(),
(A || p.match(r)) &&
(B[R.INITIAL] = yield a(function* () {
let a = null
try {
const r = C()
a = yield o(fetchCtrl, { name: R.INITIAL, ctxRef: r })
const i = M,
d = yield l(h)
if (d <= 0) throw new Error("chat loader: count is not available")
const m = yield e(b.fetch[R.INITIAL], { query: i, loaded: c, count: d, ctxRef: r })
if (m === N)
throw new Error(
`chat loader: initial messages FAIL roomId=${s} gte=${i?.gte} lte=${i?.lte} count=${d}`,
)
if (y(m))
throw new Error(
`chat loader: empty initial messages: length=${m?.length} roomId=${s} gte=${i?.gte} lte=${i?.lte} count=${d}`,
)
return (
yield t(T, { worker: R.INITIAL, events: m }),
yield n(isUpdateChatMessagesByWorker(R.INITIAL)),
!0
)
} catch (e) {
yield u("loader:fetchInitial", e)
} finally {
a?.cancel()
}
return !1
})),
yield W({ name: R.TOP, loader: b }),
yield W({ name: R.BOTTOM, loader: b }))
}
} finally {
q()
}
}