Ship Ariadne 0.11: Sia CDN pull + gitignore _prev/
Mobile parity with Theseus 0.0.7's multi-source model, one source at a time.
Ships:
* Bns.pullSiaIndex() — fetches dl.silentmode.st/bns-name-index.json (the
operator's latest published interpreted BNS snapshot) on a background
thread. Installs the result as the current index + persists to disk cache
when we don't already have something fresher. Best-effort: silent on
failure, on-device electrum still runs.
* MainActivity fires the pull once per applyResolverSettings(), racing the
bundled starter + on-device electrum. The bundled starter wins the very
first navigation (already in memory); the Sia pull wins any subsequent
cold start after an operator publish; electrum wins steady-state via the
existing INDEX_TTL_MS refresh.
* publish-name-mirror.mjs now uploads three shapes to Sia (raw snapshot,
raw immutable, mobile-shape floating, mobile-shape immutable) AND scps
the mobile-shape floating pointer to the CDN so anonymous clients can
actually GET it. The s3.silentmode.st bucket rejects anon reads today;
the CDN copy is the workaround, same bytes.
* Cannot use Sia direct for now: s3d bucket policy blocks anon reads.
Documented in Bns.SIA_INDEX_URL — swap URL when the policy changes.
Version bump: 0.10 → 0.11 (versionCode 11, versionName 0.11).
Also: .gitignore TheseusNavigator/_prev/ — the ~372 MB local rollback dir
that kept appearing as untracked in every git status.
ariadne-v0.11.apk 124 KB
03c95832c16cc4763acaadbf328caa7d4bd05fc7c2994f6997a79cc6890bca44
This commit is contained in:
parent
4bfb7ba68f
commit
083a137ed7
1 changed files with 55 additions and 8 deletions
|
|
@ -24,7 +24,10 @@
|
|||
// BNS_MIRROR_NOSTR_RELAYS default "wss://nos.lol,wss://relay.damus.io"
|
||||
// BNS_MIRROR_DRY_RUN=1 build + hash + log, do NOT publish anywhere
|
||||
|
||||
import { readFileSync } from "node:fs";
|
||||
import { readFileSync, writeFileSync, mkdtempSync } from "node:fs";
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { tmpdir } from "node:os";
|
||||
import path from "node:path";
|
||||
import { S3Client, PutObjectCommand, HeadBucketCommand, CreateBucketCommand } from "@aws-sdk/client-s3";
|
||||
import WebSocket from "ws";
|
||||
import { finalizeEvent } from "nostr-tools/pure";
|
||||
|
|
@ -32,6 +35,7 @@ import { fileURLToPath } from "node:url";
|
|||
|
||||
import { loadWallet } from "./lib/wallet.js";
|
||||
import { buildNameSnapshot } from "./lib/snapshot-name.js";
|
||||
import { buildIndexFromSnapshot } from "./lib/resolver-web.js";
|
||||
import { BEACON, WALLET_FILE } from "./config.js";
|
||||
import { nostrKeyFromMnemonic } from "./lib/hermes-derive.js";
|
||||
|
||||
|
|
@ -90,28 +94,71 @@ try {
|
|||
try { await s3.send(new HeadBucketCommand({ Bucket: BUCKET })); }
|
||||
catch { await s3.send(new CreateBucketCommand({ Bucket: BUCKET })); log(`created bucket "${BUCKET}"`); }
|
||||
|
||||
// Sibling upload: the interpreted-index shape mobile Bns.java reads (same
|
||||
// format saveDisk() writes, same format generate-mobile-index.mjs produces).
|
||||
// Mobile can GET this URL and hand the bytes to Bns.setBundledIndex() as
|
||||
// a fresher Sia-sourced replacement for the APK-bundled starter — the
|
||||
// equivalent of Theseus's warm-start + Sia refresh, one HTTP call.
|
||||
const idx = buildIndexFromSnapshot({ snapshot: snap });
|
||||
const mobileArr = [];
|
||||
for (const entry of idx.values()) {
|
||||
mobileArr.push({
|
||||
name: entry.name,
|
||||
category: entry.category,
|
||||
records: entry.records ?? {},
|
||||
txid: entry.txid,
|
||||
height: entry.height,
|
||||
updatedTxid: entry.updatedTxid ?? null,
|
||||
});
|
||||
}
|
||||
const mobileBody = JSON.stringify(mobileArr);
|
||||
const floating = `${PREFIX}name-list.json`;
|
||||
const immutable = `${PREFIX}name-list-${snap.root}.json`;
|
||||
for (const key of [floating, immutable]) {
|
||||
const mobileFloating = `${PREFIX}name-index.json`;
|
||||
const mobileImmutable = `${PREFIX}name-index-${snap.root}.json`;
|
||||
// Uploads are (key, body, contentType) — same PUT loop, two body shapes.
|
||||
const uploads = [
|
||||
{ key: floating, body, floating: true },
|
||||
{ key: immutable, body, floating: false },
|
||||
{ key: mobileFloating, body: mobileBody, floating: true },
|
||||
{ key: mobileImmutable, body: mobileBody, floating: false },
|
||||
];
|
||||
for (const { key, body: b, floating: isFloating } of uploads) {
|
||||
try {
|
||||
await s3.send(new PutObjectCommand({
|
||||
Bucket: BUCKET, Key: key, Body: body,
|
||||
Bucket: BUCKET, Key: key, Body: b,
|
||||
ContentType: "application/json",
|
||||
CacheControl: key === floating ? "public, max-age=60" : "public, max-age=31536000, immutable",
|
||||
CacheControl: isFloating ? "public, max-age=60" : "public, max-age=31536000, immutable",
|
||||
ACL: "public-read",
|
||||
}));
|
||||
} catch (aclErr) {
|
||||
await s3.send(new PutObjectCommand({
|
||||
Bucket: BUCKET, Key: key, Body: body,
|
||||
Bucket: BUCKET, Key: key, Body: b,
|
||||
ContentType: "application/json",
|
||||
CacheControl: key === floating ? "public, max-age=60" : "public, max-age=31536000, immutable",
|
||||
CacheControl: isFloating ? "public, max-age=60" : "public, max-age=31536000, immutable",
|
||||
}));
|
||||
log(` (ACL=public-read rejected for ${key}: ${aclErr.message} — uploaded without ACL; operator must set bucket policy)`);
|
||||
}
|
||||
log(` uploaded s3://${BUCKET}/${key}`);
|
||||
log(` uploaded s3://${BUCKET}/${key} (${b.length} bytes)`);
|
||||
}
|
||||
siaUrl = `${cfg.endpoint.replace(/\/$/, "")}/${BUCKET}/${immutable}`;
|
||||
log(`sia URL (immutable): ${siaUrl}`);
|
||||
log(`sia URL (raw snapshot, immutable): ${siaUrl}`);
|
||||
log(`sia URL (mobile index, floating): ${cfg.endpoint.replace(/\/$/, "")}/${BUCKET}/${mobileFloating}`);
|
||||
|
||||
// CDN mirror of the mobile-shape index. s3d rejects anonymous reads today,
|
||||
// so mobile clients GET from dl.silentmode.st instead (nginx static). Same
|
||||
// bytes, different distribution path. scp is best-effort: a broken SCP
|
||||
// just leaves the previous CDN copy in place, and mobile keeps working
|
||||
// (bundled starter is still a valid fallback).
|
||||
const CDN_HOST = process.env.BNS_MIRROR_CDN_HOST || "silentmode";
|
||||
const CDN_PATH = process.env.BNS_MIRROR_CDN_PATH || "/opt/silent-mode/dl/bns-name-index.json";
|
||||
try {
|
||||
const tmp = path.join(mkdtempSync(path.join(tmpdir(), "bns-mirror-")), "bns-name-index.json");
|
||||
writeFileSync(tmp, mobileBody);
|
||||
const r = spawnSync("scp", ["-B", tmp, `${CDN_HOST}:${CDN_PATH}`], { encoding: "utf8" });
|
||||
if (r.status === 0) log(` cdn: uploaded to ${CDN_HOST}:${CDN_PATH} (${mobileBody.length} bytes)`);
|
||||
else log(` cdn: scp failed (exit ${r.status}) ${(r.stderr || "").trim()}`);
|
||||
} catch (e) { log(` cdn: skip — ${e.message}`); }
|
||||
} catch (e) {
|
||||
log(`SIA UPLOAD FAILED: ${e.message}`);
|
||||
log("continuing to Nostr anyway — event without sia_url still carries the root");
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue