11package router
22
33import (
4- "errors"
54 "net/http"
6- "strings"
7- "time"
85
96 "github.com/gin-gonic/gin"
10- "go.opentelemetry.io/otel/attribute"
11- "go.opentelemetry.io/otel/trace"
127 "go.uber.org/zap"
138 "gorm.io/gorm"
149
1510 _ "github.com/memodb-io/Acontext/docs"
1611 "github.com/memodb-io/Acontext/internal/config"
12+ "github.com/memodb-io/Acontext/internal/middleware"
1713 "github.com/memodb-io/Acontext/internal/modules/handler"
18- "github.com/memodb-io/Acontext/internal/modules/model"
1914 "github.com/memodb-io/Acontext/internal/modules/serializer"
20- "github.com/memodb-io/Acontext/internal/pkg/utils/secrets"
21- "github.com/memodb-io/Acontext/internal/pkg/utils/tokens"
22- "github.com/memodb-io/Acontext/internal/telemetry"
2315 swaggerFiles "github.com/swaggo/files"
2416 ginSwagger "github.com/swaggo/gin-swagger"
2517)
2618
27- // zapLoggerMiddleware
28- func zapLoggerMiddleware (log * zap.Logger ) gin.HandlerFunc {
29- return func (c * gin.Context ) {
30- start := time .Now ()
31- c .Next ()
32- dur := time .Since (start )
33-
34- // Use debug level for all paths except /api/*
35- path := c .Request .URL .Path
36- isAPIPath := strings .HasPrefix (path , "/api/" )
37-
38- if isAPIPath {
39- log .Sugar ().Infow ("HTTP" ,
40- "method" , c .Request .Method ,
41- "path" , path ,
42- "status" , c .Writer .Status (),
43- "latency" , dur .String (),
44- "clientIP" , c .ClientIP (),
45- )
46- } else {
47- log .Sugar ().Debugw ("HTTP" ,
48- "method" , c .Request .Method ,
49- "path" , path ,
50- "status" , c .Writer .Status (),
51- "latency" , dur .String (),
52- "clientIP" , c .ClientIP (),
53- )
54- }
55- }
56- }
57-
58- // projectAuthMiddleware
59- func projectAuthMiddleware (cfg * config.Config , db * gorm.DB ) gin.HandlerFunc {
60- return func (c * gin.Context ) {
61- auth := c .GetHeader ("Authorization" )
62- if ! strings .HasPrefix (auth , "Bearer " ) {
63- c .AbortWithStatusJSON (http .StatusUnauthorized , serializer .AuthErr ("Unauthorized" ))
64- return
65- }
66- raw := strings .TrimPrefix (auth , "Bearer " )
67-
68- secret , ok := tokens .ParseToken (raw , cfg .Root .ProjectBearerTokenPrefix )
69- if ! ok {
70- c .AbortWithStatusJSON (http .StatusUnauthorized , serializer .AuthErr ("Unauthorized" ))
71- return
72- }
73-
74- lookup := tokens .HMAC256Hex (cfg .Root .SecretPepper , secret )
75-
76- var project model.Project
77- if err := db .WithContext (c .Request .Context ()).Where (& model.Project {SecretKeyHMAC : lookup }).First (& project ).Error ; err != nil {
78- if errors .Is (err , gorm .ErrRecordNotFound ) {
79- c .AbortWithStatusJSON (http .StatusUnauthorized , serializer .AuthErr ("Unauthorized" ))
80- return
81- }
82- c .AbortWithStatusJSON (http .StatusInternalServerError , serializer .DBErr ("" , err ))
83- return
84- }
85-
86- pass , err := secrets .VerifySecret (secret , cfg .Root .SecretPepper , project .SecretKeyHashPHC )
87- if err != nil || ! pass {
88- c .AbortWithStatusJSON (http .StatusUnauthorized , serializer .AuthErr ("Unauthorized" ))
89- return
90- }
91-
92- // Set project_id attribute on the current span for telemetry filtering
93- span := trace .SpanFromContext (c .Request .Context ())
94- if span .SpanContext ().IsValid () {
95- span .SetAttributes (attribute .String ("project_id" , project .ID .String ()))
96- }
97-
98- c .Set ("project" , & project )
99- c .Next ()
100- }
101- }
102-
10319type RouterDeps struct {
10420 Config * config.Config
10521 DB * gorm.DB
@@ -122,12 +38,12 @@ func NewRouter(d RouterDeps) *gin.Engine {
12238
12339 // Add OpenTelemetry middleware if enabled (using configuration system)
12440 if d .Config .Telemetry .Enabled && d .Config .Telemetry .OtlpEndpoint != "" {
125- r .Use (telemetry . GinMiddleware (d .Config .App .Name ))
41+ r .Use (middleware . OtelTracing (d .Config .App .Name ))
12642 // Add trace ID to response header
127- r .Use (telemetry . TraceIDMiddleware ())
43+ r .Use (middleware . TraceID ())
12844 }
12945
130- r .Use (zapLoggerMiddleware (d .Log ))
46+ r .Use (middleware . ZapLogger (d .Log ))
13147
13248 // health
13349 r .GET ("/health" , func (c * gin.Context ) { c .JSON (http .StatusOK , serializer.Response {Msg : "ok" }) })
@@ -140,7 +56,7 @@ func NewRouter(d RouterDeps) *gin.Engine {
14056
14157 v1 := r .Group ("/api/v1" )
14258 {
143- v1 .Use (projectAuthMiddleware (d .Config , d .DB ))
59+ v1 .Use (middleware . ProjectAuth (d .Config , d .DB ))
14460
14561 // ping endpoint
14662 v1 .GET ("/ping" , func (c * gin.Context ) { c .JSON (http .StatusOK , serializer.Response {Msg : "pong" }) })
0 commit comments