package main import ( "app/shelfly/handlers" "app/shelfly/internal/db" "app/shelfly/internal/library" "app/shelfly/internal/route" "log" "net" "net/http" "time" "github.com/huin/goupnp/dcps/internetgateway1" "github.com/jackpal/gateway" "github.com/jackpal/go-nat-pmp" "github.com/gorilla/mux" ) func main() { // 1. Démarrer le routeur principal r := mux.NewRouter() // 2. Initialiser la DB bd := db.InitDB() // 2.1 library.CreateDefaultFolder(bd) // 3. Routes non protégées : on les monte sur le routeur principal route.RoutesPublic(r, bd) // 4. Créer un sous-routeur pour les routes protégées protected := r.PathPrefix("/").Subrouter() // 5. Appliquer le middleware JWT à ce sous-routeur protected.Use(handlers.AuthMiddleware) // 6. Enregistrer les routes protégées sur ce sous-routeur route.RoutesProtected(protected, bd) setupPortMappingWithFallback(4000, 4000) // 6.5. Exposer le dossier upload fs := http.StripPrefix("/upload/", http.FileServer(http.Dir("/app/upload"))) r.PathPrefix("/upload/").Handler(fs) // 7. Lancer le serveur sur le port 4000 log.Fatal(http.ListenAndServe(":4000", r)) } // Fonction principale à appeler dans main() func setupPortMappingWithFallback(internalPort, externalPort uint16) { success := setupUPnPWithRenewal(internalPort, externalPort) if !success { log.Println("🔁 UPnP indisponible, tentative NAT-PMP...") setupNATPMP(internalPort, externalPort) } } // UPnP avec renouvellement automatique func setupUPnPWithRenewal(internalPort, externalPort uint16) bool { clients, _, err := internetgateway1.NewWANIPConnection1Clients() if err != nil { log.Println("Erreur découverte UPnP :", err) return false } if len(clients) == 0 { log.Println("Aucun client UPnP détecté.") return false } localIP := getLocalIP() log.Println("IP locale détectée :", localIP) if localIP == "" { log.Println("Impossible d’obtenir l’IP locale") return false } client := clients[0] protocol := "TCP" description := "GoAutoExposition" duration := uint32(3600) mapPort := func() error { err := client.AddPortMapping("", externalPort, protocol, internalPort, localIP, true, description, duration) if err != nil { log.Println("UPnP mapping échoué :", err) return err } log.Printf("✅ [UPnP] Port %d externe redirigé vers %s:%d", externalPort, localIP, internalPort) return nil } // Premier essai if err := mapPort(); err != nil { return false } // Renouvellement go func() { for { time.Sleep(55 * time.Minute) mapPort() } }() return true } // NAT-PMP fallback func setupNATPMP(internalPort, externalPort uint16) { gatewayIP := getGatewayIP() if gatewayIP == "" { log.Println("Impossible d’obtenir la gateway pour NAT-PMP") return } client := natpmp.NewClient(net.ParseIP(gatewayIP)) _, err := client.AddPortMapping("tcp", int(internalPort), int(externalPort), 3600) if err != nil { log.Println("NAT-PMP mapping échoué :", err) } else { log.Printf("✅ [NAT-PMP] Port %d externe redirigé vers local :%d via NAT-PMP", externalPort, internalPort) } } // Obtenir IP locale func getLocalIP() string { conn, err := net.Dial("udp", "8.8.8.8:80") if err != nil { return "" } defer conn.Close() localAddr := conn.LocalAddr().(*net.UDPAddr) return localAddr.IP.String() } // Obtenir IP de la passerelle (gateway) locale func getGatewayIP() string { ip, err := gateway.DiscoverGateway() if err != nil { log.Println("Erreur récupération gateway réelle :", err) return "" } return ip.String() }