verstak/cmd/verstak-gui/bindings_bridge.go

138 lines
3.2 KiB
Go

package main
import (
"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(bridge.Config{
Port: bc.Port,
Secret: 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 and secret back to config if auto-generated.
if bc.AutoGenPort {
bc.Port = port
}
if bc.Secret == "" {
bc.Secret = srv.Secret()
}
a.saveBridgeConfig(appCfg, bc)
a.mu.Lock()
a.bridge = srv
a.mu.Unlock()
}
// bridgeConfig extracts bridge config from app config, generating defaults if needed.
func (a *App) bridgeConfig(appCfg *config.AppConfig) *config.BridgeConfig {
if appCfg != nil && appCfg.Vault.Bridge.Port != 0 {
bc := &appCfg.Vault.Bridge
// If secret is empty, generate one on first run
if bc.Secret == "" {
bc.Secret = bridge.GenerateSecret()
}
return bc
}
return &config.BridgeConfig{
Port: 9786,
AutoGenPort: true,
Secret: bridge.GenerateSecret(),
}
}
// 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()
info["secret"] = a.bridge.Secret()
}
return info
}
// bridgeToBrowser converts a bridge.Event to a browser.Event.
func bridgeToBrowser(ev bridge.Event) browser.Event {
deviceID := ev.ID
if idx := indexOf(ev.ID, "_"); idx > 0 {
deviceID = ev.ID[:idx]
}
return browser.Event{
ID: ev.ID,
DeviceID: 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,
}
}
func indexOf(s string, sub string) int {
for i := 0; i < len(s); i++ {
if string(s[i]) == sub {
return i
}
}
return -1
}