verstak/cmd/verstak-gui/bindings_bridge.go

170 lines
3.8 KiB
Go

package main
import (
"fmt"
"log"
"verstak/internal/core/bridge"
"verstak/internal/core/browser"
"verstak/internal/core/config"
)
// startBridge creates and starts the local HTTP bridge for browser extension.
func (a *App) startBridge(appCfg *config.AppConfig) {
// Determine bridge config
bc := a.bridgeConfig(appCfg)
handler := func(events []bridge.Event) {
// Convert to browser events and store in staging.
be := make([]browser.Event, 0, len(events))
for _, ev := range events {
be = append(be, bridgeToBrowser(ev))
}
n, err := a.browser.InsertEvents(be)
if err != nil {
log.Printf("[bridge] store events: %v", err)
return
}
if n > 0 {
log.Printf("[bridge] stored %d/%d events", n, len(be))
}
}
srv := bridge.NewServer(bc.Secret, handler)
port, err := srv.Start(bridge.Config{
Port: bc.Port,
AutoGenPort: bc.AutoGenPort,
Secret: bc.Secret,
})
if err != nil {
log.Printf("[bridge] failed to start: %v", err)
return
}
// Save the actual port back to config if auto-generated.
if bc.AutoGenPort {
bc.Port = port
}
a.saveBridgeConfig(appCfg, bc)
a.mu.Lock()
a.bridge = srv
a.mu.Unlock()
}
// bridgeConfig extracts bridge config from app config.
func (a *App) bridgeConfig(appCfg *config.AppConfig) *config.BridgeConfig {
if appCfg != nil && appCfg.Vault.Bridge.Port != 0 {
return &appCfg.Vault.Bridge
}
return &config.BridgeConfig{
Port: 9786,
AutoGenPort: false,
}
}
// saveBridgeConfig persists the bridge config to disk.
func (a *App) saveBridgeConfig(appCfg *config.AppConfig, bc *config.BridgeConfig) {
if appCfg == nil {
// Load or create fresh
loaded, err := config.LoadAppConfig()
if err != nil || loaded == nil {
loaded = config.DefaultAppConfig()
}
appCfg = loaded
}
appCfg.Vault.Bridge = *bc
if err := config.SaveAppConfig(appCfg); err != nil {
log.Printf("[bridge] save config: %v", err)
}
}
// BridgeInfo returns the current bridge server status.
func (a *App) BridgeInfo() map[string]interface{} {
info := map[string]interface{}{
"running": false,
"port": 0,
}
if a.bridge != nil {
info["running"] = a.bridge.Running()
info["port"] = a.bridge.Port()
}
return info
}
// bridgeToBrowser converts a bridge.Event to a browser.Event.
func bridgeToBrowser(ev bridge.Event) browser.Event {
return browser.Event{
ID: ev.ID,
DeviceID: ev.DeviceID,
Type: ev.Type,
URL: ev.URL,
Title: ev.Title,
Domain: ev.Domain,
ActiveSeconds: ev.ActiveSeconds,
TSStart: ev.TSStart,
TSEnd: ev.TSEnd,
TS: ev.TS,
SelectedText: ev.SelectedText,
Note: ev.Note,
}
}
// RestartBridge stops and restarts the bridge server with current config.
func (a *App) RestartBridge() error {
// Stop existing server outside the lock to avoid blocking other bindings.
a.mu.Lock()
oldBridge := a.bridge
a.bridge = nil
a.mu.Unlock()
if oldBridge != nil {
oldBridge.Stop()
}
// Load config
appCfg, err := config.LoadAppConfig()
if err != nil || appCfg == nil {
appCfg = config.DefaultAppConfig()
}
bc := a.bridgeConfig(appCfg)
if !bc.Enabled {
return nil
}
handler := func(events []bridge.Event) {
be := make([]browser.Event, 0, len(events))
for _, ev := range events {
be = append(be, bridgeToBrowser(ev))
}
n, err := a.browser.InsertEvents(be)
if err != nil {
log.Printf("[bridge] store events: %v", err)
return
}
if n > 0 {
log.Printf("[bridge] stored %d/%d events", n, len(be))
}
}
srv := bridge.NewServer(bc.Secret, handler)
port, err := srv.Start(bridge.Config{
Port: bc.Port,
AutoGenPort: bc.AutoGenPort,
Secret: bc.Secret,
})
if err != nil {
return fmt.Errorf("bridge restart: %w", err)
}
a.mu.Lock()
a.bridge = srv
a.mu.Unlock()
log.Printf("[bridge] restarted on port %d", port)
return nil
}