OverviewFilesCommitsIssuesDocsReleasesPeers

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

139 lines · javascript ref:
const { Transform: e, pipeline: t } = require("streamx"),
  i = require("compact-encoding"),
  a = require("b4a"),
  { ConfigSchema: s } = require("@holepunchto/keet-core-schemas"),
  { UpdateConfigOperationV1: n, UpdateConfigOperationV2: o } = s.Operations,
  {
    CONFIG: r,
    VALIDATION: c,
    FEATURES: h,
    GENERIC_EVENTS: u,
    isFeatureSupported: E,
  } = require("@holepunchto/keet-core-api")
module.exports = class {
  static Operations = new Set([n.TYPE, o.TYPE])
  constructor(e) {
    ;((this.view = e),
      (this.chat = null),
      (this.members = null),
      (this.config = null),
      (this.configV2 = null))
  }
  initialize() {
    ;((this.chat = this.view.chat),
      (this.members = this.view.members),
      (this.chat = this.view.chat),
      (this.config = this.view.collections.config),
      (this.configV2 = this.view.bee))
  }
  async get(e) {
    const t = await this.configV2.get(e, s.Encoding)
    return s.getValue(t)
  }
  async getAll(e = {}) {
    const t = {}
    for await (const { key: i, value: a } of this.createReadStream(e)) t[i] = a
    return t
  }
  async put(e, t) {
    await this.configV2.put(e, t, s.Encoding)
  }
  createReadStream(i = {}) {
    const a = this.configV2.createReadStream(i, s.Encoding)
    return t(
      a,
      new e({
        transform(e, t) {
          t(null, { key: e.key, value: s.getValue(e) })
        },
      }),
    )
  }
  async getConfig() {
    const e = await this.config.get(r.V1_CONFIG_KEY)
    return { ...(e ? e.value : {}), ...(await this.getAll()) }
  }
  async isBroadcastRoom() {
    const e = await this.getConfig()
    return !!e && "1" === e.roomType
  }
  async isDisableMembershipEvents() {
    return 1 === (await this.get(r.DISABLE_MEMBERSHIP_EVENTS))
  }
  async deletePinnedMessageIfExists(e) {
    const t = (await this.get(r.PINNED_MESSAGES)) || [],
      i = t.findIndex((t) => a.equals(t.key, e.key) && t.seq === e.seq)
    ;-1 !== i &&
      (t.splice(i, 1), await this.put(r.PINNED_MESSAGES, s.encodeValue(r.PINNED_MESSAGES, t)))
  }
  async _validate(e, t) {
    const i = s.decodeValue(e, t)
    switch (e) {
      case r.PINNED_MESSAGES:
        return (
          !(await this.view.isUnsupportedFeature(h.PINNED_MESSAGES)) &&
          (
            await Promise.all([this._pinLimitNotExceeded(e, i), this._pinnedMessageExists(e, i)])
          ).every((e) => !0 === e)
        )
      case r.DISABLE_MEMBERSHIP_EVENTS:
        return await this.view.isFeatureSupported(h.DISABLE_MEMBERSHIP_EVENTS)
      default:
        return !0
    }
  }
  _pinLimitNotExceeded(e, t) {
    return t.length <= c.PINNED_MESSAGES_LIMIT
  }
  async _pinnedMessageExists(e, t) {
    const i = t.length ? t[t.length - 1] : null
    return !i || (await this.chat.messageExists(i))
  }
  async _maybeTrackChange({ id: e, timestamp: t, from: i, to: a }) {
    ;(await this.view.isFeatureSupported(h.ROOM_RENAME_EVENT)) &&
      null !== i &&
      i !== a &&
      (await this.chat.addMessage({
        id: e,
        timestamp: t,
        event: { type: u.ROOM_TITLE_CHANGED, value: { from: i, to: a } },
      }))
  }
  async _applyUpdateConfigOperationV1(e, { id: t }) {
    const { key: a, value: s } = e.value
    if (!(await this.members.isModerator(t.key))) return
    const n = await this.view.internal.getCodeVersion()
    if (E(n, h.V2_CONFIG)) return this.put(a, i.encode(i.string, s))
    const o = await this.getConfig()
    ;(s ? (o[a] = s) : delete o[a], await this.config.update(r.V1_CONFIG_KEY, o, { upsert: !0 }))
  }
  async _applyUpdateConfigOperationV2(e, t) {
    const { id: i } = t,
      { key: a, value: n } = e.value
    if ((await this.members.isModerator(i.key)) && (await this._validate(a, n))) {
      if (a === r.ROOM_TITLE) {
        const e = await this.get(a),
          i = s.decodeValue(a, n)
        await this._maybeTrackChange({ ...t, from: e, to: i })
      }
      await this.put(a, n)
    }
  }
  autobaseApply(e, t) {
    switch (e.type) {
      case n.TYPE:
        return this._applyUpdateConfigOperationV1(e, t)
      case o.TYPE:
        return this._applyUpdateConfigOperationV2(e, t)
    }
  }
  async migrate() {
    const e = await this.config.get(r.V1_CONFIG_KEY)
    if (e && e.value)
      for await (const t of Object.keys(e.value)) {
        const a = e.value[t]
        await this.put(t, i.encode(i.string, a))
      }
  }
}