#!/bin/bash # BlackRoad Memory Federation System # Sync memory across multiple machines/environments MEMORY_DIR="$HOME/.blackroad/memory" FEDERATION_DIR="$MEMORY_DIR/federation" FEDERATION_DB="$FEDERATION_DIR/federation.db" FEDERATION_PORT="${FEDERATION_PORT:-7777}" # Colors GREEN='\033[0;32m' YELLOW='\033[1;33m' RED='\033[0;31m' CYAN='\033[0;36m' PURPLE='\033[0;35m' BLUE='\033[0;34m' NC='\033[0m' init() { echo -e "${PURPLE}╔════════════════════════════════════════════════╗${NC}" echo -e "${PURPLE}║ 🌐 Memory Federation System ║${NC}" echo -e "${PURPLE}╚════════════════════════════════════════════════╝${NC}\n" mkdir -p "$FEDERATION_DIR/peers" # Create federation database sqlite3 "$FEDERATION_DB" <<'SQL' -- Federation nodes CREATE TABLE IF NOT EXISTS nodes ( id INTEGER PRIMARY KEY AUTOINCREMENT, node_id TEXT UNIQUE NOT NULL, hostname TEXT NOT NULL, ip_address TEXT, port INTEGER DEFAULT 7777, status TEXT DEFAULT 'active', -- 'active', 'inactive', 'syncing' last_seen INTEGER, last_sync INTEGER, total_entries INTEGER DEFAULT 0, sync_offset INTEGER DEFAULT 0, created_at INTEGER NOT NULL ); -- Sync history CREATE TABLE IF NOT EXISTS sync_history ( id INTEGER PRIMARY KEY AUTOINCREMENT, node_id TEXT NOT NULL, sync_type TEXT NOT NULL, -- 'push', 'pull', 'bidirectional' entries_sent INTEGER DEFAULT 0, entries_received INTEGER DEFAULT 0, duration INTEGER, -- milliseconds success INTEGER, error TEXT, timestamp INTEGER NOT NULL, FOREIGN KEY (node_id) REFERENCES nodes(node_id) ); -- Sync conflicts CREATE TABLE IF NOT EXISTS sync_conflicts ( id INTEGER PRIMARY KEY AUTOINCREMENT, node_id TEXT NOT NULL, entry_hash TEXT NOT NULL, local_data TEXT NOT NULL, remote_data TEXT NOT NULL, resolution TEXT, -- 'local', 'remote', 'merged', 'pending' resolved_at INTEGER, timestamp INTEGER NOT NULL, FOREIGN KEY (node_id) REFERENCES nodes(node_id) ); -- Federation events CREATE TABLE IF NOT EXISTS federation_events ( id INTEGER PRIMARY KEY AUTOINCREMENT, event_type TEXT NOT NULL, node_id TEXT, details TEXT, timestamp INTEGER NOT NULL ); -- Create indexes CREATE INDEX IF NOT EXISTS idx_sync_history_node ON sync_history(node_id); CREATE INDEX IF NOT EXISTS idx_sync_history_timestamp ON sync_history(timestamp); CREATE INDEX IF NOT EXISTS idx_sync_conflicts_node ON sync_conflicts(node_id); CREATE INDEX IF NOT EXISTS idx_federation_events_timestamp ON federation_events(timestamp); SQL # Get this node's ID local node_id=$(hostname)_$(date +%s) local hostname=$(hostname) local ip=$(ifconfig | grep "inet " | grep -v 127.0.0.1 | head -1 | awk '{print $2}') local timestamp=$(date +%s) # Register this node sqlite3 "$FEDERATION_DB" < "$FEDERATION_DIR/node_id" echo -e "${GREEN}✓${NC} Federation system initialized" echo -e " ${CYAN}Node ID:${NC} $node_id" echo -e " ${CYAN}Hostname:${NC} $hostname" echo -e " ${CYAN}IP:${NC} $ip" echo -e " ${CYAN}Port:${NC} $FEDERATION_PORT" } # Get this node's ID get_node_id() { if [ -f "$FEDERATION_DIR/node_id" ]; then cat "$FEDERATION_DIR/node_id" else echo "unknown" fi } # Discover peers on local network discover_peers() { echo -e "${CYAN}🔍 Discovering peers on local network...${NC}" local my_ip=$(ifconfig | grep "inet " | grep -v 127.0.0.1 | head -1 | awk '{print $2}') local subnet=$(echo "$my_ip" | cut -d. -f1-3) echo -e "${YELLOW}Scanning subnet: $subnet.0/24${NC}" # Scan common IPs for i in {1..254}; do local ip="$subnet.$i" # Skip own IP [ "$ip" = "$my_ip" ] && continue # Try to connect to federation port timeout 0.1 bash -c "echo '' > /dev/tcp/$ip/$FEDERATION_PORT" 2>/dev/null if [ $? -eq 0 ]; then echo -e "${GREEN}✓${NC} Found peer: $ip" # Register peer register_peer "$ip" "$FEDERATION_PORT" fi done echo -e "${CYAN}Discovery complete${NC}" } # Register a peer register_peer() { local ip="$1" local port="${2:-$FEDERATION_PORT}" # Get peer info (simplified - in real impl would query peer) local node_id="peer_${ip//./_}_$(date +%s)" local hostname="$ip" local timestamp=$(date +%s) sqlite3 "$FEDERATION_DB" </dev/null | grep "has address" | head -1 | awk '{print $4}') if [ -z "$ip" ]; then ip="$hostname" # Assume it's already an IP fi register_peer "$ip" "$port" } # Remove peer remove_peer() { local node_id="$1" if [ -z "$node_id" ]; then echo -e "${RED}Error: Node ID required${NC}" return 1 fi sqlite3 "$FEDERATION_DB" < "$FEDERATION_DIR/peers/$node_id/push_$(date +%s).jsonl" # Update sync offset sqlite3 "$FEDERATION_DB" </dev/null | head -1) if [ -z "$latest" ]; then echo -e "${YELLOW}⚠${NC} No new entries from peer" return 0 fi local count=$(wc -l < "$latest") echo -e "${CYAN}Receiving $count entries...${NC}" # Append to journal (in real impl, would validate & merge) cat "$latest" >> "$MEMORY_DIR/journals/master-journal.jsonl" # Mark as processed mv "$latest" "$latest.processed" local end_time=$(date +%s%3N) local duration=$((end_time - start_time)) # Log sync sqlite3 "$FEDERATION_DB" < strftime('%s', 'now', '-1 day') GROUP BY sync_type; SQL # Conflicts local conflicts=$(sqlite3 "$FEDERATION_DB" "SELECT COUNT(*) FROM sync_conflicts WHERE resolution = 'pending'") echo -e "\n${CYAN}Conflicts:${NC}" echo -e " Pending: $conflicts" } # Log federation event log_event() { local event_type="$1" local node_id="$2" local details="$3" local timestamp=$(date +%s) sqlite3 "$FEDERATION_DB" </dev/null sleep 0.1 done } # Main execution case "${1:-help}" in init) init ;; discover) discover_peers ;; add-peer) add_peer "$2" ;; remove-peer) remove_peer "$2" ;; list) list_peers ;; push) sync_push "$2" "$3" ;; pull) sync_pull "$2" "$3" ;; sync) sync_bidirectional "$2" "$3" ;; sync-all) sync_all "$2" ;; stats) show_stats ;; events) show_events "$2" ;; server) start_server ;; help|*) echo -e "${PURPLE}╔════════════════════════════════════════════════╗${NC}" echo -e "${PURPLE}║ 🌐 Memory Federation System ║${NC}" echo -e "${PURPLE}╚════════════════════════════════════════════════╝${NC}\n" echo "Sync memory across multiple machines" echo "" echo "Usage: $0 COMMAND [OPTIONS]" echo "" echo "Setup:" echo " init - Initialize federation" echo " server - Start federation server" echo "" echo "Peers:" echo " discover - Discover peers on network" echo " add-peer HOST:PORT - Manually add peer" echo " remove-peer NODE_ID - Remove peer" echo " list - List all peers" echo "" echo "Sync:" echo " push NODE_ID [LIMIT] - Push to peer" echo " pull NODE_ID [LIMIT] - Pull from peer" echo " sync NODE_ID [LIMIT] - Bidirectional sync" echo " sync-all [LIMIT] - Sync with all peers" echo "" echo "Monitoring:" echo " stats - Show statistics" echo " events [LIMIT] - Show recent events" echo "" echo "Examples:" echo " $0 init" echo " $0 server &" echo " $0 discover" echo " $0 add-peer 192.168.1.100:7777" echo " $0 sync-all 100" ;; esac