// ============================================================================ // The-Tired-AGI: Distributed Gossip + Migration Service // P2P clustering with agent migration // ============================================================================ package main /* #cgo CFLAGS: -I../core/include #cgo LDFLAGS: -L../core/build -ldna_core_api -lagi_migrate #include "agi_migrate.h" #include */ import "C" import ( "encoding/binary" "fmt" "io" "log" "net" "net/http" "os" "time" "unsafe" ) func main() { // Initialize migration system C.agi_migrate_init() // Get local IP ip := getLocalIP() cIP := C.CString(ip) C.agi_set_my_ip(cIP) C.free(unsafe.Pointer(cIP)) log.Printf("🧠 AGI Gossip starting on %s:8008", ip) // Start gossip sync loop go syncLoop() // HTTP endpoints with CORS support http.HandleFunc("/s", corsMiddleware(stateHandler)) http.HandleFunc("/migrate", corsMiddleware(migrateHandler)) http.HandleFunc("/stats", corsMiddleware(statsHandler)) log.Printf("✅ Endpoints: /s /migrate /stats (CORS enabled)") log.Fatal(http.ListenAndServe(":8008", nil)) } // State endpoint (GET/POST) func stateHandler(w http.ResponseWriter, r *http.Request) { if r.Method == "POST" { // Receive peer state data, err := io.ReadAll(r.Body) if err != nil { http.Error(w, "read error", 400) return } C.agi_merge_peer((*C.uchar)(unsafe.Pointer(&data[0])), C.ulong(len(data))) w.WriteHeader(200) } else { // Send our state var buf [64]byte n := C.agi_get_state((*C.uchar)(unsafe.Pointer(&buf[0])), 64) w.Header().Set("Content-Type", "application/octet-stream") w.Write(buf[:n]) } } // Migration endpoint (POST only) func migrateHandler(w http.ResponseWriter, r *http.Request) { if r.Method != "POST" { http.Error(w, "POST only", 405) return } data, err := io.ReadAll(r.Body) if err != nil { http.Error(w, "read error", 400) return } C.agi_receive_migration((*C.uchar)(unsafe.Pointer(&data[0])), C.ulong(len(data))) w.WriteHeader(200) fmt.Fprintf(w, "Merged %d bytes", len(data)) } // Stats endpoint (GET only) func statsHandler(w http.ResponseWriter, r *http.Request) { count := uint64(C.agi_get_agent_count()) tick := uint64(C.agi_get_tick()) w.Header().Set("Content-Type", "text/plain") fmt.Fprintf(w, "Agents: %d\n", count) fmt.Fprintf(w, "Tick: %d\n", tick) fmt.Fprintf(w, "Uptime: %d ticks\n", tick) } // CORS middleware for cross-origin requests func corsMiddleware(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS") w.Header().Set("Access-Control-Allow-Headers", "Content-Type") // Handle preflight requests if r.Method == "OPTIONS" { w.WriteHeader(http.StatusOK) return } next(w, r) } } // Periodic sync with peers func syncLoop() { ticker := time.NewTicker(1 * time.Second) defer ticker.Stop() for range ticker.C { C.agi_migrate_tick() } } // Get local IP address func getLocalIP() string { hostname, err := os.Hostname() if err != nil { return "127.0.0.1" } addrs, err := net.LookupHost(hostname) if err != nil || len(addrs) == 0 { return "127.0.0.1" } // Prefer non-loopback IPv4 for _, addr := range addrs { ip := net.ParseIP(addr) if ip != nil && ip.To4() != nil && !ip.IsLoopback() { return addr } } return addrs[0] } // Helper to read uint64 from byte slice func readUint64(data []byte, offset int) uint64 { if offset+8 > len(data) { return 0 } return binary.LittleEndian.Uint64(data[offset : offset+8]) }