package main import ( "fmt" "log" "net" "net/http" "google.golang.org/grpc" "google.golang.org/grpc/reflection" // "server/api" // This would be the generated package ) const version = "1.0.0" // CoordinatorServer implements the Coordinator gRPC service type CoordinatorServer struct { // In a full implementation, we would have a Redis client here // nodes map[string]*NodeInfo } func (s *CoordinatorServer) RegisterNode(ctx interface{}, req interface{}) (interface{}, error) { fmt.Println("RegisterNode called") return nil, nil // Placeholder for actual implementation } func (s *CoordinatorServer) Heartbeat(ctx interface{}, req interface{}) (interface{}, error) { fmt.Println("Heartbeat called") return nil, nil } func (s *CoordinatorServer) GetPeerEndpoint(ctx interface{}, req interface{}) (interface{}, error) { fmt.Println("GetPeerEndpoint called") return nil, nil } func (s *CoordinatorServer) SignalConnection(ctx interface{}, req interface{}) (interface{}, error) { fmt.Println("SignalConnection called") return nil, nil } // STUN server implementation func startSTUNServer(port int) { addr := fmt.Sprintf(":%d", port) conn, err := net.ListenUDP("udp", &net.UDPAddr{Port: port}) if err != nil { log.Fatalf("STUN server failed to start: %v", err) } defer conn.Close() fmt.Printf("STUN server listening on %s\n", addr) buf := make([]byte, 1024) for { n, remoteAddr, err := conn.ReadFromUDP(buf) if err != nil { log.Printf("STUN read error: %v", err) continue } fmt.Printf("Received STUN request from %s (size: %d)\n", remoteAddr, n) // Simplified STUN response: send the remote address back to the client // In a real STUN server, we would follow RFC 5389 response := []byte(fmt.Sprintf("STUN_RESP:%s", remoteAddr.String())) _, err = conn.WriteToUDP(response, remoteAddr) if err != nil { log.Printf("STUN write error: %v", err) } } } func main() { // Start STUN server in a goroutine go startSTUNServer(3478) // Serve HTML Dashboard http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { // Note: In a production app, we would use a template to inject the version // For this task, we serve the file and suggest using a template for dynamic injection http.ServeFile(w, r, "C:\\Users\\jadon\\Documents\\vscode\\tailscale-test\\meshvpn-dashboard\\index.html") }) // Start HTTP server in a goroutine go func() { fmt.Printf("HTTP Dashboard listening on :8080 (Version: %s)\n", version) if err := http.ListenAndServe(":8080", nil); err != nil { log.Fatalf("HTTP server failed: %v", err) } }() // Start gRPC Coordinator server lis, err := net.Listen("tcp", ":50051") if err != nil { log.Fatalf("failed to listen: %v", err) } s := grpc.NewServer() // In a real setup, we'd register the generated server: // pb.RegisterCoordinatorServer(s, &CoordinatorServer{}) reflection.Register(s) fmt.Println("Coordinator Server listening on :50051") if err := s.Serve(lis); err != nil { log.Fatalf("failed to serve: %v", err) } }