import { createAction as e } from "@reduxjs/toolkit"
import { eventChannel as o, END as r } from "redux-saga"
import { take as t, fork as n, cancel as a, cancelled as l } from "redux-saga/effects"
export const channelEmptyData = e("channel/empty-data")
export const channelError = e("channel/error")
const s = { START: "SUB_START", END: "SUB_END", DATA: "SUB_DATA", ERROR: "SUB_ERROR" }
export function channelFromEventEmmitter(e, r) {
return o((o) => {
const t = (...e) => {
e.length < 1 ? o(channelEmptyData()) : o(...e)
}
return (
e.on(r, t),
e.on("error", () => {}),
() => {
e.off(r, t)
}
)
})
}
export function channelFromReadable(e, { onError: t } = {}) {
return o(
(o) => (
e.on("error", (e) => {
t && t(e)
}),
e.on("close", () => {
o(r)
}),
e.on("data", (...e) => {
e.length < 1 ? o(channelEmptyData()) : o(...e)
}),
() => {
e.destroy()
}
),
)
}
export function channelFromMessages(e, r) {
return o((o) => {
const t = e(r, (e) => {
o(e || channelEmptyData())
})
return () => {
t.destroy()
}
})
}
let i = null
export const setApiSubscriptionLifecycleMethods = (e) => {
i = e
}
export function* apiTakeMatch(e, { matchFn: o = (e) => !!e, onError: r } = {}) {
const [n, ...a] = e
let l = null,
c = null
const m = Date.now(),
p = (e) => {
c = e
}
try {
const e = n(...a)
if (!e)
return (
i?.onError?.({ method: n, startTime: m, error: "no subscription", logType: s.ERROR }),
r ? r(new Error("apiTakeMatch: no subscription")) : null
)
for (
l = channelFromReadable(e, { onError: p }),
i?.onStart?.({ method: n, startTime: m, args: a, logType: s.START });
;
) {
const e = yield t(l)
if (o(e))
return (
i?.onData?.({
method: n,
args: a,
startTime: m,
dataTime: Date.now(),
response: e,
logType: s.DATA,
}),
e
)
}
} finally {
;(i?.onEnd?.({ method: n, startTime: m, endTime: Date.now(), logType: s.END }),
l?.close(),
c && r && (yield r(c)))
}
}
export function* apiSubscribeSaga(e, o, { onError: r, onCleanup: n, params: a } = {}) {
const [c, ...m] = e
let p = null,
T = null
const d = Date.now(),
y = (e) => {
T = e
},
u = Array.isArray(a) ? a : []
let h = 0
try {
for (
p = channelFromReadable(c(...m), { onError: y }),
i?.onStart?.({ method: c, args: m, startTime: d, logType: s.START });
;
) {
const e = yield t(p)
;((h += 1),
i?.onData?.({
method: c,
args: m,
startTime: d,
response: e,
dataTime: Date.now(),
counter: h,
logType: s.DATA,
}),
yield o(...u.concat([e])))
}
} catch (e) {
;(i?.onError?.({ method: c, startTime: d, error: e, logType: s.ERROR }),
r ? yield r(e) : console.error(e))
} finally {
if (
(i?.onEnd?.({ method: c, startTime: d, endTime: Date.now(), logType: s.END }),
p?.close(),
T && r && (yield r(T)),
n)
) {
const e = yield l()
yield n({ apiClose: !e })
}
}
}
export const apiTakeEvery = (e, o, r) => n(apiSubscribeSaga, e, o, r)
export function* apiSubscribeLatest(e, o, { onError: r, onCleanup: c, params: m } = {}) {
const [p, ...T] = e
let d = null,
y = null,
u = null
const h = Date.now(),
E = (e) => {
u = e
},
D = Array.isArray(m) ? m : []
let g = 0
try {
for (
y = channelFromReadable(p(...T), { onError: E }),
i?.onStart?.({ method: p, args: T, startTime: h, logType: s.START });
;
) {
const e = yield t(y)
;((g += 1),
i?.onData?.({
method: p,
args: T,
startTime: h,
response: e,
dataTime: Date.now(),
counter: g,
logType: s.DATA,
}),
d && (yield a(d)),
(d = yield n(o, ...D.concat([e]))))
}
} catch (e) {
;(i?.onError?.({ method: p, startTime: h, error: u, logType: s.ERROR }),
r ? yield r(e) : console.error(e))
} finally {
if (
(i?.onEnd?.({ method: p, startTime: h, endTime: Date.now(), logType: s.END }),
d?.cancel(),
y?.close(),
u && r && (yield r(u)),
c)
) {
const e = yield l()
yield c({ apiClose: !e })
}
}
}
export const apiTakeLatest = (e, o, ...r) => n(apiSubscribeLatest, e, o, { params: r })