v0.3.3: Rate limiting, IPv6 fix, schema versioning, video preload, engagement propagation
Security & stability: - Incoming auth-fail rate limiting per source IP (3 attempts, then exponential backoff) - Schema versioning via PRAGMA user_version with migration framework Networking: - IPv6 http_addr fix: advertise actual public IPv6 instead of 0.0.0.0 - N2/N3 TTL reduced from 7 days to 5 hours - Full N1/N2 state re-broadcast every 4 hours - Bootstrap isolation recovery: 24h check with sticky N1 advertising - Bidirectional engagement propagation (upstream + downstream) - Auto downstream registration on pull sync and push notification - post_upstream table for CDN tree traversal Media & UI: - Video preload="auto" for share links and in-app blob URLs - Following: Online/Offline split with last-seen timestamps - DMs filtered from My Posts tab - Image lightbox, audio player, file attachments with download prompt - Share link unroutable address filtering Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
e6f55fb1d6
commit
8fad30cf95
8 changed files with 136 additions and 17 deletions
|
|
@ -28,16 +28,72 @@ pub struct Storage {
|
|||
conn: Connection,
|
||||
}
|
||||
|
||||
/// Current schema version. Bump this when making schema or data changes
|
||||
/// that require migration. Old databases with a lower version will be migrated.
|
||||
/// If the gap is too large (major version mismatch), the DB is reset instead.
|
||||
const SCHEMA_VERSION: u32 = 2;
|
||||
|
||||
/// Minimum schema version we can migrate from. Anything older gets a full reset.
|
||||
const MIN_MIGRATABLE_VERSION: u32 = 1;
|
||||
|
||||
impl Storage {
|
||||
pub fn open(path: impl AsRef<Path>) -> anyhow::Result<Self> {
|
||||
let conn = Connection::open(path)?;
|
||||
let conn = Connection::open(path.as_ref())?;
|
||||
conn.execute_batch("PRAGMA journal_mode=WAL;")?;
|
||||
|
||||
// Check schema version
|
||||
let db_version: u32 = conn.pragma_query_value(None, "user_version", |row| row.get(0))?;
|
||||
|
||||
if db_version > 0 && db_version < MIN_MIGRATABLE_VERSION {
|
||||
// Too old to migrate — reset the database
|
||||
tracing::warn!(
|
||||
db_version, current = SCHEMA_VERSION,
|
||||
"Database schema too old to migrate, resetting"
|
||||
);
|
||||
drop(conn);
|
||||
std::fs::remove_file(path.as_ref())?;
|
||||
let conn = Connection::open(path.as_ref())?;
|
||||
conn.execute_batch("PRAGMA journal_mode=WAL;")?;
|
||||
let storage = Self { conn };
|
||||
storage.init_tables()?;
|
||||
storage.set_schema_version(SCHEMA_VERSION)?;
|
||||
return Ok(storage);
|
||||
}
|
||||
|
||||
let storage = Self { conn };
|
||||
storage.init_tables()?;
|
||||
storage.migrate()?;
|
||||
|
||||
if db_version < SCHEMA_VERSION {
|
||||
// Run version-specific data migrations
|
||||
storage.migrate_data(db_version)?;
|
||||
storage.set_schema_version(SCHEMA_VERSION)?;
|
||||
tracing::info!(from = db_version, to = SCHEMA_VERSION, "Database schema upgraded");
|
||||
}
|
||||
|
||||
Ok(storage)
|
||||
}
|
||||
|
||||
fn set_schema_version(&self, version: u32) -> anyhow::Result<()> {
|
||||
self.conn.pragma_update(None, "user_version", version)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Data migrations that run once when upgrading between schema versions.
|
||||
fn migrate_data(&self, from_version: u32) -> anyhow::Result<()> {
|
||||
if from_version < 2 {
|
||||
// v1 → v2: Clear stale N2/N3 entries and mesh_peers that may prevent
|
||||
// bootstrap reconnection. The node will rediscover peers on next startup.
|
||||
tracing::info!("Schema v2: clearing stale network state for fresh discovery");
|
||||
let _ = self.conn.execute_batch(
|
||||
"DELETE FROM reachable_n2;
|
||||
DELETE FROM reachable_n3;
|
||||
DELETE FROM mesh_peers;"
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn init_tables(&self) -> anyhow::Result<()> {
|
||||
self.conn.execute_batch(
|
||||
"CREATE TABLE IF NOT EXISTS posts (
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue