| … | … | @@ -37,7 +37,16 @@ let follows = new Map() // discoveryKey -> { feed, publicKey, name } |
| 37 | 37 | * Initialize Corestore and load state (without starting swarm) |
| 38 | 38 | */ |
| 39 | 39 | async function loadState() { |
| 40 | | if (store) return // Already loaded |
| 40 | if (store) return true // Already loaded |
| 41 | |
| 42 | // Check if storage directory exists first |
| 43 | const fs = await import('fs') |
| 44 | const path = await import('path') |
| 45 | const identityPath = path.join(STORAGE_PATH, 'cores') |
| 46 | |
| 47 | if (!fs.existsSync(identityPath)) { |
| 48 | return null // Not initialized yet |
| 49 | } |
| 41 | 50 | |
| 42 | 51 | store = new Corestore(STORAGE_PATH) |
| 43 | 52 | await store.ready() |
| … | … | @@ -47,6 +56,8 @@ async function loadState() { |
| 47 | 56 | await identityCore.ready() |
| 48 | 57 | |
| 49 | 58 | if (identityCore.length === 0) { |
| 59 | await store.close() |
| 60 | store = null |
| 50 | 61 | return null // Not initialized |
| 51 | 62 | } |
| 52 | 63 | |
| … | … | @@ -75,17 +86,21 @@ async function startSwarm() { |
| 75 | 86 | |
| 76 | 87 | swarm = new Hyperswarm() |
| 77 | 88 | |
| 89 | let connectionCount = 0 |
| 78 | 90 | swarm.on('connection', (socket, peerInfo) => { |
| 79 | | console.log('🔗 Connected to peer') |
| 91 | connectionCount++ |
| 92 | console.log(`🔗 Connected to peer ${connectionCount}`) |
| 80 | 93 | store.replicate(socket) |
| 81 | 94 | }) |
| 82 | 95 | |
| 83 | 96 | // Announce our feed |
| 84 | 97 | const discovery = swarm.join(myFeed.discoveryKey, { server: true, client: false }) |
| 85 | 98 | await discovery.flushed() |
| 99 | console.log(` 📢 Announced feed: ${b4a.toString(myFeed.discoveryKey, 'hex').substring(0, 16)}...`) |
| 86 | 100 | |
| 87 | 101 | // Load and join followed feeds |
| 88 | 102 | await loadFollows() |
| 103 | console.log(` 📥 Joined ${follows.size} follow topics`) |
| 89 | 104 | |
| 90 | 105 | // Graceful shutdown |
| 91 | 106 | goodbye(() => cleanup()) |
| … | … | @@ -283,9 +298,23 @@ async function cmdTimeline(limit = 20) { |
| 283 | 298 | // Start swarm to fetch remote data |
| 284 | 299 | console.log('📡 Connecting to network...') |
| 285 | 300 | await startSwarm() |
| 301 | console.log(` Following ${follows.size} users`) |
| 286 | 302 | |
| 287 | | // Wait a bit for connections |
| 288 | | await new Promise(resolve => setTimeout(resolve, 2000)) |
| 303 | // Wait for DHT discovery and connections |
| 304 | console.log('⏳ Waiting for peer connections (8 seconds)...') |
| 305 | await new Promise(resolve => setTimeout(resolve, 8000)) |
| 306 | |
| 307 | // Download latest blocks from followed feeds |
| 308 | console.log('📥 Syncing feeds...') |
| 309 | for (const [discoveryKey, { feed, name }] of follows.entries()) { |
| 310 | try { |
| 311 | // Update feed length (fetch remote length) |
| 312 | await feed.update() |
| 313 | console.log(` ${name}: ${feed.length} blocks`) |
| 314 | } catch (err) { |
| 315 | console.log(` ${name}: sync failed`) |
| 316 | } |
| 317 | } |
| 289 | 318 | |
| 290 | 319 | const messages = [] |
| 291 | 320 | |
| … | … | @@ -306,12 +335,13 @@ async function cmdTimeline(limit = 20) { |
| 306 | 335 | const feedLimit = Math.min(limit, feed.length) |
| 307 | 336 | for (let i = Math.max(0, feed.length - feedLimit); i < feed.length; i++) { |
| 308 | 337 | try { |
| 309 | | const block = await feed.get(i, { wait: false, timeout: 1000 }) |
| 338 | const block = await feed.get(i, { wait: true, timeout: 5000 }) |
| 310 | 339 | if (!block) continue |
| 311 | 340 | const entry = JSON.parse(block.toString()) |
| 312 | 341 | messages.push({ ...entry, author: name || publicKey.substring(0, 16), isOwn: false }) |
| 313 | 342 | } catch (err) { |
| 314 | | // Sparse replication may not have all blocks yet |
| 343 | // Skip blocks that can't be fetched |
| 344 | console.log(` ⚠️ Couldn't fetch block ${i} from ${name}: ${err.message}`) |
| 315 | 345 | continue |
| 316 | 346 | } |
| 317 | 347 | } |