OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-vdrive / lib / passthrough.cjs

76 lines · javascript ref:
// T2 — pass-through wrapper around hypercore-storage.
//
// Core takes its per-core storage from exactly two calls (hypercore/lib/core.js):
//   :162  await this.db.resumeCore(discoveryKey)
//   :232  await this.db.createCore({...})
// so subclassing CorestoreStorage and wrapping those two return values puts us
// under every block read/write without touching anything above.
//
// Objects that construct more of themselves (snapshot/atomize) must be re-wrapped,
// and read()/write() must return wrapped RX/TX — that is where T3 will redirect
// getBlock/putBlock. Here everything is pure delegation.

const CorestoreStorage = require('hypercore-storage')

const stats = { getBlock: 0, putBlock: 0, read: 0, write: 0, wrapped: 0 }

function delegate (target, overrides) {
  return new Proxy(target, {
    get (t, prop) {
      if (prop === '__unwrapped') return t
      if (overrides && prop in overrides) return overrides[prop]
      // NB: no receiver — getters must run with `this` bound to the real object
      const v = Reflect.get(t, prop)
      return typeof v === 'function' ? v.bind(t) : v
    },
    set (t, prop, value) {
      t[prop] = value
      return true
    }
  })
}

function wrapRX (rx) {
  stats.read++
  return delegate(rx, {
    getBlock (index) {
      stats.getBlock++
      return rx.getBlock(index)
    }
  })
}

function wrapTX (tx) {
  stats.write++
  return delegate(tx, {
    putBlock (index, data) {
      stats.putBlock++
      return tx.putBlock(index, data)
    }
  })
}

function wrapCoreStorage (inner) {
  if (!inner) return inner
  stats.wrapped++
  const overrides = {
    read: (...args) => wrapRX(inner.read(...args)),
    write: (...args) => wrapTX(inner.write(...args)),
    snapshot: (...args) => wrapCoreStorage(inner.snapshot(...args)),
    atomize: (...args) => wrapCoreStorage(inner.atomize(...args))
  }
  return delegate(inner, overrides)
}

class WrappedCorestoreStorage extends CorestoreStorage {
  async resumeCore (discoveryKey) {
    return wrapCoreStorage(await super.resumeCore(discoveryKey))
  }

  async createCore (data) {
    return wrapCoreStorage(await super.createCore(data))
  }
}

module.exports = { WrappedCorestoreStorage, stats }