Add scout constellation mode for APK venue persona packs.
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
Cluster 3+ scout_report hits on the same SSID within 10 minutes; server infers airport/campus/retail venue class and pushes persona spread_policy. Emberwake weather-map merges active scout biomes. Includes agent, server API, and Vitest coverage.
This commit is contained in:
106
server/internal/api/scout_constellation.go
Normal file
106
server/internal/api/scout_constellation.go
Normal file
@@ -0,0 +1,106 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
fleetai "crypto-miner-server/internal/ai"
|
||||
)
|
||||
|
||||
// ScoutConstellationHandler serves active scout venue constellations.
|
||||
type ScoutConstellationHandler struct {
|
||||
hub *WSHub
|
||||
}
|
||||
|
||||
// NewScoutConstellationHandler returns a REST handler backed by the WS hub.
|
||||
func NewScoutConstellationHandler(hub *WSHub) *ScoutConstellationHandler {
|
||||
return &ScoutConstellationHandler{hub: hub}
|
||||
}
|
||||
|
||||
// GET /api/v1/scout/constellations
|
||||
func (h *ScoutConstellationHandler) GetConstellations(w http.ResponseWriter, _ *http.Request) {
|
||||
if h.hub == nil {
|
||||
writeJSON(w, map[string]interface{}{"constellations": []fleetai.ScoutConstellation{}})
|
||||
return
|
||||
}
|
||||
writeJSON(w, map[string]interface{}{
|
||||
"constellations": h.hub.scoutConstellationSnapshot(),
|
||||
"generated_at": time.Now().UTC().Format(time.RFC3339),
|
||||
})
|
||||
}
|
||||
|
||||
func (h *WSHub) ensureScoutConstellations() {
|
||||
if h.scoutConstellations == nil {
|
||||
h.scoutConstellations = fleetai.NewScoutConstellationRegistry()
|
||||
}
|
||||
if h.scoutAgents == nil {
|
||||
h.scoutAgents = make(map[string]bool)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *WSHub) scoutConstellationSnapshot() []fleetai.ScoutConstellation {
|
||||
h.scoutConstellationMu.Lock()
|
||||
defer h.scoutConstellationMu.Unlock()
|
||||
h.ensureScoutConstellations()
|
||||
return h.scoutConstellations.Snapshot()
|
||||
}
|
||||
|
||||
func (h *WSHub) scoutConstellationForAgent(agentID string) *fleetai.ScoutConstellation {
|
||||
h.scoutConstellationMu.Lock()
|
||||
defer h.scoutConstellationMu.Unlock()
|
||||
h.ensureScoutConstellations()
|
||||
return h.scoutConstellations.ForAgent(agentID)
|
||||
}
|
||||
|
||||
func (h *WSHub) ingestScoutConstellationReport(agentID, ssid string, serviceCount int) {
|
||||
h.scoutConstellationMu.Lock()
|
||||
defer h.scoutConstellationMu.Unlock()
|
||||
h.ensureScoutConstellations()
|
||||
h.scoutAgents[agentID] = true
|
||||
|
||||
constellation, changed := h.scoutConstellations.Record(agentID, ssid, serviceCount, time.Now().UTC())
|
||||
if !changed {
|
||||
return
|
||||
}
|
||||
|
||||
h.broadcastScoutConstellationsLocked()
|
||||
h.pushScoutConstellationPolicyLocked(constellation)
|
||||
}
|
||||
|
||||
func (h *WSHub) broadcastScoutConstellationsLocked() {
|
||||
snapshot := h.scoutConstellations.Snapshot()
|
||||
h.broadcastDashboard(Message{
|
||||
Type: "scout_constellations",
|
||||
Payload: mustMarshal(map[string]interface{}{
|
||||
"constellations": snapshot,
|
||||
"generated_at": time.Now().UTC().Format(time.RFC3339),
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
func (h *WSHub) pushScoutConstellationPolicyLocked(constellation fleetai.ScoutConstellation) {
|
||||
spreadPolicy := fleetai.BuildScoutSpreadPolicy(constellation)
|
||||
temp := fleetai.PersonaSpreadTemperament(constellation.PersonaPack)
|
||||
policy := FleetAgentPolicy{SpreadTemperament: &temp}
|
||||
|
||||
for _, agentID := range constellation.AgentIDs {
|
||||
payload := marshalPolicyUpdatePayload("scout-constellation-"+constellation.SSID, policy)
|
||||
var body map[string]interface{}
|
||||
_ = json.Unmarshal(payload, &body)
|
||||
if body == nil {
|
||||
body = map[string]interface{}{}
|
||||
}
|
||||
body["spread_policy"] = spreadPolicy
|
||||
out, _ := json.Marshal(body)
|
||||
_ = h.SendToAgent(agentID, Message{Type: "policy_update", Payload: out})
|
||||
}
|
||||
}
|
||||
|
||||
func (h *WSHub) scoutSpreadPolicyForAuth(agentID string) map[string]interface{} {
|
||||
c := h.scoutConstellationForAgent(agentID)
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
return fleetai.BuildScoutSpreadPolicy(*c)
|
||||
}
|
||||
Reference in New Issue
Block a user