OverviewFilesCommitsIssuesDocsReleasesPeers

keet-cli / keet-core-4.14.4-pretty / lib / core / tasks / pairing / invitation.js

209 lines · javascript ref:
const i = require("b4a"),
  t = require("safety-catch"),
  e = require("signal-promise"),
  { Task: s } = require("../task"),
  {
    getInvitationId: a,
    generatePairingCapabilities: o,
    generateRoomPairingName: n,
    createInvitationJoinOperation: r,
  } = require("../../invitations")
module.exports = class extends s {
  constructor(i) {
    super(i)
    const t = this.description.joinRoomInvitation
    ;((this._invitation = t.invitation),
      (this._initiator = t.invitation.initiator),
      (this._inviter = t.invitation.inviter),
      (this._identity = t.invitation.identity),
      (this._mailboxPublicKey = t.invitation.mailbox),
      (this._responseKeyPair = t.invitation.responseKeyPair),
      (this._invitationSeed = this._invitation.invitationSeed),
      (this._capabilities = o(this._mailboxPublicKey)),
      (this._invitationId = a(this._invitationSeed)),
      (this._roomInfo = null),
      (this._sharedRoomInfo = null),
      (this._writerInfo = null),
      (this._identityInfo = null),
      (this._privateProfileInfo = null),
      (this._room = null),
      (this._core = null),
      (this._responseCore = null),
      (this._wakeupSession = null),
      (this._privateProfile = null),
      (this._signal = null),
      (this._watcher = null))
  }
  async _close() {
    ;(this._signal &&
      this._signal.notify(new Error("Invitation join task closed before resolving")),
      this._watcher && this._privateProfile.db.unwatch(this._watcher),
      this._wakeupSession &&
        (this.swarmWorker.stopActiveSwarming(this._capabilities.swarmTopic),
        this._wakeupSession.destroy()),
      this._core && (await this._core.close()),
      this._responseCore && (await this._responseCore.close()),
      this._room && this.keet.internalReleaseRoom(this._room),
      this._privateProfile && this.keet.internalReleaseRoom(this._privateProfile))
  }
  _samePendingInvitation(t) {
    return (
      i.equals(t.id, this._invitationId) &&
      i.equals(t.responseKeyPair.publicKey, this._responseKeyPair.publicKey)
    )
  }
  async _appendJoinRequest() {
    const i = { key: this._core.key, responsePublicKey: this._responseKeyPair.publicKey }
    if (await this.local.get("@local/writer-appends", i)) return
    const t = { identity: this._identityInfo, privateProfile: this._privateProfileInfo },
      e = {
        device: this.keet.internalCreateDeviceUpdate(t, this._core.key, {
          isPrivateProfile: !!this._identity,
          buildType: this._invitation.buildType,
        }),
        member: this.keet.internalGetMemberUpdate(t),
      }
    let s = null
    this._identity && (s = { devicePublicKey: this._identity.devicePublicKey })
    const a = this.keet.internalGetHeads(this._inviter, this._room),
      o = r(
        this._core.key,
        this._mailboxPublicKey,
        this._responseKeyPair,
        this._invitationSeed,
        e,
        { identity: s, heads: a },
      )
    if ((await this.keet.internalAppendOptimisticOperation(this._core.key, o), this.closing)) return
    const n = await this.keet.internalEnterLocalTransaction()
    try {
      ;(await n.insert("@local/writer-appends", i), await n.flush())
    } finally {
      await this.keet.internalExitLocalTransaction()
    }
  }
  async _waitForResponse() {
    ;((this._responseCore = this.store.get({ keyPair: this._responseKeyPair, writable: !1 })),
      await this._responseCore.ready())
    const i = this._privateProfileInfo.capabilities.mailboxKeyPair.publicKey
    if (
      (this.keet.blindPeering.addCoreBackground(this._responseCore, {
        target: i,
        referrer: i,
        priority: 1,
      }),
      this.closing)
    )
      return
    const t = (i) => {
      this._wakeupSession.announce(i, [{ key: this._core.key, length: this._core.length }])
    }
    this._wakeupSession = this.keet.protomuxWakeup.session(this._mailboxPublicKey, {
      discoveryKey: this._capabilities.wakeupTopic,
      onpeeractive: t,
    })
    for (const i of this._wakeupSession.peers) i.active && t(i)
    ;(this.swarmWorker.startActiveSwarming(this._capabilities.swarmTopic),
      this.keet.discovery && this.keet.discovery.announce(this._capabilities.discoveryKeyPair))
    try {
      await this._responseCore.get(0)
    } catch (i) {
      if (this.closing) return
      throw i
    }
    this.closing ||
      (this.swarmWorker.stopActiveSwarming(this._capabilities.swarmTopic),
      this.keet.discovery &&
        this.keet.discovery.subscribe(this._capabilities.discoveryKeyPair.publicKey, {
          since: Date.now(),
        }),
      await this._responseCore.close(),
      this.closing ||
        this._privateProfile.base.hintWakeup([{ key: this._responseCore.key, length: 1 }]))
  }
  async _append() {
    const i = await this.keet.store.createKeyPair(n(this._responseKeyPair.publicKey)),
      t = await this.keet.internalEnterLocalTransaction()
    try {
      ;((this._writerInfo = {
        keyPair: i,
        key: this._core.key,
        mailbox: this._mailboxPublicKey,
        responseKeyPair: this._responseKeyPair,
      }),
        await t.insert("@local/writers", this._writerInfo),
        await t.flush())
    } finally {
      await this.keet.internalExitLocalTransaction()
    }
    await this._appendJoinRequest()
  }
  async _run() {
    if (this.closing) return
    this.keet.onlineBoot.opened || (await this.keet.onlineBoot.ready())
    const [i, s] = await Promise.all([
        this.local.get("@local/writers", { mailbox: this._mailboxPublicKey }),
        this.local.get("@local/identity"),
      ]),
      [a, o] = await Promise.all([
        this.local.get("@local/rooms", { roomKey: s.privateProfileKey }),
        this.local.get("@local/rooms-by-mailbox", {
          capabilities: { mailboxKeyPair: { publicKey: this._mailboxPublicKey } },
        }),
      ])
    if (this.closing) return
    if (
      ((this._roomInfo = o),
      (this._writerInfo = i),
      (this._identityInfo = s),
      (this._privateProfileInfo = a),
      (this._privateProfile = this.keet.internalOpenExistingRoom(
        this._identityInfo.privateProfileKey,
      )),
      await this._privateProfile.ready(),
      this.closing)
    )
      return
    if (
      ((this._room = this._roomInfo
        ? this.keet.internalOpenExistingRoom(this._roomInfo.roomKey)
        : null),
      this._room && (await this._room.ready(), this.closing))
    )
      return
    const n = await this._privateProfile.db.get("@keet-private-id/pending-invitations", {
      id: this._invitationId,
    })
    !this.closing &&
      n &&
      this._samePendingInvitation(n) &&
      ((this._core = this.store.get({ key: this._initiator.key })),
      await this._core.ready(),
      this.closing ||
        (this._core.writable &&
          (await this._append(),
          this._room && (await this._room.base.setLocal(this._core.key), this.closing))) ||
        (this.keet.emit("pending-rooms-changed"),
        this.keet.blindPeering.addCoreBackground(this._core, {
          target: this._mailboxPublicKey,
          referrer: this._mailboxPublicKey,
          priority: 1,
        }),
        this._waitForResponse().catch(this.keet.onerror),
        (this._signal = new e()),
        (this._watcher = async () => {
          try {
            const i = await this._privateProfile.db.get("@keet-private-id/pending-invitations", {
              id: this._invitationId,
            })
            ;(i && this._samePendingInvitation(i)) || this._signal.notify()
          } catch (i) {
            t(i)
          }
        }),
        this._privateProfile.db.watch(this._watcher),
        this._watcher(),
        await this._signal.wait()))
  }
}