OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-proto-peer / scripts / upload-avatar.mjs

52 lines · javascript ref:
// Upload wj62's avatar to the peer's BlobStore (device control surface, writer-gated), then read it
// back via get-blob (membrane surface) to prove the peer blob path end-to-end BEFORE the bridge.
//   bare scripts/upload-avatar.mjs /home/fleeky/Downloads/Internet_dog.jpg [origin|device]
import '../lib/bare-globals.js'
import Hyperswarm from 'hyperswarm'
import crypto from 'hypercore-crypto'
import b4a from 'b4a'
import c from 'compact-encoding'
import ProtomuxRPC from 'protomux-rpc'
import fs from 'bare-fs'
import { cidForBlobSync } from 'atproto-repo/lib/cid.js'

const CONTROL = {
  origin: '8ae330710aaef922dce79a907f6ff8f57e459de61d4d45f1551d5e0ff23a11d7', // stortron
  device: 'e0cac0d06e67da9c79674a5ca195809300b04635d1a46254f4fd21edd1ce491d'  // tabertron
}
const WRITER_SEED = 'wj62-swarm-test-writer-2026-07-05'
const DEVICE_PROTOCOL = 'hyper-proto-peer/device/v1'
const MEMBRANE_PROTOCOL = 'hyper-proto-peer/rpc/v1'

const path = globalThis.Bare.argv[2]
const which = (globalThis.Bare.argv[3] || 'origin').toLowerCase()
if (!path) { console.log('usage: bare scripts/upload-avatar.mjs <image path> [origin|device]'); globalThis.Bare.exit(1) }
const ck = CONTROL[which]
const bytes = fs.readFileSync(path)
const mimeType = path.endsWith('.png') ? 'image/png' : 'image/jpeg'
const localCid = cidForBlobSync(b4a.from(bytes)).toString()
console.log('LOCAL file=' + path + ' size=' + bytes.length + ' mime=' + mimeType + ' cid=' + localCid)

const swarm = new Hyperswarm({ keyPair: crypto.keyPair(crypto.hash(b4a.from(WRITER_SEED))) })
const done = new Promise((res, rej) => {
  const to = setTimeout(() => rej(new Error('timeout')), 30000)
  swarm.on('connection', async conn => {
    if (b4a.toString(conn.remotePublicKey, 'hex') !== ck) return
    try {
      const dev = new ProtomuxRPC(conn, { protocol: DEVICE_PROTOCOL, valueEncoding: c.json })
      const up = await dev.request('upload-blob', { bytes: b4a.toString(bytes, 'hex'), mimeType })
      console.log('UPLOADED ' + JSON.stringify(up) + '  cidMatch=' + (up.cid === localCid))
      // read it back via the membrane surface (public get-blob) on the SAME connection
      const mem = new ProtomuxRPC(conn, { protocol: MEMBRANE_PROTOCOL, valueEncoding: c.json })
      const got = await mem.request('get-blob', { cid: up.cid })
      const gotLen = got && got.bytes ? b4a.byteLength(got.bytes, 'hex') : 0
      const roundtrip = got && got.bytes && b4a.toString(bytes, 'hex') === got.bytes
      console.log('GET-BLOB back size=' + gotLen + ' mime=' + (got && got.mimeType) + ' roundtripBytesEqual=' + roundtrip)
      clearTimeout(to); res({ cid: up.cid })
    } catch (e) { clearTimeout(to); rej(e) }
  })
})
swarm.join(b4a.from(ck, 'hex'), { client: true, server: true }); await swarm.flush()
try { const r = await done; console.log('OK cid=' + r.cid) } catch (e) { console.log('FAIL ' + e.message) }
await swarm.destroy(); globalThis.Bare.exit(0)