const e = require("./registration"),
{ isMemberActive: t, getMemberForDeviceKey: a } = require("./query"),
{ KeetContractError: l } = require("./errors"),
{ addEvent: r } = require("./chat"),
{
contract: {
hyperschema: { getEnum: c },
},
} = require("../../../schema/spec"),
i = c("@keet/room-type")
async function s(e, { db: c, writer: i }) {
const s = i.key,
[y, m, o, d] = await Promise.all([
a(c, s),
c.get("@keet/calls", { callKey: e.callKey }),
c.get("@keet/devices", { key: s }),
c.findOne("@keet/active-calls-by-timestamp"),
])
if (!t(y)) throw l.INACTIVE_MEMBER()
if (m) throw l.CALL_KEY_EXISTS()
if (d) throw l.ACTIVE_CALL_EXISTS()
if (!o) throw l.ABORT()
if (
(await c.insert("@keet/calls", {
version: e.version,
callKey: e.callKey,
encryptionKey: e.encryptionKey,
discoveryKey: e.discoveryKey,
createdAt: e.header.timestamp,
}),
await c.insert("@keet/call-members", {
callKey: e.callKey,
memberKey: y.key,
createdAt: e.header.timestamp,
}),
await c.insert("@keet/call-devices", {
callKey: e.callKey,
deviceKey: o.key,
swarmKey: o.profile.swarmKey,
memberKey: y.key,
createdAt: e.header.timestamp,
}),
e.streams?.length)
)
for await (const t of e.streams)
await c.insert("@keet/call-streams", {
callKey: e.callKey,
deviceKey: o.key,
streamKey: t,
createdAt: e.header.timestamp,
})
await r(c, i, { callStarted: !0 }, e.header.timestamp)
}
async function y(e, { db: r, writer: c }) {
const i = e.callKey,
s = c.key,
[y, m, o] = await Promise.all([
a(r, s),
r.get("@keet/calls", { callKey: i }),
r.get("@keet/devices", { key: s }),
])
if (!t(y)) throw l.INACTIVE_MEMBER()
if (!m) throw l.CALL_NOT_FOUND()
if (m.endedAt) throw l.CALL_ENDED()
if (!o) throw l.ABORT()
const [d, K] = await Promise.all([
r.get("@keet/call-members", { callKey: e.callKey, memberKey: y.key }),
r.get("@keet/call-devices", { callKey: e.callKey, deviceKey: s }),
])
if (K) throw l.CALL_DEVICE_EXISTS()
if (
(await r.insert("@keet/call-devices", {
callKey: e.callKey,
deviceKey: o.key,
swarmKey: o.profile.swarmKey,
memberKey: y.key,
createdAt: e.header.timestamp,
}),
e.streams?.length)
)
for await (const t of e.streams)
await r.insert("@keet/call-streams", {
callKey: e.callKey,
deviceKey: o.key,
streamKey: t,
createdAt: e.header.timestamp,
})
d ||
(await r.insert("@keet/call-members", {
callKey: e.callKey,
memberKey: y.key,
createdAt: e.header.timestamp,
}))
}
async function m({ header: e, callKey: r }, { db: c, writer: s }) {
const y = s.key,
m = { gte: { callKey: r }, lte: { callKey: r } },
[o, d, K, n] = await Promise.all([
a(c, y),
c.get("@keet/calls", { callKey: r }),
c.find("@keet/call-members", m).toArray(),
c.get("@keet/system-digest"),
])
if (n.settings.roomType === i.DirectMessage) throw l.CALL_LEAVE_NOT_ALLOWED()
if (!t(o)) throw l.INACTIVE_MEMBER()
if (!d) throw l.CALL_NOT_FOUND()
const k = o.key,
w = { gte: { callKey: r, memberKey: k }, lte: { callKey: r, memberKey: k } },
f = { gte: { callKey: r, deviceKey: y }, lte: { callKey: r, deviceKey: y } },
[h, A, E, _] = await Promise.all([
c.get("@keet/call-members", { callKey: r, memberKey: k }),
c.get("@keet/call-devices", { callKey: r, deviceKey: y }),
c.find("@keet/call-devices-by-member-key", w).toArray(),
c.find("@keet/call-streams-by-device-key", f).toArray(),
])
if (!h) throw l.CALL_MEMBER_NOT_FOUND()
if (!A) throw l.CALL_DEVICE_NOT_FOUND()
const L = []
L.push(c.delete("@keet/call-devices", A))
for (const e of _) L.push(c.delete("@keet/call-streams", e))
return (
E.length > 1 ||
(L.push(c.delete("@keet/call-members", h)),
1 === K.length && ((d.endedAt = e.timestamp), L.push(c.insert("@keet/calls", d)))),
Promise.all(L)
)
}
async function o({ header: e, callKey: c }, { db: s, writer: y }) {
const m = y.key,
[o, d, K, n] = await Promise.all([
a(s, m),
s.get("@keet/calls", { callKey: c }),
s.get("@keet/call-devices", { callKey: c, deviceKey: m }),
s.get("@keet/system-digest"),
])
if (!t(o)) throw l.INACTIVE_MEMBER()
if (!d) throw l.CALL_NOT_FOUND()
if (d.endedAt) throw l.CALL_ENDED()
if (!K) throw l.CALL_DEVICE_NOT_FOUND()
;((d.endedAt = e.timestamp), await s.insert("@keet/calls", d))
const k = { gte: { callKey: c }, lte: { callKey: c } },
[w, f, h] = await Promise.all([
s.find("@keet/call-members", k).toArray(),
s.find("@keet/call-devices", k).toArray(),
s.find("@keet/call-streams", k).toArray(),
]),
A = []
for (const e of w) A.push(s.delete("@keet/call-members", e))
for (const e of f) A.push(s.delete("@keet/call-devices", e))
for (const e of h) A.push(s.delete("@keet/call-streams", e))
if ((await Promise.all(A), n.settings.roomType === i.DirectMessage))
return w.length > 1
? await r(s, y, { callHangup: !0 }, e.timestamp)
: void (await r(s, y, { callMissed: !0 }, e.timestamp))
}
async function d({ header: e, callKey: r, streamKey: c }, { db: i, writer: s }) {
const y = s.key,
[m, o, d, K] = await Promise.all([
a(i, y),
i.get("@keet/calls", { callKey: r }),
i.get("@keet/call-devices", { callKey: r, deviceKey: y }),
i.get("@keet/call-streams", { callKey: r, streamKey: c }),
])
if (!t(m)) throw l.INACTIVE_MEMBER()
if (!o) throw l.CALL_NOT_FOUND()
if (o.endedAt) throw l.CALL_ENDED()
if (!d) throw l.CALL_DEVICE_NOT_FOUND()
if (K) throw l.CALL_STREAM_EXISTS()
await i.insert("@keet/call-streams", {
callKey: r,
deviceKey: d.deviceKey,
streamKey: c,
createdAt: e.timestamp,
})
}
async function K({ callKey: e, streamKey: r }, { db: c, writer: i }) {
const s = i.key,
[y, m, o, d] = await Promise.all([
a(c, s),
c.get("@keet/calls", { callKey: e }),
c.get("@keet/call-devices", { callKey: e, deviceKey: s }),
c.get("@keet/call-streams", { callKey: e, streamKey: r }),
])
if (!t(y)) throw l.INACTIVE_MEMBER()
if (!m) throw l.CALL_NOT_FOUND()
if (m.endedAt) throw l.CALL_ENDED()
if (!o) throw l.CALL_DEVICE_NOT_FOUND()
if (!d) throw l.CALL_STREAM_NOT_FOUND()
await c.delete("@keet/call-streams", d)
}
function n(e) {
;(e.add("@keet/start-call", s),
e.add("@keet/join-call", y),
e.add("@keet/leave-call", m),
e.add("@keet/end-call", o),
e.add("@keet/add-call-stream", d),
e.add("@keet/remove-call-stream", K))
}
module.exports = { [e]: n }