package api import ( "net/http" "strconv" "strings" dbpkg "crypto-miner-server/internal/db" ) // OathLedgerBridge records immutable rows and broadcasts dashboard WS events. type OathLedgerBridge struct { DB *dbpkg.Database Hub *WSHub } // Record appends one oath ledger row and emits oath_ledger_event when a hub is wired. func (b *OathLedgerBridge) Record(actor, actionType, agentID, strain, outcome string, whySource, payload interface{}) error { if b == nil || b.DB == nil { return nil } whyHash := dbpkg.HashWhyJSON(whySource) entry, err := b.DB.InsertOathLedger(actor, actionType, agentID, strain, whyHash, outcome, payload) if err != nil { return err } if b.Hub != nil && entry != nil { b.Hub.BroadcastOathLedgerEvent(*entry) } return nil } // BroadcastOathLedgerEvent pushes a live oath row to dashboard clients. func (h *WSHub) BroadcastOathLedgerEvent(entry dbpkg.OathLedgerEntry) { if h == nil { return } h.broadcastDashboard(Message{ Type: "oath_ledger_event", Payload: mustMarshal(entry), }) } // GetOathLedger lists recent immutable accountability rows. func (f *FleetHandler) GetOathLedger(w http.ResponseWriter, r *http.Request) { if f.db == nil { writeJSON(w, []dbpkg.OathLedgerEntry{}) return } limit := 100 if raw := strings.TrimSpace(r.URL.Query().Get("limit")); raw != "" { if n, err := strconv.Atoi(raw); err == nil && n > 0 { limit = n } } rows, err := f.db.ListOathLedger(limit) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } if rows == nil { rows = []dbpkg.OathLedgerEntry{} } writeJSON(w, rows) } func agentStrainFromDB(database *dbpkg.Database, agentID string) string { if database == nil || agentID == "" { return "" } ag, err := database.GetAgent(agentID) if err != nil || ag == nil { return "" } return ag.SpreadStrain } func oathOutcomeFromError(err error) string { if err != nil { return dbpkg.OathOutcomeFail } return dbpkg.OathOutcomeSuccess }