wip
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}