| … | … | @@ -58,7 +58,7 @@ let userDrive = null // Hyperdrive for user files (images, etc.) |
| 58 | 58 | let identity = null // Legacy IdentityKey (will be removed in Phase 2) |
| 59 | 59 | let anprotoKeypair = null // ANProto keypair { publicKey: Buffer, secretKey: Buffer } |
| 60 | 60 | let follows = new Map() // discoveryKey -> { feed, publicKey, name } |
| 61 | | let bridgeProcess = null // Bridge daemon child process (for web UI management) |
| 61 | let bridgeInstance = null // Bridge daemon instance (WirecoreBridge, for web UI management) |
| 62 | 62 | let bridgeConfig = { relayUrl: 'https://7rnx.net/relay', autoStart: false } // Bridge configuration |
| 63 | 63 | |
| 64 | 64 | /** |
| … | … | @@ -1557,24 +1557,31 @@ async function followUser(publicKeyInput, name) { |
| 1557 | 1557 | * Get bridge status (running, stats, config) |
| 1558 | 1558 | */ |
| 1559 | 1559 | async function getBridgeStatus() { |
| 1560 | | const { WirecoreBridge } = await import('./bridge/wirecore-bridge.js') |
| 1561 | | const bridge = new WirecoreBridge(STORAGE_PATH, bridgeConfig.relayUrl) |
| 1562 | | |
| 1563 | 1560 | try { |
| 1564 | | await bridge.init() |
| 1565 | | const status = await bridge.status() |
| 1566 | | await bridge.close() |
| 1561 | // If bridge is running, get its status |
| 1562 | if (bridgeInstance) { |
| 1563 | const status = await bridgeInstance.status() |
| 1564 | return { |
| 1565 | running: true, |
| 1566 | config: bridgeConfig, |
| 1567 | status |
| 1568 | } |
| 1569 | } |
| 1567 | 1570 | |
| 1571 | // Bridge not running - return basic status without accessing storage |
| 1572 | // (accessing storage would cause ELOCKED if web server already has it open) |
| 1568 | 1573 | return { |
| 1569 | | running: bridgeProcess !== null && !bridgeProcess.killed, |
| 1570 | | pid: bridgeProcess ? bridgeProcess.pid : null, |
| 1574 | running: false, |
| 1571 | 1575 | config: bridgeConfig, |
| 1572 | | status |
| 1576 | status: { |
| 1577 | relay: { online: null }, // Unknown when bridge not running |
| 1578 | sync: { pendingPosts: 0 }, |
| 1579 | stats: { totalPushed: 0, totalPulled: 0 } |
| 1580 | } |
| 1573 | 1581 | } |
| 1574 | 1582 | } catch (err) { |
| 1575 | 1583 | return { |
| 1576 | 1584 | running: false, |
| 1577 | | pid: null, |
| 1578 | 1585 | config: bridgeConfig, |
| 1579 | 1586 | error: err.message |
| 1580 | 1587 | } |
| … | … | @@ -1582,55 +1589,44 @@ async function getBridgeStatus() { |
| 1582 | 1589 | } |
| 1583 | 1590 | |
| 1584 | 1591 | /** |
| 1585 | | * Start bridge daemon as child process |
| 1592 | * Start bridge daemon in-process |
| 1586 | 1593 | */ |
| 1587 | 1594 | async function startBridge() { |
| 1588 | | if (bridgeProcess && !bridgeProcess.killed) { |
| 1595 | if (bridgeInstance) { |
| 1589 | 1596 | throw new Error('Bridge already running') |
| 1590 | 1597 | } |
| 1591 | 1598 | |
| 1592 | | const { spawn } = await import('bare-subprocess') |
| 1599 | console.log('🌉 Starting bridge daemon...') |
| 1600 | console.log(' Relay:', bridgeConfig.relayUrl) |
| 1593 | 1601 | |
| 1594 | | // Start bridge daemon |
| 1595 | | const pullInterval = bridgeConfig.pullInterval || 300 // 5 minutes default |
| 1596 | | bridgeProcess = spawn('pear', ['run', '.', 'bridge', 'start', '--interval', pullInterval.toString()], { |
| 1597 | | stdio: 'inherit', |
| 1598 | | cwd: process.cwd() |
| 1599 | | }) |
| 1602 | const { WirecoreBridge } = await import('./bridge/wirecore-bridge.js') |
| 1600 | 1603 | |
| 1601 | | bridgeProcess.on('exit', (code) => { |
| 1602 | | console.log(`Bridge process exited with code ${code}`) |
| 1603 | | bridgeProcess = null |
| 1604 | | }) |
| 1604 | // Pass existing Corestore instance to avoid ELOCKED error |
| 1605 | bridgeInstance = new WirecoreBridge(bridgeConfig.relayUrl, store, STORAGE_PATH) |
| 1605 | 1606 | |
| 1606 | | // Wait a moment to ensure it started |
| 1607 | | await new Promise(resolve => setTimeout(resolve, 1000)) |
| 1607 | await bridgeInstance.init() |
| 1608 | 1608 | |
| 1609 | | if (bridgeProcess.killed) { |
| 1610 | | throw new Error('Bridge failed to start') |
| 1611 | | } |
| 1609 | // Start in daemon mode (watch + periodic pull) |
| 1610 | const pullInterval = (bridgeConfig.pullInterval || 300) * 1000 // Convert seconds to ms |
| 1611 | await bridgeInstance.start(pullInterval) |
| 1612 | 1612 | |
| 1613 | | console.log('✅ Bridge daemon started (PID:', bridgeProcess.pid, ')') |
| 1613 | console.log('✅ Bridge daemon started') |
| 1614 | 1614 | } |
| 1615 | 1615 | |
| 1616 | 1616 | /** |
| 1617 | 1617 | * Stop bridge daemon |
| 1618 | 1618 | */ |
| 1619 | 1619 | async function stopBridge() { |
| 1620 | | if (!bridgeProcess || bridgeProcess.killed) { |
| 1620 | if (!bridgeInstance) { |
| 1621 | 1621 | throw new Error('Bridge not running') |
| 1622 | 1622 | } |
| 1623 | 1623 | |
| 1624 | | bridgeProcess.kill('SIGTERM') |
| 1624 | console.log('🌉 Stopping bridge daemon...') |
| 1625 | 1625 | |
| 1626 | | // Wait for graceful shutdown |
| 1627 | | await new Promise(resolve => setTimeout(resolve, 2000)) |
| 1626 | await bridgeInstance.stop() |
| 1627 | await bridgeInstance.close() |
| 1628 | bridgeInstance = null |
| 1628 | 1629 | |
| 1629 | | if (!bridgeProcess.killed) { |
| 1630 | | bridgeProcess.kill('SIGKILL') |
| 1631 | | } |
| 1632 | | |
| 1633 | | bridgeProcess = null |
| 1634 | 1630 | console.log('✅ Bridge daemon stopped') |
| 1635 | 1631 | } |
| 1636 | 1632 | |
| … | … | @@ -1639,7 +1635,9 @@ async function stopBridge() { |
| 1639 | 1635 | */ |
| 1640 | 1636 | async function syncBridge() { |
| 1641 | 1637 | const { WirecoreBridge } = await import('./bridge/wirecore-bridge.js') |
| 1642 | | const bridge = new WirecoreBridge(STORAGE_PATH, bridgeConfig.relayUrl) |
| 1638 | |
| 1639 | // Pass existing Corestore instance to avoid ELOCKED error |
| 1640 | const bridge = new WirecoreBridge(bridgeConfig.relayUrl, store, STORAGE_PATH) |
| 1643 | 1641 | |
| 1644 | 1642 | await bridge.init() |
| 1645 | 1643 | const result = await bridge.sync() |