This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

1package main 2 3import ( 4 "context" 5 "encoding/json" 6 "fmt" 7 "log" 8 "net/http" 9 "strconv" 10 "time" 11 12 "github.com/bluesky-social/indigo/atproto/identity" 13 "github.com/prometheus/client_golang/prometheus" 14 "github.com/prometheus/client_golang/prometheus/promhttp" 15 "github.com/sourcegraph/zoekt" 16 "tangled.org/core/repoident" 17) 18 19type IndexServer struct { 20 cfg *Config 21 dir identity.Directory 22 queue *Queue 23} 24 25func NewIndexServer(cfg *Config) *IndexServer { 26 return &IndexServer{ 27 cfg: cfg, 28 dir: baseDir(cfg.PlcUrl), 29 queue: NewQueue(cfg.IndexQueueSize), 30 } 31} 32 33func (s *IndexServer) Run(ctx context.Context) { 34 // // Start a goroutine which updates the queue with commits to index. 35 // go func() { 36 // }() 37 38 for range s.cfg.IndexConcurrency { 39 go s.processQueue(ctx) 40 } 41 42 mux := http.NewServeMux() 43 mux.HandleFunc("/", s.handleHealth) 44 mux.HandleFunc("/debug/metrics", s.handleMetrics) 45 mux.HandleFunc("/debug/queue", s.handleDebugQueue) 46 mux.HandleFunc("/admin/forceIndex", s.handleForceIndex) 47 mux.HandleFunc("/admin/enqueueIndex", s.handleEnqueueIndex) 48 if err := http.ListenAndServe(s.cfg.Listen, mux); err != nil { 49 log.Fatal(err) 50 } 51} 52 53func (s *IndexServer) handleHealth(w http.ResponseWriter, r *http.Request) { 54 // Nothing to do. Just return 200 55} 56 57func (s *IndexServer) handleMetrics(w http.ResponseWriter, r *http.Request) { 58 promhttp.Handler().ServeHTTP(w, r) 59} 60 61type indexRequest struct { 62 Repo repoident.RepoDid `json:"repo"` 63 Branches []zoekt.RepositoryBranch `json:"branches"` 64} 65 66func (s *IndexServer) handleDebugQueue(w http.ResponseWriter, r *http.Request) { 67 for _, req := range s.queue.Snapshot() { 68 fmt.Fprintln(w, req.Repo) 69 for _, b := range req.Branches { 70 fmt.Fprintf(w, "\t%s:\t%s\n", b.Name, b.Version) 71 } 72 } 73} 74 75func (s *IndexServer) handleEnqueueIndex(w http.ResponseWriter, r *http.Request) { 76 route := "enqueueIndex" 77 dec := json.NewDecoder(r.Body) 78 dec.DisallowUnknownFields() 79 var req indexRequest 80 if err := dec.Decode(&req); err != nil { 81 log.Printf("Error decoding index request: %v", err) 82 http.Error(w, "JSON parser error", http.StatusBadRequest) 83 s.incrementRequestsTotal(r.Method, route, http.StatusBadRequest) 84 return 85 } 86 87 if !s.queue.Enqueue(req) { 88 // queue full: reject so the producer retries later 89 http.Error(w, "index queue full", http.StatusServiceUnavailable) 90 s.incrementRequestsTotal(r.Method, route, http.StatusServiceUnavailable) 91 return 92 } 93 94 w.WriteHeader(http.StatusAccepted) 95 s.incrementRequestsTotal(r.Method, route, http.StatusAccepted) 96} 97 98func (s *IndexServer) handleForceIndex(w http.ResponseWriter, r *http.Request) { 99 route := "index" 100 dec := json.NewDecoder(r.Body) 101 dec.DisallowUnknownFields() 102 var req indexRequest 103 if err := dec.Decode(&req); err != nil { 104 log.Printf("Error decoding index request: %v", err) 105 http.Error(w, "JSON parser error", http.StatusBadRequest) 106 return 107 } 108 109 if err := gitIndex(r.Context(), s.cfg, s.dir, req); err != nil { 110 s.respondWithError(w, r.Method, route, err) 111 return 112 } 113 114 w.Header().Set("Content-Type", "application/json") 115 _ = json.NewEncoder(w).Encode(map[string]any{ 116 "success": true, 117 }) 118 119 s.incrementRequestsTotal(r.Method, route, http.StatusOK) 120} 121 122func (s *IndexServer) respondWithError(w http.ResponseWriter, method, route string, err error) { 123 responseCode := http.StatusInternalServerError 124 125 log.Print(err) 126 s.incrementRequestsTotal(method, route, responseCode) 127 128 w.Header().Set("Content-Type", "application/json") 129 w.WriteHeader(responseCode) 130 response := map[string]any{ 131 "Success": false, 132 "Error": err.Error(), 133 } 134 135 _ = json.NewEncoder(w).Encode(response) 136} 137 138func (s *IndexServer) incrementRequestsTotal(method, route string, responseCode int) { 139 requestsTotal.With(prometheus.Labels{"code": strconv.Itoa(responseCode), "method": method, "route": route}).Inc() 140} 141 142func (s *IndexServer) processQueue(ctx context.Context) { 143 for { 144 select { 145 case <-ctx.Done(): 146 return 147 default: 148 } 149 150 req, ok := s.queue.Pop() 151 if !ok { 152 time.Sleep(time.Second) 153 continue 154 } 155 156 if err := gitIndex(ctx, s.cfg, s.dir, req); err != nil { 157 log.Printf("indexing repo %s failed: %v", req.Repo, err) 158 } 159 } 160}