const e = require("hypercore-id-encoding"),
l = require("hypercore-storage"),
t = require("multi-profile-store"),
a = require("@holepunchto/keet-push/lib/notifications.js"),
{ decodeValue: o } = require("autobase/lib/values.js"),
n = require("b4a"),
{
contract: {
hyperdispatch: { decode: i },
hyperschema: { getEnum: r },
},
} = require("../../schema/spec"),
c = r("@keet/room-type"),
s = require("../core/local"),
u = require("keet-identity-key"),
{ ProofEncoding: d } = require("keet-identity-key/lib/encoding"),
m = require("compact-encoding")
function y(e) {
return "@keet/start-call" === e.name
? "call"
: "@keet/join-call" === e.name
? "call_joined"
: "@keet/end-call" === e.name || "@keet/leave-call" === e.name
? "call_hangup"
: void 0
}
function f(e) {
return "@keet/start-call" === e.name
? "Message for call"
: "@keet/join-call" === e.name
? "Message for call joined"
: "@keet/end-call" === e.name || "@keet/leave-call" === e.name
? "Message for call hangup"
: void 0
}
function p(e, l) {
switch (e) {
case c.Default:
return (l("Room type is default"), "0")
case c.Broadcast:
return (l("Room type is Broadcast"), "1")
case c.DirectMessage:
return (l("Room type is DirectMessage"), "2")
default:
throw new Error("Incompatible legacy room type:", e)
}
}
function g(e, l, t) {
try {
return !!u.verify(e, l, { expectedIdentity: t })
} catch {
return !1
}
}
module.exports = async function (r, c, { log: u = () => {}, profile: k = !0 } = {}) {
const h = t.open(r).active()
if (!h && k) return (u("no active profile is made"), null)
const { version: v, discoveryKey: b, proof: x } = a.decode(c),
K = new l(h ? h.storage : r, {
readOnly: !0,
blockCache: !1,
tableCacheIndexAndFilterBlocks: !1,
optimizeFiltersForMemory: !0,
maxOpenFiles: 1,
useDirectReads: !0,
filterPolicy: null,
})
try {
const l = s.rocks(K.rocks.columnFamily("keet/local-database"))
;(await l.ready(), u("Keet local database is ready"))
const [t, r] = await Promise.all([
l.get("@local/rooms-by-discovery-key", { discoveryKey: b }),
l.get("@local/identity"),
])
if (!t || t.status.isRemoved) return (u("Room member was removed from room"), null)
const c = await l.get("@local/room-preferences", { roomKey: t.roomKey })
if (c && (!c.status.isActive || c.status.isFullyMuted)) return null
const k = await a.receive(K, t.roomKey, x, v),
h = 1 === v ? k?.result : k,
w = 1 === v ? k?.attest : null,
M = w ? m.decode(d, w) : null
if ((u("Receiving notification"), !h)) return null
if ((u("Notification is good"), !h.block)) return null
if ((u("Notification was not blocked"), !h.newer)) return null
const q = h.key,
T = h.discoveryKey,
I = o(n.from(h.proof.block.value), {
autobase: t.roomKey,
encryptionKey: t.encryptionKey,
key: q,
manifest: h.proof.manifest,
index: h.block.index,
}),
[R, j] = await Promise.all([l.get("@local/devices", { device: { key: q } }), I]),
D = R?.device,
F = i(j),
B = M?.identity || D?.memberKey,
[P, A] = await Promise.all([
B ? l.get("@local/contacts", { memberKey: B }) : null,
B ? l.get("@local/members", { key: B }) : null,
]),
E = !!P?.status.isBlocked
u("Blocked?: ", E)
const S = w ? g(w, q, r.publicKey) : A && n.equals(A.key, r.publicKey)
u(
`Member exists ?: ${null !== A} and keys are equal?: ${null !== A && n.equals(A.key, r.publicKey)}`,
)
const N = A ? A.profile.displayName : null,
_ = A ? A.profile.avatar : null,
C = t ? t.config.avatar : null,
O = t ? t.digest.abi.version : 0
let $ = null
switch (F.name) {
case "@keet/add-chat-message": {
const l = F.value.header.timestamp,
a = F.value.message
if (a?.files && a.files.length > 0) {
const e = a.files[0]
;(($ = {
timestamp: l,
type: "file",
chatText: null,
callId: null,
fileType: e.metadata?.mimetype,
location: null,
}),
u("Message for file"))
} else if (a?.event?.locationShared)
(($ = {
timestamp: l,
type: "location",
chatText: a.text,
callId: null,
fileType: null,
location: a.event.locationShared,
}),
u("Message for location"))
else if (a.text)
(($ = {
timestamp: l,
type: "text",
chatText: a.text,
callId: null,
fileType: null,
location: null,
}),
u("Message for text"))
else if (a.event.callStarted && O < 23) {
if (Math.abs(Date.now() - l) > 12e4) return
;(($ = {
timestamp: l,
type: "call",
chatText: null,
callId: e.encode(t.discoveryKey),
fileType: null,
location: null,
}),
u("Message for call"))
} else if (a.event.callHangup && O < 23) {
if (Math.abs(Date.now() - l) > 12e4) return
;(($ = {
timestamp: l,
type: "call_hangup",
chatText: null,
callId: e.encode(t.discoveryKey),
fileType: null,
location: null,
}),
u("Message for call hangup"))
}
break
}
case "@keet/start-call":
case "@keet/join-call":
case "@keet/leave-call":
case "@keet/end-call": {
if (O < 23) return
const l = F.value.header.timestamp
if (Math.abs(Date.now() - l) > 12e4) return
const t = y(F),
a = f(F)
;(($ = {
timestamp: l,
type: t,
chatText: null,
callId: e.encode(F.value.callKey),
fileType: null,
location: null,
}),
u(a))
break
}
}
const z = {
id: null,
sender: { id: e.encode(q), length: h.length, blocked: E, self: S, name: N, memberAvatar: _ },
room: {
key: t.roomKey,
title: t.config.title,
type: p(t.digest.settings.roomType, u),
roomAvatar: C,
},
proof: { discoveryKey: T, data: h.proof },
index: h.block.index,
message: $,
}
return (
(z.id = z.sender.id + (-1 !== z.index ? "/b" + z.index : "/l" + z.sender.length)),
u("Returning result"),
z
)
} catch (e) {
return (u("Error:", e), null)
} finally {
;(await K.close(), u("Storage closed"))
}
}