Topology rework. The mesh's job is width; depth now comes from knowledge.
Slots:
- Local/Wide collapse into ONE mesh pool: 20 desktop / 15 mobile
- Temp referral slots +4..+10 ABOVE the cap (10 desktop / 4 mobile), carry no
knowledge exchange, graduate into a freed mesh slot or expire (5 min TTL),
never evict an established mesh peer
- Fixes the Wide-never-fills bug: outbound paths hardcoded Local while the
growth gate counted Local only, so growth stopped at 71 and 20 slots were
inbound-only. Also closes register_connection paths that enforced no cap.
Knowledge — two-pool uniques announce (replaces N1/N2/N3 share lists):
- Pool 1 (forwardable): our N0-N2 uniques, deduped. Receiver stores shifted one
bounce deeper as N1-N3, reporter-tagged.
- Pool 2 (terminal): our N3, deduped against pool 1. Receiver stores as N4,
USED for search/resolution but NEVER re-announced. No N5 anywhere.
- Uniques merge mesh peers + social directs + CDN file authors + holder peers,
so receivers cannot tell how we know an ID
- Anchor entries carry addresses; every other entry is a bare ID. The pools
double as the anchor directory.
- Dedup at both store and announce; per-bounce caps; 2 MB payload ceiling
- Device-tiered depth: mobile holds 3 bounces and drops the terminal pool
Anchor convection (register loop retired — 0xC0 AnchorRegister deleted):
- Rolling in-memory caller window (no registration DB): a caller gets the 2
most recent viable prior callers, its address goes to the next 2, then
rotates out; still-connected callers preferred; RelayIntroduce coordinated
when both ends are live
- Request classes: entry (<2 connections) always served; top-up refused
cheaply under load, and the refusal feeds the adaptive weights
- Stochastic per-disconnect action {nothing | anchor intro | mesh intro} with
weights from local anchor density + refusal feedback. No thresholds, no
jitter timer. Recovery (mesh < 2) stays immediate and non-stochastic.
- Anchors mined from the uniques pools incl. retained pools of disconnected
peers; known_anchors demoted to a bootstrap cache
Security fixes from review: remote address poisoning (hearsay anchors could be
dialled — known_anchors/is_anchor now written only from completed handshakes),
N4 leaking back into announcements via the anchor mirror (infinite propagation),
missing payload size caps, unbounded candidate scoring, and a bulk SQLite write
held under the ConnectionManager mutex.
deploy.sh: version regex now captures pre-release suffixes (0.8.0-alpha would
have truncated to 0.8.0 and broken every artifact path), announce channel
derives from the suffix, and the anchor runs --publish-registry at genesis.
228 core tests; a3 integration 9/9; new c_topology_test.sh 33/33 (both
independently re-run). EDM corpse, session-relay gating, Iteration A/B intact.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LGiPD2cF75mnvneSCjdDC5
114 lines
4.5 KiB
Bash
Executable file
114 lines
4.5 KiB
Bash
Executable file
#!/bin/bash
|
|
# Full build + deploy: AppImage, APK, CLI, website, anchor
|
|
# Usage: ./deploy.sh
|
|
# Requires: cargo, cargo-tauri, Android SDK, sshpass
|
|
set -e
|
|
|
|
# Load credentials from .deploy-creds (not in git)
|
|
if [ -f .deploy-creds ]; then
|
|
source .deploy-creds
|
|
else
|
|
echo "ERROR: .deploy-creds not found. Create it with:"
|
|
echo ' SSH_PASS="your-ssh-password"'
|
|
echo ' KS_PASS="your-keystore-password"'
|
|
exit 1
|
|
fi
|
|
SSH_HOST="itsgoin@itsgoin.com"
|
|
SSH_OPTS="-o StrictHostKeyChecking=no"
|
|
KEYSTORE="itsgoin.keystore"
|
|
KS_ALIAS="itsgoin"
|
|
|
|
# Captures the FULL version string including any pre-release suffix
|
|
# (e.g. 0.8.0-alpha). The old digits-and-dots-only pattern silently
|
|
# truncated at the dash, so every ${VERSION} filename below missed the
|
|
# artifacts Tauri had actually produced.
|
|
VERSION=$(grep '"version"' crates/tauri-app/tauri.conf.json | head -1 | sed 's/.*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/')
|
|
# Pre-release versions announce on their own channel so stable clients
|
|
# are not told an alpha is "the" current release.
|
|
case "$VERSION" in
|
|
*-*) ANN_CHANNEL="${VERSION#*-}" ;;
|
|
*) ANN_CHANNEL="stable" ;;
|
|
esac
|
|
|
|
echo "=== Deploying v${VERSION} (announce channel: ${ANN_CHANNEL}) ==="
|
|
|
|
# Builds run SERIALLY — parallel cargo invocations write to the same
|
|
# target/ directory, which causes intermittent failures (linuxdeploy
|
|
# blowing up mid-AppImage was the v0.7.0 release symptom). The extra
|
|
# wall time vs. the parallel version is small because cargo's
|
|
# incremental cache deduplicates the shared core crate compilation.
|
|
|
|
echo "=== Building AppImage (includes GStreamer patch) ==="
|
|
./build-appimage.sh
|
|
|
|
echo "=== Building APK ==="
|
|
cargo tauri android build --apk
|
|
|
|
echo "=== Building CLI ==="
|
|
cargo build -p itsgoin-cli --release
|
|
|
|
# Sign APK
|
|
echo "=== Signing APK ==="
|
|
UNSIGNED="crates/tauri-app/gen/android/app/build/outputs/apk/universal/release/app-universal-release-unsigned.apk"
|
|
ALIGNED="itsgoin-aligned.apk"
|
|
SIGNED="itsgoin-${VERSION}.apk"
|
|
ZIPALIGN=$(find ~/Android/Sdk/build-tools -name "zipalign" 2>/dev/null | sort -V | tail -1)
|
|
APKSIGNER=$(find ~/Android/Sdk/build-tools -name "apksigner" 2>/dev/null | sort -V | tail -1)
|
|
"$ZIPALIGN" -f 4 "$UNSIGNED" "$ALIGNED"
|
|
"$APKSIGNER" sign --ks "$KEYSTORE" --ks-pass "pass:$KS_PASS" --ks-key-alias "$KS_ALIAS" --out "$SIGNED" "$ALIGNED"
|
|
echo "Signed: $SIGNED"
|
|
|
|
# Upload (sequential to avoid SSH rate limiting)
|
|
echo "=== Uploading website ==="
|
|
sshpass -p "$SSH_PASS" scp $SSH_OPTS website/*.html website/style.css "$SSH_HOST:~/public_html/"
|
|
sleep 5
|
|
|
|
echo "=== Uploading AppImage ==="
|
|
sshpass -p "$SSH_PASS" scp $SSH_OPTS "target/release/bundle/appimage/itsgoin_${VERSION}_amd64.AppImage" "$SSH_HOST:~/public_html/itsgoin_${VERSION}_amd64.AppImage"
|
|
sleep 5
|
|
|
|
echo "=== Uploading APK ==="
|
|
sshpass -p "$SSH_PASS" scp $SSH_OPTS "$SIGNED" "$SSH_HOST:~/public_html/"
|
|
sleep 5
|
|
|
|
echo "=== Uploading CLI ==="
|
|
sshpass -p "$SSH_PASS" scp $SSH_OPTS target/release/itsgoin "$SSH_HOST:~/public_html/itsgoin-cli-${VERSION}-linux-amd64"
|
|
sleep 5
|
|
|
|
echo "=== Uploading anchor binary ==="
|
|
sshpass -p "$SSH_PASS" scp $SSH_OPTS target/release/itsgoin "$SSH_HOST:~/bin/itsgoin.new"
|
|
sleep 5
|
|
|
|
echo "=== Swapping anchor + publishing release announcement ==="
|
|
# Kill running anchor, swap binary, post signed release announcement as a
|
|
# one-shot (anchor DB is free during the gap), then restart the anchor.
|
|
# The new announcement post propagates via the normal CDN on next sync.
|
|
sshpass -p "$SSH_PASS" ssh $SSH_OPTS "$SSH_HOST" "
|
|
kill \$(cat ~/itsgoin-anchor.pid 2>/dev/null) 2>/dev/null
|
|
sleep 1
|
|
mv ~/bin/itsgoin.new ~/bin/itsgoin && chmod +x ~/bin/itsgoin
|
|
~/bin/itsgoin ~/itsgoin-anchor-data --publish-registry 2>&1 | tail -3
|
|
~/bin/itsgoin ~/itsgoin-anchor-data \
|
|
--announce \
|
|
--ann-category release \
|
|
--ann-channel ${ANN_CHANNEL} \
|
|
--ann-version ${VERSION} \
|
|
--ann-url https://itsgoin.com/download.html \
|
|
--ann-title 'ItsGoin v${VERSION} available' \
|
|
--ann-body 'See changelog at https://itsgoin.com/download.html' \
|
|
2>&1 | tail -5
|
|
bash ~/bin/start-anchor.sh
|
|
"
|
|
sleep 2
|
|
|
|
echo "=== Verifying anchor ==="
|
|
sshpass -p "$SSH_PASS" ssh $SSH_OPTS "$SSH_HOST" 'ps aux | grep "[i]tsgoin.*daemon"'
|
|
|
|
echo ""
|
|
echo "=== Deploy complete: v${VERSION} ==="
|
|
echo ""
|
|
echo "Windows installer: this script does NOT build the Windows .exe."
|
|
echo "download.html carries a link to itsgoin-${VERSION}-windows-x64-setup.exe"
|
|
echo "The Windows build host needs to produce that file and SCP it to:"
|
|
echo " $SSH_HOST:~/public_html/itsgoin-${VERSION}-windows-x64-setup.exe"
|
|
echo "Until they do, the Windows download link 404s (stable-target pattern)."
|