OverviewFilesCommitsIssuesDocsReleasesPeers

keet-deobfuscated / @holepunchto / keet-indexing / lib / reactions / index.js

115 lines · javascript ref:
const e = require("b4a"),
  { ReactionSchema: t } = require("@holepunchto/keet-core-schemas"),
  { AddReactionOperation: i, RemoveReactionOperation: s } = t.Operations,
  a = 32,
  n = 3,
  o = e.alloc(1)
function c(e, t, i) {
  const s = e.reactions.findIndex((e) => e.text === i)
  if (-1 !== s) {
    const i = e.reactions[s]
    ;((i.count += 1), i.latest.unshift(t), i.latest.length > 3 && i.latest.pop())
  } else e.reactions.push({ text: i, count: 1, latest: [t] })
  ;(e.reactions.length > a && e.reactions.pop(), e.reactions.sort())
}
function r(e, t, i) {
  const s = e.reactions.findIndex((e) => e.text === i)
  if (-1 === s) return
  const a = e.reactions[s]
  if (((a.count -= 1), a.count > 0)) {
    const e = a.latest.findIndex((e) => l(e, t))
    ;-1 !== e && a.latest.splice(e, 1)
  } else e.reactions.splice(s, 1)
  e.reactions.sort()
}
function h() {
  return { total: 0, reactions: [] }
}
function l(t, i) {
  return e.equals(t, i)
}
module.exports = class {
  static Operations = new Set([i.TYPE, s.TYPE])
  constructor(e) {
    ;((this.view = e),
      (this.chat = null),
      (this.members = null),
      (this.reactions = null),
      (this.reactionDigests = null),
      (this.reactionsByMember = null))
  }
  initialize() {
    ;((this.chat = this.view.chat),
      (this.members = this.view.members),
      (this.reactions = this.view.collections.reactions),
      (this.reactionDigests = this.view.indexes.reactionDigests),
      (this.reactionsByMember = this.view.indexes.reactionsByMember))
  }
  async _applyAddReactionOperation(e, { id: t }) {
    const { to: i, text: s } = e.value,
      [a, n, c] = await Promise.all([
        this.members.getMemberForDeviceKey(t.key),
        this.chat.getEventId(i),
        this.members.isDeviceMuted(t.key),
      ])
    !c && a && n && (await this.reactions.update([...n, a.key, s], o, { upsert: !0 }))
  }
  async _applyRemoveReactionOperation(e, { id: t }) {
    const { to: i, text: s } = e.value,
      [a, n, o] = await Promise.all([
        this.members.getMemberForDeviceKey(t.key),
        this.chat.getEventId(i),
        this.members.isDeviceMuted(t.key),
      ])
    o ||
      (a &&
        n &&
        a &&
        n &&
        (await this.reactions.get([...n, a.key, s])) &&
        (await this.reactions.delete([...n, a.key, s])))
  }
  async _indexReactionDigests(e, t, i) {
    const [s, a, n, o] = i,
      l = [s, a, n],
      u = [s, a],
      m = await this.reactionsByMember.get(l),
      d = m?.value,
      p = await this.reactionDigests.get(u),
      y = p ? p.value : h()
    ;(e && t) ||
      (e && (r(y, n, o), d && d.length <= 1 && (y.total -= 1)),
      t && (c(y, n, o), d || (y.total += 1)),
      y.total > 0 ? await this.reactionDigests.insert(u, y) : await this.reactionDigests.delete(u))
  }
  async _indexReactionsByMember(e, t, i) {
    const [s, a, n, o] = i,
      c = [s, a, n],
      r = await this.reactionsByMember.get(c),
      h = r?.value
    if (e && h) {
      const e = h.indexOf(o)
      ;-1 !== e &&
        (h.splice(e, 1),
        h.length > 0
          ? await this.reactionsByMember.insert(c, h)
          : await this.reactionsByMember.delete(c))
    }
    t &&
      (h
        ? -1 === h.indexOf(o) && (h.push(o), h.sort(), await this.reactionsByMember.insert(c, h))
        : await this.reactionsByMember.insert(c, [o]))
  }
  autobaseApply(e, t) {
    switch (e.type) {
      case i.TYPE:
        return this._applyAddReactionOperation(e, t)
      case s.TYPE:
        return this._applyRemoveReactionOperation(e, t)
    }
  }
  async autobaseIndex({ prev: e, next: t, id: i }) {
    ;(await this._indexReactionDigests(e, t, i), await this._indexReactionsByMember(e, t, i))
  }
}