const e = require("b4a"),
{ KeetContractError: i } = require("./errors"),
{ fileStats: r } = require("./stats"),
n = 524288
async function t(r, t, l) {
if (!t && !l) return
if (!g(l)) return
if (
(l.preview && (l.preview = null),
!l.pointer.inlined && l.pointer.blob && (l.pointer.blob = null),
!l || !l.pointer.inlined)
)
return t || l
if (t && t.hash && l.hash && e.equals(t.hash, l.hash)) return { ...l, pointer: t.pointer }
if (l.pointer.inlined.byteLength > n)
throw i.INLINED_FILESIZE_TOO_LARGE("Cannot inline a blob that is larger than 512 KB")
const a = await r.put(l.pointer.inlined)
return { ...l, pointer: { blob: a } }
}
async function l(e, i, r) {
return {
small: await t(e, i?.small, r?.small),
medium: await t(e, i?.medium, r?.medium),
large: await t(e, i?.large, r?.large),
}
}
async function a(e, i, r) {
return await l(e, i, r)
}
async function s(e, i) {
return o(e, i)
}
async function o(e, i) {
i && (await Promise.all([p(e, i.small), p(e, i.medium), p(e, i.large)]))
}
async function p(e, i) {
if (!i) return
if (!i.pointer.blob) return
const r = await e.get(i.pointer.blob)
i.pointer = { inlined: r }
}
async function f({ primaryThread: e, id: i, blobs: n, db: t, oplog: a, file: s }) {
;(s.preview && (s.preview = await l(n, null, s.preview)),
s.pointer.inlined && (s.pointer.inlined = null),
s.pointer.blob && (s.pointer.blob = null))
const o = { id: i, oplog: a, status: { isDeleted: !1 }, file: s }
return (await t.insert("@keet/files", o), await r(t, e, o), i)
}
async function u({ primaryThread: e, files: r, id: n, blobs: t, db: l, oplog: a }) {
if (!r || r.length < 1) return []
if (!v(r)) throw i.FILE_RECORD_INVALID()
const s = []
for (const i of r)
s.push(await f({ primaryThread: e, id: n++, blobs: t, db: l, oplog: a, file: i }))
return s
}
async function d({ primaryThread: e, clock: i, message: r, blobs: n, db: t, oplog: l }) {
const a = r.files || [],
s = await u({ primaryThread: e, files: a, id: i, blobs: n, db: t, oplog: l })
return (
await b({ primaryThread: e, clock: i + a.length, message: r, blobs: n, db: t, oplog: l }),
s
)
}
async function b({ primaryThread: e, clock: i, message: r, blobs: n, db: t, oplog: l }) {
let a = 0
const s = r?.display?.httpLink || []
for (const r of s)
(r.preview?.files && (r.preview.files = []),
r.preview?.file &&
((r.preview.files = await u({
primaryThread: e,
id: i + a,
files: [r.preview.file],
blobs: n,
db: t,
oplog: l,
})),
(a += r.preview.files.length)))
const o = r?.display?.pearLink || []
for (const r of o)
(r.preview?.files && (r.preview.files = []),
r.preview?.file &&
((r.preview.files = await u({
primaryThread: e,
id: i + a,
files: [r.preview.file],
blobs: n,
db: t,
oplog: l,
})),
(a += r.preview.files.length)))
}
async function c({ primaryThread: e, message: i, db: r, blobs: n }) {
const t = i.message?.files || [],
l = i.message?.display?.httpLink || []
for (const { preview: e } of l) e && e.files && e.files.length && t.push(...e.files)
const a = i.message?.display?.pearLink || []
for (const { preview: e } of a) e && e.files && e.files.length && t.push(...e.files)
await w({ primaryThread: e, files: t, db: r, blobs: n })
}
async function w({ primaryThread: e, files: i, db: n, blobs: t }) {
if (!i || !i.length) return
const l = await Promise.all(i.map((e) => n.get("@keet/files", { id: e }))),
a = []
for (const i of l)
((i.status.isDeleted = !0), a.push(n.insert("@keet/files", i)), a.push(r(n, e, i, i)))
await Promise.all(a)
}
function m(i, r) {
return (
(!i && !r) ||
(!(!i && r) &&
!(i && !r) &&
(i.hash && r.hash
? e.equals(i.hash, r.hash)
: e.equals(i.pointer.inlined, r.pointer.inlined)))
)
}
function h(e, i) {
const r = m(e?.small, i?.small),
n = m(e?.medium, i?.medium),
t = m(e?.large, i?.large)
return r && n && t
}
function g(e) {
return (
e.preview &&
(e.preview?.small?.preview && (e.preview.small.preview = null),
e.preview?.medium?.preview && (e.preview.medium.preview = null),
e.preview?.large?.preview && (e.preview.large.preview = null)),
!(
(e.pointer.externalDrive && !e.pointer.externalDrive.path) ||
(e.pointer.externalDrive && e.pointer.externalBlob)
)
)
}
function v(e) {
const i = Array.isArray(e) ? e : [e]
for (const e of i) if (!g(e)) return !1
return !0
}
module.exports = {
isSameAvatar: h,
updateAvatar: a,
updateImageFile: l,
restoreAvatar: s,
restoreFile: o,
insertMessageFiles: d,
deleteMessageFiles: c,
MAX_INLINED_FILE_SIZE: n,
}