at main 4.3 kB view raw
1package api 2 3import ( 4 "context" 5 "fmt" 6 "net/http" 7 "time" 8 9 "github.com/atscan/atscand/internal/config" 10 "github.com/atscan/atscand/internal/log" 11 "github.com/atscan/atscand/internal/plc" 12 "github.com/atscan/atscand/internal/storage" 13 "github.com/gorilla/handlers" 14 "github.com/gorilla/mux" 15) 16 17type Server struct { 18 router *mux.Router 19 server *http.Server 20 db storage.Database 21 plcBundleDir string 22 bundleManager *plc.BundleManager 23 plcIndexDIDs bool 24} 25 26func NewServer(db storage.Database, apiCfg config.APIConfig, plcCfg config.PLCConfig, bundleManager *plc.BundleManager) *Server { 27 s := &Server{ 28 router: mux.NewRouter(), 29 db: db, 30 plcBundleDir: plcCfg.BundleDir, 31 bundleManager: bundleManager, // Use provided shared instance 32 plcIndexDIDs: plcCfg.IndexDIDs, 33 } 34 35 s.setupRoutes() 36 37 // Add CORS middleware 38 corsHandler := handlers.CORS( 39 handlers.AllowedOrigins([]string{"*"}), 40 handlers.AllowedMethods([]string{"GET", "POST", "OPTIONS"}), 41 handlers.AllowedHeaders([]string{"Content-Type", "X-Requested-With"}), 42 ) 43 44 s.server = &http.Server{ 45 Addr: fmt.Sprintf("%s:%d", apiCfg.Host, apiCfg.Port), 46 Handler: corsHandler(s.router), 47 ReadTimeout: 15 * time.Second, 48 WriteTimeout: 15 * time.Second, 49 } 50 51 return s 52} 53 54func (s *Server) setupRoutes() { 55 api := s.router.PathPrefix("/api/v1").Subrouter() 56 57 // Generic endpoints (keep as-is) 58 api.HandleFunc("/endpoints", s.handleGetEndpoints).Methods("GET") 59 api.HandleFunc("/endpoints/stats", s.handleGetEndpointStats).Methods("GET") 60 api.HandleFunc("/endpoints/random", s.handleGetRandomEndpoint).Methods("GET") 61 62 //PDS-specific endpoints (virtual, created via JOINs) 63 api.HandleFunc("/pds", s.handleGetPDSList).Methods("GET") 64 api.HandleFunc("/pds/stats", s.handleGetPDSStats).Methods("GET") 65 api.HandleFunc("/pds/countries", s.handleGetCountryLeaderboard).Methods("GET") 66 api.HandleFunc("/pds/versions", s.handleGetVersionStats).Methods("GET") 67 api.HandleFunc("/pds/duplicates", s.handleGetDuplicateEndpoints).Methods("GET") 68 api.HandleFunc("/pds/{endpoint}", s.handleGetPDSDetail).Methods("GET") 69 70 // PDS repos 71 api.HandleFunc("/pds/{endpoint}/repos", s.handleGetPDSRepos).Methods("GET") 72 api.HandleFunc("/pds/{endpoint}/repos/stats", s.handleGetPDSRepoStats).Methods("GET") 73 api.HandleFunc("/pds/repos/{did}", s.handleGetDIDRepos).Methods("GET") 74 75 // Global DID routes 76 api.HandleFunc("/did/{did}", s.handleGetGlobalDID).Methods("GET") 77 api.HandleFunc("/handle/{handle}", s.handleGetDIDByHandle).Methods("GET") // NEW 78 79 // PLC Bundle routes 80 api.HandleFunc("/plc/bundles", s.handleGetPLCBundles).Methods("GET") 81 api.HandleFunc("/plc/bundles/stats", s.handleGetPLCBundleStats).Methods("GET") 82 api.HandleFunc("/plc/bundles/chain", s.handleGetChainInfo).Methods("GET") 83 api.HandleFunc("/plc/bundles/verify-chain", s.handleVerifyChain).Methods("POST") 84 api.HandleFunc("/plc/bundles/{number}", s.handleGetPLCBundle).Methods("GET") 85 api.HandleFunc("/plc/bundles/{number}/dids", s.handleGetPLCBundleDIDs).Methods("GET") 86 api.HandleFunc("/plc/bundles/{number}/download", s.handleDownloadPLCBundle).Methods("GET") 87 api.HandleFunc("/plc/bundles/{number}/labels", s.handleGetBundleLabels).Methods("GET") 88 89 // PLC history/metrics 90 api.HandleFunc("/plc/history", s.handleGetPLCHistory).Methods("GET") 91 92 // PLC Export endpoint (simulates PLC directory) 93 api.HandleFunc("/plc/export", s.handlePLCExport).Methods("GET") 94 95 // DID routes 96 api.HandleFunc("/plc/did/{did}", s.handleGetDID).Methods("GET") 97 api.HandleFunc("/plc/did/{did}/history", s.handleGetDIDHistory).Methods("GET") 98 api.HandleFunc("/plc/dids/stats", s.handleGetDIDStats).Methods("GET") 99 100 // Mempool routes 101 api.HandleFunc("/mempool/stats", s.handleGetMempoolStats).Methods("GET") 102 103 // Metrics routes 104 api.HandleFunc("/metrics/plc", s.handleGetPLCMetrics).Methods("GET") 105 106 // Debug Endpoints 107 api.HandleFunc("/debug/db/sizes", s.handleGetDBSizes).Methods("GET") 108 api.HandleFunc("/jobs", s.handleGetJobStatus).Methods("GET") 109 110 // Health check 111 s.router.HandleFunc("/health", s.handleHealth).Methods("GET") 112} 113 114func (s *Server) Start() error { 115 log.Info("API server listening on %s", s.server.Addr) 116 return s.server.ListenAndServe() 117} 118 119func (s *Server) Shutdown(ctx context.Context) error { 120 return s.server.Shutdown(ctx) 121}