@@ -9,54 +9,41 @@ import (
99 "github.com/btouchard/shm/internal/services/badge"
1010)
1111
12- // BadgeInstances generates a badge showing the number of active instances.
13- // GET /badge/{app-slug}/instances
1412func (h * Handlers ) BadgeInstances (w http.ResponseWriter , r * http.Request ) {
15- // Extract app slug from path
1613 appSlug := extractSlugFromPath (r .URL .Path , "/badge/" , "/instances" )
1714 if appSlug == "" {
1815 renderErrorBadge (w , "invalid slug" )
1916 return
2017 }
2118
22- // Get active instances count
2319 count , err := h .dashboard .GetActiveInstancesCount (r .Context (), appSlug )
2420 if err != nil {
2521 h .logger .Warn ("failed to get instances count" , "slug" , appSlug , "error" , err )
2622 renderErrorBadge (w , "error" )
2723 return
2824 }
2925
30- // Determine color based on count
3126 color := badge .GetInstancesColor (count )
32-
33- // Allow custom color via query param
3427 if customColor := r .URL .Query ().Get ("color" ); customColor != "" {
3528 color = "#" + strings .TrimPrefix (customColor , "#" )
3629 }
3730
38- // Allow custom label
3931 label := r .URL .Query ().Get ("label" )
4032 if label == "" {
4133 label = "instances"
4234 }
4335
44- // Generate badge
4536 b := badge .NewBadge (label , badge .FormatNumber (float64 (count )), color )
4637 renderSVGBadge (w , b .ToSVG ())
4738}
4839
49- // BadgeVersion generates a badge showing the most used version.
50- // GET /badge/{app-slug}/version
5140func (h * Handlers ) BadgeVersion (w http.ResponseWriter , r * http.Request ) {
52- // Extract app slug from path
5341 appSlug := extractSlugFromPath (r .URL .Path , "/badge/" , "/version" )
5442 if appSlug == "" {
5543 renderErrorBadge (w , "invalid slug" )
5644 return
5745 }
5846
59- // Get most used version
6047 version , err := h .dashboard .GetMostUsedVersion (r .Context (), appSlug )
6148 if err != nil {
6249 h .logger .Warn ("failed to get version" , "slug" , appSlug , "error" , err )
@@ -68,28 +55,21 @@ func (h *Handlers) BadgeVersion(w http.ResponseWriter, r *http.Request) {
6855 version = "no data"
6956 }
7057
71- // Allow custom color via query param
7258 color := badge .ColorPurple
7359 if customColor := r .URL .Query ().Get ("color" ); customColor != "" {
7460 color = "#" + strings .TrimPrefix (customColor , "#" )
7561 }
7662
77- // Allow custom label
7863 label := r .URL .Query ().Get ("label" )
7964 if label == "" {
8065 label = "version"
8166 }
8267
83- // Generate badge
8468 b := badge .NewBadge (label , version , color )
8569 renderSVGBadge (w , b .ToSVG ())
8670}
8771
88- // BadgeMetric generates a badge showing an aggregated metric value.
89- // GET /badge/{app-slug}/metric/{metric-name}
9072func (h * Handlers ) BadgeMetric (w http.ResponseWriter , r * http.Request ) {
91- // Extract app slug and metric name from path
92- // Path format: /badge/{slug}/metric/{name}
9373 parts := strings .Split (strings .TrimPrefix (r .URL .Path , "/badge/" ), "/" )
9474 if len (parts ) < 3 || parts [1 ] != "metric" {
9575 renderErrorBadge (w , "invalid path" )
@@ -104,96 +84,74 @@ func (h *Handlers) BadgeMetric(w http.ResponseWriter, r *http.Request) {
10484 return
10585 }
10686
107- // Get aggregated metric
10887 value , err := h .dashboard .GetAggregatedMetric (r .Context (), appSlug , metricName )
10988 if err != nil {
11089 h .logger .Warn ("failed to get metric" , "slug" , appSlug , "metric" , metricName , "error" , err )
11190 renderErrorBadge (w , "error" )
11291 return
11392 }
11493
115- // Determine color based on value
11694 color := badge .GetMetricColor (value )
117-
118- // Allow custom color via query param
11995 if customColor := r .URL .Query ().Get ("color" ); customColor != "" {
12096 color = "#" + strings .TrimPrefix (customColor , "#" )
12197 }
12298
123- // Allow custom label
12499 label := r .URL .Query ().Get ("label" )
125100 if label == "" {
126101 label = metricName
127102 }
128103
129- // Generate badge
130104 b := badge .NewBadge (label , badge .FormatNumber (value ), color )
131105 renderSVGBadge (w , b .ToSVG ())
132106}
133107
134- // BadgeCombined generates a combined badge showing metric value and instance count.
135- // GET /badge/{app-slug}/combined?metric=users_count
136108func (h * Handlers ) BadgeCombined (w http.ResponseWriter , r * http.Request ) {
137- // Extract app slug from path
138109 appSlug := extractSlugFromPath (r .URL .Path , "/badge/" , "/combined" )
139110 if appSlug == "" {
140111 renderErrorBadge (w , "invalid slug" )
141112 return
142113 }
143114
144- // Get metric name from query param (default: users_count)
145115 metricName := r .URL .Query ().Get ("metric" )
146116 if metricName == "" {
147117 metricName = "users_count"
148118 }
149119
150- // Get combined stats
151120 metricValue , instanceCount , err := h .dashboard .GetCombinedStats (r .Context (), appSlug , metricName )
152121 if err != nil {
153122 h .logger .Warn ("failed to get combined stats" , "slug" , appSlug , "metric" , metricName , "error" , err )
154123 renderErrorBadge (w , "error" )
155124 return
156125 }
157126
158- // Allow custom color
159127 color := badge .ColorIndigo
160128 if customColor := r .URL .Query ().Get ("color" ); customColor != "" {
161129 color = "#" + strings .TrimPrefix (customColor , "#" )
162130 }
163131
164- // Allow custom label
165132 label := r .URL .Query ().Get ("label" )
166133 if label == "" {
167134 label = "adoption"
168135 }
169136
170- // Format compact: "1.2k / 42"
171137 value := badge .FormatNumber (metricValue ) + " / " + badge .FormatNumber (float64 (instanceCount ))
172-
173- // Generate badge
174138 b := badge .NewBadge (label , value , color )
175139 renderSVGBadge (w , b .ToSVG ())
176140}
177141
178- // Helper functions
179-
180- // extractSlugFromPath extracts the app slug from a badge path.
181- // Example: /badge/my-app/instances -> "my-app"
182142func extractSlugFromPath (path , prefix , suffix string ) string {
183143 s := strings .TrimPrefix (path , prefix )
184144 s = strings .TrimSuffix (s , suffix )
185145 return s
186146}
187147
188- // renderSVGBadge writes an SVG badge to the response with proper headers.
189148func renderSVGBadge (w http.ResponseWriter , svg string ) {
190149 w .Header ().Set ("Content-Type" , "image/svg+xml;charset=utf-8" )
191- w .Header ().Set ("Cache-Control" , "public, max-age=300" ) // 5 minutes cache
150+ w .Header ().Set ("Cache-Control" , "public, max-age=300" )
192151 w .WriteHeader (http .StatusOK )
193152 _ , _ = w .Write ([]byte (svg ))
194153}
195154
196- // renderErrorBadge renders an error badge.
197155func renderErrorBadge (w http.ResponseWriter , message string ) {
198156 b := badge .NewBadge ("error" , message , badge .ColorRed )
199157 renderSVGBadge (w , b .ToSVG ())
0 commit comments