diff --git a/.gitignore b/.gitignore index 43583ba..42db729 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ -.env +**/.env game diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..8ebeeed --- /dev/null +++ b/Dockerfile @@ -0,0 +1,7 @@ +FROM docker.io/library/debian:13-slim + +ADD game /game +WORKDIR / + +ENTRYPOINT ["/game"] +CMD ["serve", "backend"] diff --git a/Makefile b/Makefile index a63e5fb..6f7642d 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,15 @@ -.PHONY: all install clean swagger +.PHONY: all install clean swagger docker SWAG ?= ~/go/bin/swag TARGET := $(shell find . -type f -name '*.go') -all: swagger install +all: swagger docker install -install: game +docker: game + docker compose up -d --force-recreate --build backend + +install: CGO_ENABLED=0 go install game: $(TARGET) diff --git a/backend/docs/docs.go b/backend/docs/docs.go index 9ef356d..2e72c0e 100644 --- a/backend/docs/docs.go +++ b/backend/docs/docs.go @@ -1,19 +1,96 @@ -// Code generated by swaggo/swag. DO NOT EDIT. - +// Package docs Code generated by swaggo/swag. DO NOT EDIT package docs -import "github.com/swaggo/swag/v2" +import "github.com/swaggo/swag" const docTemplate = `{ - "schemes": {{ marshal .Schemes }},"swagger":"2.0","info":{"description":"{{escape .Description}}","title":"{{.Title}}","contact":{},"license":{"name":"0BSD"},"version":"{{.Version}}"},"host":"{{.Host}}","basePath":"{{.BasePath}}","paths":{}}` + "schemes": {{ marshal .Schemes }}, + "swagger": "2.0", + "info": { + "description": "{{escape .Description}}", + "title": "{{.Title}}", + "contact": {}, + "license": { + "name": "0BSD" + }, + "version": "{{.Version}}" + }, + "host": "{{.Host}}", + "basePath": "{{.BasePath}}", + "paths": { + "/api/user": { + "get": { + "consumes": [ + "application/json" + ], + "parameters": [ + { + "type": "string", + "description": "Username to be queried", + "name": "username", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/auth/register": { + "post": { + "consumes": [ + "application/json" + ], + "parameters": [ + { + "description": "query params", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/models.User" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + } + }, + "definitions": { + "models.User": { + "type": "object", + "properties": { + "password": { + "type": "string" + }, + "username": { + "type": "string" + } + } + } + } +}` // SwaggerInfo holds exported Swagger Info so clients can modify it var SwaggerInfo = &swag.Spec{ - Version: "2.0", + Version: "0.0.1-alpha", Host: "", BasePath: "/", Schemes: []string{}, - Title: "NASAOJ v3", + Title: "Intro. to Network Programming Game", Description: "", InfoInstanceName: "swagger", SwaggerTemplate: docTemplate, diff --git a/backend/docs/swagger.json b/backend/docs/swagger.json index 182035e..dd4a560 100644 --- a/backend/docs/swagger.json +++ b/backend/docs/swagger.json @@ -1 +1,77 @@ -{"swagger":"2.0","info":{"title":"NASAOJ v3","contact":{},"license":{"name":"0BSD"},"version":"2.0"},"basePath":"/","paths":{}} \ No newline at end of file +{ + "swagger": "2.0", + "info": { + "title": "Intro. to Network Programming Game", + "contact": {}, + "license": { + "name": "0BSD" + }, + "version": "0.0.1-alpha" + }, + "basePath": "/", + "paths": { + "/api/user": { + "get": { + "consumes": [ + "application/json" + ], + "parameters": [ + { + "type": "string", + "description": "Username to be queried", + "name": "username", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/auth/register": { + "post": { + "consumes": [ + "application/json" + ], + "parameters": [ + { + "description": "query params", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/models.User" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + } + }, + "definitions": { + "models.User": { + "type": "object", + "properties": { + "password": { + "type": "string" + }, + "username": { + "type": "string" + } + } + } + } +} \ No newline at end of file diff --git a/backend/docs/swagger.yaml b/backend/docs/swagger.yaml index 3a421b0..08a8c7a 100644 --- a/backend/docs/swagger.yaml +++ b/backend/docs/swagger.yaml @@ -1,9 +1,48 @@ basePath: / +definitions: + models.User: + properties: + password: + type: string + username: + type: string + type: object info: contact: {} license: name: 0BSD - title: NASAOJ v3 - version: "2.0" -paths: {} + title: Intro. to Network Programming Game + version: 0.0.1-alpha +paths: + /api/user: + get: + consumes: + - application/json + parameters: + - description: Username to be queried + in: query + name: username + required: true + type: string + responses: + "200": + description: OK + "400": + description: Bad Request + /auth/register: + post: + consumes: + - application/json + parameters: + - description: query params + in: body + name: request + required: true + schema: + $ref: '#/definitions/models.User' + responses: + "200": + description: OK + "400": + description: Bad Request swagger: "2.0" diff --git a/backend/handlers/api/getUser.go b/backend/handlers/api/getUser.go new file mode 100644 index 0000000..5dfa98d --- /dev/null +++ b/backend/handlers/api/getUser.go @@ -0,0 +1,55 @@ +package api + +import ( + "database/sql" + "net/http" + + "gitea.konchin.com/ytshih/inp2025/game/backend/middlewares" + "github.com/uptrace/bunrouter" +) + +type GetUserOutput struct { + Username string `json:"username"` +} + +// GetUser +// +// @Accept json +// @Param username query string true "Username to be queried" +// @Success 200 +// @Failure 400 +// @Router /api/user [get] +func (self *Handlers) GetUser( + w http.ResponseWriter, + req bunrouter.Request, +) error { + ctx := req.Context() + + username := req.URL.Query().Get("username") + if username == "" { + return middlewares.HTTPError{ + StatusCode: http.StatusBadRequest, + Message: "must provide username", + } + } + + user, err := self.db.GetUser(ctx, username) + if err != nil { + if err == sql.ErrNoRows { + return middlewares.HTTPError{ + StatusCode: http.StatusNotFound, + Message: "user not exist", + OriginError: err, + } + } + return middlewares.HTTPError{ + StatusCode: http.StatusInternalServerError, + Message: "failed to get user", + OriginError: err, + } + } + + return bunrouter.JSON(w, GetUserOutput{ + Username: user.Username, + }) +} diff --git a/backend/handlers/api/handlers.go b/backend/handlers/api/handlers.go new file mode 100644 index 0000000..ee7da76 --- /dev/null +++ b/backend/handlers/api/handlers.go @@ -0,0 +1,13 @@ +package api + +import ( + "gitea.konchin.com/ytshih/inp2025/game/interfaces" +) + +type Handlers struct { + db interfaces.Database +} + +func NewHandlers(db interfaces.Database) *Handlers { + return &Handlers{db: db} +} diff --git a/backend/handlers/auth/getLogin.go b/backend/handlers/auth/getLogin.go index 8832b06..98a7137 100644 --- a/backend/handlers/auth/getLogin.go +++ b/backend/handlers/auth/getLogin.go @@ -1 +1,36 @@ package auth + +import ( + "net/http" + + "gitea.konchin.com/ytshih/inp2025/game/backend/middlewares" + "gitea.konchin.com/ytshih/inp2025/game/models" + "gitea.konchin.com/ytshih/inp2025/game/types" + "gitea.konchin.com/ytshih/inp2025/game/utils" + "github.com/uptrace/bunrouter" +) + +func (self *Handlers) GetLogin( + w http.ResponseWriter, + req bunrouter.Request, +) error { + ctx := req.Context() + user, ok := ctx.Value(types.User("")).(models.User) + if !ok { + return middlewares.HTTPError{ + StatusCode: http.StatusUnauthorized, + Message: "user not found", + } + } + + err := self.db.InsertUserStatus(ctx, + models.UserStatus{Username: user.Username}) + if err != nil { + return middlewares.HTTPError{ + StatusCode: http.StatusInternalServerError, + Message: "failed to update user status", + } + } + + return utils.Success(w) +} diff --git a/backend/handlers/auth/handlers.go b/backend/handlers/auth/handlers.go new file mode 100644 index 0000000..30c232f --- /dev/null +++ b/backend/handlers/auth/handlers.go @@ -0,0 +1,13 @@ +package auth + +import ( + "gitea.konchin.com/ytshih/inp2025/game/interfaces" +) + +type Handlers struct { + db interfaces.Database +} + +func NewHandlers(db interfaces.Database) *Handlers { + return &Handlers{db: db} +} diff --git a/backend/handlers/auth/postRegister.go b/backend/handlers/auth/postRegister.go new file mode 100644 index 0000000..7206fca --- /dev/null +++ b/backend/handlers/auth/postRegister.go @@ -0,0 +1,62 @@ +package auth + +import ( + "encoding/json" + "io" + "net/http" + + "gitea.konchin.com/ytshih/inp2025/game/backend/middlewares" + "gitea.konchin.com/ytshih/inp2025/game/models" + "gitea.konchin.com/ytshih/inp2025/game/types" + "gitea.konchin.com/ytshih/inp2025/game/utils" + "github.com/uptrace/bunrouter" +) + +// PostRegister +// +// @Accept json +// @Param request body models.User true "query params" +// @Success 200 +// @Failure 400 +// @Router /auth/register [post] +func (self *Handlers) PostRegister( + w http.ResponseWriter, + req bunrouter.Request, +) error { + ctx := req.Context() + + b, err := io.ReadAll(req.Body) + if err != nil { + return middlewares.HTTPError{ + StatusCode: http.StatusBadRequest, + Message: "failed to read body payload", + OriginError: err, + } + } + + var user models.User + if err := json.Unmarshal(b, &user); err != nil { + return middlewares.HTTPError{ + StatusCode: http.StatusBadRequest, + Message: "failed to unmarshal json into user", + OriginError: err, + } + } + + if err := self.db.InsertUser(ctx, user); err != nil { + if err == types.UsernameConflictError { + return middlewares.HTTPError{ + StatusCode: http.StatusBadRequest, + Message: "username already exist", + OriginError: err, + } + } + return middlewares.HTTPError{ + StatusCode: http.StatusInternalServerError, + Message: "failed to insert user", + OriginError: err, + } + } + + return utils.Success(w) +} diff --git a/backend/middlewares/accessLog.go b/backend/middlewares/accessLog.go index c2449dc..7243584 100644 --- a/backend/middlewares/accessLog.go +++ b/backend/middlewares/accessLog.go @@ -7,7 +7,9 @@ import ( "github.com/uptrace/bunrouter" ) -func AccessLog(next bunrouter.HandlerFunc) bunrouter.HandlerFunc { +func (self *Handlers) AccessLog( + next bunrouter.HandlerFunc, +) bunrouter.HandlerFunc { return func(w http.ResponseWriter, req bunrouter.Request) error { tracing.Logger.Ctx(req.Context()). Info(req.Method + " " + req.Params().Route()) diff --git a/backend/middlewares/auth.go b/backend/middlewares/auth.go new file mode 100644 index 0000000..025edf5 --- /dev/null +++ b/backend/middlewares/auth.go @@ -0,0 +1,50 @@ +package middlewares + +import ( + "context" + "net/http" + + "gitea.konchin.com/ytshih/inp2025/game/models" + "gitea.konchin.com/ytshih/inp2025/game/types" + "github.com/uptrace/bunrouter" +) + +func (self *Handlers) Auth( + next bunrouter.HandlerFunc, +) bunrouter.HandlerFunc { + return func(w http.ResponseWriter, req bunrouter.Request) error { + ctx := req.Context() + + username, password, ok := req.BasicAuth() + if !ok { + return HTTPError{ + StatusCode: http.StatusBadRequest, + Message: "basic auth wrong format", + } + } + + dbUser, err := self.db.GetUser(ctx, username) + if err != nil { + return HTTPError{ + StatusCode: http.StatusBadRequest, + Message: "username not exist", + OriginError: err, + } + } + + if dbUser.Password != password { + return HTTPError{ + StatusCode: http.StatusUnauthorized, + Message: "password incorrect", + } + } + + user := models.User{ + Username: username, + Password: password, + } + + ctx = context.WithValue(ctx, types.User(""), user) + return next(w, req.WithContext(ctx)) + } +} diff --git a/backend/middlewares/bunrouterOtel.go b/backend/middlewares/bunrouterOtel.go index 687f1fc..b0e57c7 100644 --- a/backend/middlewares/bunrouterOtel.go +++ b/backend/middlewares/bunrouterOtel.go @@ -10,7 +10,9 @@ import ( "go.opentelemetry.io/otel/trace" ) -func BunrouterOtel(next bunrouter.HandlerFunc) bunrouter.HandlerFunc { +func (self *Handlers) BunrouterOtel( + next bunrouter.HandlerFunc, +) bunrouter.HandlerFunc { return func(w http.ResponseWriter, req bunrouter.Request) error { span := trace.SpanFromContext(req.Context()) if !span.IsRecording() { diff --git a/backend/middlewares/errorHandler.go b/backend/middlewares/errorHandler.go index d47973a..5fb99f5 100644 --- a/backend/middlewares/errorHandler.go +++ b/backend/middlewares/errorHandler.go @@ -15,8 +15,6 @@ type HTTPError struct { StatusCode int `json:"code"` Message string `json:"message"` OriginError error `json:"-"` - - TraceID string `json:"traceId"` } func (e HTTPError) Error() string { @@ -31,7 +29,9 @@ func NewHTTPError(err error) HTTPError { } } -func ErrorHandler(next bunrouter.HandlerFunc) bunrouter.HandlerFunc { +func (self *Handlers) ErrorHandler( + next bunrouter.HandlerFunc, +) bunrouter.HandlerFunc { return func(w http.ResponseWriter, req bunrouter.Request) error { err := next(w, req) ctx := req.Context() @@ -53,7 +53,6 @@ func ErrorHandler(next bunrouter.HandlerFunc) bunrouter.HandlerFunc { // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status span := trace.SpanFromContext(ctx) - httpErr.TraceID = span.SpanContext().TraceID().String() span.SetAttributes( attribute.Int("http.response.status_code", httpErr.StatusCode), ) diff --git a/backend/middlewares/handler.go b/backend/middlewares/handler.go new file mode 100644 index 0000000..71e2d46 --- /dev/null +++ b/backend/middlewares/handler.go @@ -0,0 +1,11 @@ +package middlewares + +import "gitea.konchin.com/ytshih/inp2025/game/interfaces" + +type Handlers struct { + db interfaces.Database +} + +func NewHandlers(db interfaces.Database) *Handlers { + return &Handlers{db: db} +} diff --git a/cmd/play/root.go b/cmd/play/root.go new file mode 100644 index 0000000..cebaf07 --- /dev/null +++ b/cmd/play/root.go @@ -0,0 +1,36 @@ +package play + +import ( + "gitea.konchin.com/ytshih/inp2025/game/plays" + tea "github.com/charmbracelet/bubbletea" + "github.com/go-resty/resty/v2" + "github.com/spf13/cobra" +) + +var RootCmd = &cobra.Command{ + Use: "play", + Short: "Play game", + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + client := resty.New(). + SetBaseURL(args[0]) + + queue := []*tea.Program{} + queue = append(queue, + tea.NewProgram(plays.NewLanding(plays.NewBase(client)))) + + for len(queue) > 0 { + program := queue[0] + queue = queue[1:] + + res, err := program.Run() + if err != nil { + panic(err) + } + err = res.(plays.Next).Next(&queue) + if err != nil { + panic(err) + } + } + }, +} diff --git a/cmd/root.go b/cmd/root.go index cdeed9c..58f2866 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -3,7 +3,9 @@ package cmd import ( "strings" + "gitea.konchin.com/ytshih/inp2025/game/cmd/play" "gitea.konchin.com/ytshih/inp2025/game/cmd/serve" + "gitea.konchin.com/ytshih/inp2025/game/utils" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -12,10 +14,12 @@ var RootCmd = &cobra.Command{ Use: "game", Short: "Game for Intro. to Network Programming 2025", PersistentPreRun: func(cmd *cobra.Command, args []string) { + ctx := cmd.Context() viper.AutomaticEnv() - viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_")) + viper.SetEnvKeyReplacer(strings.NewReplacer("_", "-")) viper.BindPFlags(cmd.PersistentFlags()) viper.BindPFlags(cmd.Flags()) + utils.ReadConfig(ctx) }, } @@ -23,4 +27,5 @@ func init() { cobra.EnableTraverseRunHooks = true RootCmd.AddCommand(serve.RootCmd) + RootCmd.AddCommand(play.RootCmd) } diff --git a/cmd/serve/backend.go b/cmd/serve/backend.go index 286a40b..858025c 100644 --- a/cmd/serve/backend.go +++ b/cmd/serve/backend.go @@ -1,23 +1,31 @@ package serve import ( + "database/sql" "log" "net/http" "github.com/spf13/cobra" "github.com/spf13/viper" httpSwagger "github.com/swaggo/http-swagger" + "github.com/uptrace/bun" + "github.com/uptrace/bun/dialect/sqlitedialect" + "github.com/uptrace/bun/driver/sqliteshim" + "github.com/uptrace/bun/extra/bunotel" "github.com/uptrace/bunrouter" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" "go.uber.org/zap" _ "gitea.konchin.com/ytshih/inp2025/game/backend/docs" + "gitea.konchin.com/ytshih/inp2025/game/backend/handlers/auth" "gitea.konchin.com/ytshih/inp2025/game/backend/middlewares" + "gitea.konchin.com/ytshih/inp2025/game/implements" "gitea.konchin.com/ytshih/inp2025/game/tracing" + "gitea.konchin.com/ytshih/inp2025/game/utils" ) -// @title NASAOJ v3 -// @version 2.0 +// @title Intro. to Network Programming Game +// @version 0.0.1-alpha // @license.name 0BSD // @BasePath / var backendCmd = &cobra.Command{ @@ -27,22 +35,55 @@ var backendCmd = &cobra.Command{ ctx := cmd.Context() tracing.InitTracer("game backend") - router := bunrouter.New() - backend := router.NewGroup(""). - Use(middlewares.ErrorHandler). - Use(middlewares.BunrouterOtel). - Use(middlewares.AccessLog) - tracing.Logger.Ctx(ctx). - Debug("nmsl", - zap.Bool("swagger", viper.GetBool("swagger"))) + Debug("connect to sql", + zap.String("sql.url", + "file:"+viper.GetString("sqlite-file")+"?cache=shared&mode=rwc")) + sqldb, err := sql.Open(sqliteshim.ShimName, + "file:"+viper.GetString("sqlite-file")+"?cache=shared&mode=rwc") + if err != nil { + tracing.Logger.Ctx(ctx). + Panic("failed to init sqlite", + zap.Error(err)) + panic(err) + } + bunDB := bun.NewDB(sqldb, sqlitedialect.New()) + bunDB.AddQueryHook(bunotel.NewQueryHook(bunotel.WithDBName("sqlite"))) + if err := utils.InitDB(ctx, bunDB); err != nil { + tracing.Logger.Ctx(ctx). + Panic("failed to init db schema", + zap.Error(err)) + panic(err) + } + + db := implements.NewBunDatabase(bunDB) + authHandlers := auth.NewHandlers(db) + // apiHandlers := api.NewHandlers(db) + middlewareHandlers := middlewares.NewHandlers(db) + + router := bunrouter.New() if viper.GetBool("swagger") { - backend.GET("/swagger/*any", + router.GET("/swagger/*any", bunrouter.HTTPHandlerFunc( httpSwagger.Handler())) } + backend := router.NewGroup(""). + Use(middlewareHandlers.ErrorHandler). + Use(middlewareHandlers.BunrouterOtel). + Use(middlewareHandlers.AccessLog) + + authGroup := backend.NewGroup("/auth") + authGroup.GET("/login", + middlewareHandlers.Auth( + authHandlers.GetLogin)) + authGroup.POST("/register", + authHandlers.PostRegister) + + // apiGroup := backend.NewGroup("/api"). + // Use(middlewareHandlers.Auth) + tracing.Logger.Ctx(ctx). Info("http server up", zap.String("http.port", viper.GetString("port"))) @@ -57,4 +98,6 @@ func init() { String("port", "8080", "Port to listen on") backendCmd.Flags(). Bool("swagger", false, "Enable swagger") + backendCmd.Flags(). + String("sqlite-file", ":memory:", "File for sqlite") } diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..619921f --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,9 @@ +--- +services: + backend: + build: + context: . + env_file: ./backend/.env + ports: + - 8081:8080 + restart: unless-stopped diff --git a/go.mod b/go.mod index bafe699..6543e81 100644 --- a/go.mod +++ b/go.mod @@ -2,8 +2,36 @@ module gitea.konchin.com/ytshih/inp2025/game go 1.24.5 +require ( + github.com/spf13/cobra v1.10.1 + github.com/spf13/viper v1.20.1 + github.com/swaggo/http-swagger v1.3.4 + github.com/swaggo/swag v1.16.2 + github.com/uptrace/bun v1.2.15 + github.com/uptrace/bun/dialect/sqlitedialect v1.2.15 + github.com/uptrace/bun/driver/sqliteshim v1.2.15 + github.com/uptrace/bun/extra/bunotel v1.2.15 + github.com/uptrace/bunrouter v1.0.23 + github.com/uptrace/opentelemetry-go-extra/otelzap v0.3.2 + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 + go.opentelemetry.io/otel v1.38.0 + go.opentelemetry.io/otel/trace v1.38.0 + go.uber.org/zap v1.27.0 +) + require ( github.com/KyleBanks/depth v1.2.1 // indirect + github.com/atotto/clipboard v0.1.4 // indirect + github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect + github.com/charmbracelet/bubbles v0.21.0 // indirect + github.com/charmbracelet/bubbletea v1.3.7 // indirect + github.com/charmbracelet/colorprofile v0.3.2 // indirect + github.com/charmbracelet/lipgloss v1.1.0 // indirect + github.com/charmbracelet/x/ansi v0.10.1 // indirect + github.com/charmbracelet/x/cellbuf v0.0.13 // indirect + github.com/charmbracelet/x/term v0.2.1 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.8.0 // indirect github.com/go-logr/logr v1.4.3 // indirect @@ -12,41 +40,51 @@ require ( github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/spec v0.20.9 // indirect github.com/go-openapi/swag v0.22.3 // indirect + github.com/go-resty/resty/v2 v2.16.5 // indirect github.com/go-viper/mapstructure/v2 v2.2.1 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect + github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-localereader v0.0.1 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/mattn/go-sqlite3 v1.14.28 // indirect + github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect + github.com/muesli/cancelreader v0.2.2 // indirect + github.com/muesli/termenv v0.16.0 // indirect + github.com/ncruces/go-strftime v0.1.9 // indirect github.com/pelletier/go-toml/v2 v2.2.3 // indirect - github.com/pkg/errors v0.9.1 // indirect + github.com/puzpuzpuz/xsync/v3 v3.5.1 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + github.com/rivo/uniseg v0.4.7 // indirect github.com/sagikazarmark/locafero v0.7.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.12.0 // indirect github.com/spf13/cast v1.7.1 // indirect - github.com/spf13/cobra v1.10.1 // indirect github.com/spf13/pflag v1.0.9 // indirect - github.com/spf13/viper v1.20.1 // indirect github.com/subosito/gotenv v1.6.0 // indirect - github.com/sv-tools/openapi v0.2.1 // indirect github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe // indirect - github.com/swaggo/http-swagger v1.3.4 // indirect - github.com/swaggo/swag v1.8.1 // indirect - github.com/swaggo/swag/v2 v2.0.0-rc4 // indirect - github.com/uptrace/bunrouter v1.0.23 // indirect + github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect + github.com/uptrace/opentelemetry-go-extra/otelsql v0.3.2 // indirect github.com/uptrace/opentelemetry-go-extra/otelutil v0.3.2 // indirect - github.com/uptrace/opentelemetry-go-extra/otelzap v0.3.2 // indirect + github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect + github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect + github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 // indirect - go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/log v0.6.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect - go.opentelemetry.io/otel/trace v1.38.0 // indirect - go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.27.0 // indirect - golang.org/x/net v0.33.0 // indirect - golang.org/x/sys v0.35.0 // indirect - golang.org/x/text v0.21.0 // indirect - golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect + golang.org/x/exp v0.0.0-20250711185948-6ae5c78190dc // indirect + golang.org/x/net v0.42.0 // indirect + golang.org/x/sys v0.36.0 // indirect + golang.org/x/text v0.28.0 // indirect + golang.org/x/tools v0.35.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + modernc.org/libc v1.66.3 // indirect + modernc.org/mathutil v1.7.1 // indirect + modernc.org/memory v1.11.0 // indirect + modernc.org/sqlite v1.38.0 // indirect ) diff --git a/go.sum b/go.sum index f0be3bc..36d9a1b 100644 --- a/go.sum +++ b/go.sum @@ -1,16 +1,43 @@ github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= +github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= +github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= +github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= +github.com/charmbracelet/bubbles v0.21.0 h1:9TdC97SdRVg/1aaXNVWfFH3nnLAwOXr8Fn6u6mfQdFs= +github.com/charmbracelet/bubbles v0.21.0/go.mod h1:HF+v6QUR4HkEpz62dx7ym2xc71/KBHg+zKwJtMw+qtg= +github.com/charmbracelet/bubbletea v1.3.7 h1:FNaEEFEenOEPnZsY9MI64thl2c84MI66+1QaQbxGOl4= +github.com/charmbracelet/bubbletea v1.3.7/go.mod h1:PEOcbQCNzJ2BYUd484kHPO5g3kLO28IffOdFeI2EWus= +github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs= +github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk= +github.com/charmbracelet/colorprofile v0.3.2 h1:9J27WdztfJQVAQKX2WOlSSRB+5gaKqqITmrvb1uTIiI= +github.com/charmbracelet/colorprofile v0.3.2/go.mod h1:mTD5XzNeWHj8oqHb+S1bssQb7vIHbepiebQ2kPKVKbI= +github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY= +github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30= +github.com/charmbracelet/x/ansi v0.10.1 h1:rL3Koar5XvX0pHGfovN03f5cxLbCF2YvLeyz7D2jVDQ= +github.com/charmbracelet/x/ansi v0.10.1/go.mod h1:3RQDQ6lDnROptfpWuUVIUG64bD2g2BgntdxH0Ya5TeE= +github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8= +github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs= +github.com/charmbracelet/x/cellbuf v0.0.13 h1:/KBBKHuVRbq1lYx5BzEHBAFBP8VcQzJejZ/IA3iR28k= +github.com/charmbracelet/x/cellbuf v0.0.13/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs= +github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ= +github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= @@ -28,28 +55,67 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-resty/resty/v2 v2.16.5 h1:hBKqmWrr7uRc3euHVqmh1HTHcKn99Smr7o5spptdhTM= +github.com/go-resty/resty/v2 v2.16.5/go.mod h1:hkJtXbA2iKHzJheXYvQ8snQES5ZLGKMwQ07xAwp/fiA= github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs= +github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= +github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= +github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-sqlite3 v1.14.28 h1:ThEiQrnbtumT+QMknw63Befp/ce/nUPgBPMlRFEum7A= +github.com/mattn/go-sqlite3 v1.14.28/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= +github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= +github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= +github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc= +github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk= +github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= +github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/puzpuzpuz/xsync/v3 v3.5.1 h1:GJYJZwO6IdxN/IKbneznS6yPkVC+c3zyY/j19c++5Fg= +github.com/puzpuzpuz/xsync/v3 v3.5.1/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo= github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k= @@ -73,69 +139,92 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= -github.com/sv-tools/openapi v0.2.1 h1:ES1tMQMJFGibWndMagvdoo34T1Vllxr1Nlm5wz6b1aA= -github.com/sv-tools/openapi v0.2.1/go.mod h1:k5VuZamTw1HuiS9p2Wl5YIDWzYnHG6/FgPOSFXLAhGg= github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe h1:K8pHPVoTgxFJt1lXuIzzOX7zZhZFldJQK/CgKx9BFIc= github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe/go.mod h1:lKJPbtWzJ9JhsTN1k1gZgleJWY/cqq0psdoMmaThG3w= github.com/swaggo/http-swagger v1.3.4 h1:q7t/XLx0n15H1Q9/tk3Y9L4n210XzJF5WtnDX64a5ww= github.com/swaggo/http-swagger v1.3.4/go.mod h1:9dAh0unqMBAlbp1uE2Uc2mQTxNMU/ha4UbucIg1MFkQ= -github.com/swaggo/swag v1.8.1 h1:JuARzFX1Z1njbCGz+ZytBR15TFJwF2Q7fu8puJHhQYI= -github.com/swaggo/swag v1.8.1/go.mod h1:ugemnJsPZm/kRwFUnzBlbHRd0JY9zE1M4F+uy2pAaPQ= -github.com/swaggo/swag/v2 v2.0.0-rc4 h1:SZ8cK68gcV6cslwrJMIOqPkJELRwq4gmjvk77MrvHvY= -github.com/swaggo/swag/v2 v2.0.0-rc4/go.mod h1:Ow7Y8gF16BTCDn8YxZbyKn8FkMLRUHekv1kROJZpbvE= +github.com/swaggo/swag v1.16.2 h1:28Pp+8DkQoV+HLzLx8RGJZXNGKbFqnuvSbAAtoxiY04= +github.com/swaggo/swag v1.16.2/go.mod h1:6YzXnDcpr0767iOejs318CwYkCQqyGer6BizOg03f+E= +github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYmW5DyG0UqvY96Bu5QYsTLvCHdrgo= +github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs= +github.com/uptrace/bun v1.2.15 h1:Ut68XRBLDgp9qG9QBMa9ELWaZOmzHNdczHQdrOZbEFE= +github.com/uptrace/bun v1.2.15/go.mod h1:Eghz7NonZMiTX/Z6oKYytJ0oaMEJ/eq3kEV4vSqG038= +github.com/uptrace/bun/dialect/sqlitedialect v1.2.15 h1:7upGMVjFRB1oI78GQw6ruNLblYn5CR+kxqcbbeBBils= +github.com/uptrace/bun/dialect/sqlitedialect v1.2.15/go.mod h1:c7YIDaPNS2CU2uI1p7umFuFWkuKbDcPDDvp+DLHZnkI= +github.com/uptrace/bun/driver/sqliteshim v1.2.15 h1:M/rZJSjOPV4OmfTVnDPtL+wJmdMTqDUn8cuk5ycfABA= +github.com/uptrace/bun/driver/sqliteshim v1.2.15/go.mod h1:YqwxFyvM992XOCpGJtXyKPkgkb+aZpIIMzGbpaw1hIk= +github.com/uptrace/bun/extra/bunotel v1.2.15 h1:6KAvKRpH9BC/7n3eMXVgDYLqghHf2H3FJOvxs/yjFJM= +github.com/uptrace/bun/extra/bunotel v1.2.15/go.mod h1:qnASdcJVuoEE+13N3Gd8XHi5gwCydt2S1TccJnefH2k= github.com/uptrace/bunrouter v1.0.23 h1:Bi7NKw3uCQkcA/GUCtDNPq5LE5UdR9pe+UyWbjHB/wU= github.com/uptrace/bunrouter v1.0.23/go.mod h1:O3jAcl+5qgnF+ejhgkmbceEk0E/mqaK+ADOocdNpY8M= +github.com/uptrace/opentelemetry-go-extra/otelsql v0.3.2 h1:ZjUj9BLYf9PEqBn8W/OapxhPjVRdC6CsXTdULHsyk5c= +github.com/uptrace/opentelemetry-go-extra/otelsql v0.3.2/go.mod h1:O8bHQfyinKwTXKkiKNGmLQS7vRsqRxIQTFZpYpHK3IQ= github.com/uptrace/opentelemetry-go-extra/otelutil v0.3.2 h1:3/aHKUq7qaFMWxyQV0W2ryNgg8x8rVeKVA20KJUkfS0= github.com/uptrace/opentelemetry-go-extra/otelutil v0.3.2/go.mod h1:Zit4b8AQXaXvA68+nzmbyDzqiyFRISyw1JiD5JqUBjw= github.com/uptrace/opentelemetry-go-extra/otelzap v0.3.2 h1:cj/Z6FKTTYBnstI0Lni9PA+k2foounKIPUmj1LBwNiQ= github.com/uptrace/opentelemetry-go-extra/otelzap v0.3.2/go.mod h1:LDaXk90gKEC2nC7JH3Lpnhfu+2V7o/TsqomJJmqA39o= +github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8= +github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= +github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= +github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 h1:RbKq8BG0FI8OiXhBfcRtqqHcZcka+gU3cskNuf05R18= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0/go.mod h1:h06DGIukJOevXaj/xrNjhi/2098RZzcLTbc0jDAUbsg= -go.opentelemetry.io/otel v1.30.0 h1:F2t8sK4qf1fAmY9ua4ohFS/K+FUuOPemHUIXHtktrts= -go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDIXqP0pc= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/log v0.6.0 h1:nH66tr+dmEgW5y+F9LanGJUBYPrRgP4g2EkmPE3LeK8= go.opentelemetry.io/otel/log v0.6.0/go.mod h1:KdySypjQHhP069JX0z/t26VHwa8vSwzgaKmXtIB3fJM= -go.opentelemetry.io/otel/metric v1.30.0 h1:4xNulvn9gjzo4hjg+wzIKG7iNFEaBMX00Qd4QIZs7+w= -go.opentelemetry.io/otel/metric v1.30.0/go.mod h1:aXTfST94tswhWEb+5QjlSqG+cZlmyXy/u8jFpor3WqQ= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= -go.opentelemetry.io/otel/trace v1.30.0 h1:7UBkkYzeg3C7kQX8VAidWh2biiQbtAKjyIML8dQ9wmc= -go.opentelemetry.io/otel/trace v1.30.0/go.mod h1:5EyKqTzzmyqB9bwtCCq6pDLktPK6fmGf/Dph+8VI02o= +go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= +go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= +go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= +go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= -go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= -go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= -go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/exp v0.0.0-20250711185948-6ae5c78190dc h1:TS73t7x3KarrNd5qAipmspBDS1rkMcgVG/fS1aRb4Rc= +golang.org/x/exp v0.0.0-20250711185948-6ae5c78190dc/go.mod h1:A+z0yzpGtvnG90cToK5n2tu8UJVP2XUATh+r+sfOOOc= +golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg= +golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= -golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= -golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= +golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= +golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= +golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0= +golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= @@ -144,3 +233,29 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +modernc.org/cc/v4 v4.26.2 h1:991HMkLjJzYBIfha6ECZdjrIYz2/1ayr+FL8GN+CNzM= +modernc.org/cc/v4 v4.26.2/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= +modernc.org/ccgo/v4 v4.28.0 h1:rjznn6WWehKq7dG4JtLRKxb52Ecv8OUGah8+Z/SfpNU= +modernc.org/ccgo/v4 v4.28.0/go.mod h1:JygV3+9AV6SmPhDasu4JgquwU81XAKLd3OKTUDNOiKE= +modernc.org/fileutil v1.3.8 h1:qtzNm7ED75pd1C7WgAGcK4edm4fvhtBsEiI/0NQ54YM= +modernc.org/fileutil v1.3.8/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc= +modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI= +modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= +modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks= +modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI= +modernc.org/libc v1.66.3 h1:cfCbjTUcdsKyyZZfEUKfoHcP3S0Wkvz3jgSzByEWVCQ= +modernc.org/libc v1.66.3/go.mod h1:XD9zO8kt59cANKvHPXpx7yS2ELPheAey0vjIuZOhOU8= +modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= +modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= +modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI= +modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw= +modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8= +modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= +modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= +modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= +modernc.org/sqlite v1.38.0 h1:+4OrfPQ8pxHKuWG4md1JpR/EYAh3Md7TdejuuzE7EUI= +modernc.org/sqlite v1.38.0/go.mod h1:1Bj+yES4SVvBZ4cBOpVZ6QgesMCKpJZDq0nxYzOpmNE= +modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= +modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= +modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= +modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= diff --git a/go.work.sum b/go.work.sum index 565142e..6291828 100644 --- a/go.work.sum +++ b/go.work.sum @@ -1,72 +1,135 @@ +cel.dev/expr v0.16.1 h1:NR0+oFYzR1CqLFhTAqg3ql59G9VfN8fKq1TCHJ6gq1g= cel.dev/expr v0.16.1/go.mod h1:AsGA5zb3WruAEQeQng1RZdGEXmBj0jvMWh6l5SnNuC8= +cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE= cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U= +cloud.google.com/go/auth v0.13.0 h1:8Fu8TZy167JkW8Tj3q7dIkr2v4cndv41ouecJx0PAHs= cloud.google.com/go/auth v0.13.0/go.mod h1:COOjD9gwfKNKz+IIduatIhYJQIc0mG3H102r/EMxX6Q= +cloud.google.com/go/auth/oauth2adapt v0.2.6 h1:V6a6XDu2lTwPZWOawrAa9HUK+DB2zfJyTuciBG5hFkU= cloud.google.com/go/auth/oauth2adapt v0.2.6/go.mod h1:AlmsELtlEBnaNTL7jCj8VQFLy6mbZv0s4Q7NGBeQ5E8= +cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I= cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg= +cloud.google.com/go/iam v1.2.2 h1:ozUSofHUGf/F4tCNy/mu9tHLTaxZFLOUiKzjcgWHGIA= cloud.google.com/go/iam v1.2.2/go.mod h1:0Ys8ccaZHdI1dEUilwzqng/6ps2YB6vRsjIe00/+6JY= +cloud.google.com/go/monitoring v1.21.2 h1:FChwVtClH19E7pJ+e0xUhJPGksctZNVOk2UhMmblmdU= cloud.google.com/go/monitoring v1.21.2/go.mod h1:hS3pXvaG8KgWTSz+dAdyzPrGUYmi2Q+WFX8g2hqVEZU= +cloud.google.com/go/storage v1.49.0 h1:zenOPBOWHCnojRd9aJZAyQXBYqkJkdQS42dxL55CIMw= cloud.google.com/go/storage v1.49.0/go.mod h1:k1eHhhpLvrPjVGfo0mOUPEJ4Y2+a/Hv5PiwehZI9qGU= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0 h1:3c8yed4lgqTt+oTQ+JNMDo+F4xprBf+O/il4ZC0nRLw= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0/go.mod h1:obipzmGjfSjam60XLwGfqUkJsfiheAl+TUjG+4yzyPM= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.48.1 h1:UQ0AhxogsIRZDkElkblfnwjc3IaltCm2HUMvezQaL7s= github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.48.1/go.mod h1:jyqM3eLpJ3IbIFDTKVz2rF9T/xWGW0rIriGwnz8l9Tk= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.48.1 h1:8nn+rsCvTq9axyEh382S0PFLBeaFwNsT43IrPWzctRU= github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.48.1/go.mod h1:viRWSEhtMZqz1rhwmOVKkWl6SwmVowfL9O2YR5gI2PE= +github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= +github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/agiledragon/gomonkey/v2 v2.3.1 h1:k+UnUY0EMNYUFUAQVETGY9uUTxjMdnUkP0ARyJS1zzs= github.com/agiledragon/gomonkey/v2 v2.3.1/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY= +github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA= +github.com/bits-and-blooms/bitset v1.22.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g= github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao= +github.com/charmbracelet/x/exp/golden v0.0.0-20240806155701-69247e0abc2a/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U= +github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U= +github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78 h1:QVw89YDxXxEe+l8gU8ETbOasdwEV+avkR75ZzsVV9WI= github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= +github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0= +github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w= +github.com/envoyproxy/go-control-plane v0.13.1 h1:vPfJZCkob6yTMEgS+0TwfTUfbHjfy/6vOJ8hUWX/uXE= github.com/envoyproxy/go-control-plane v0.13.1/go.mod h1:X45hY0mufo6Fd0KW3rqsGvQMw58jvjymeCzBU3mWyHw= +github.com/envoyproxy/protoc-gen-validate v1.1.0 h1:tntQDh69XqOCOZsDz0lVJQez/2L6Uu2PdjCQwWCJ3bM= github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4= -github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM= github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw= github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA= +github.com/googleapis/gax-go/v2 v2.14.1 h1:hb0FFeiPaQskmvakKu5EbCbpntQn48jyHuvrkurSS/Q= github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/otiai10/copy v1.7.0 h1:hVoPiN+t+7d2nzzwMiDHPSOogsWAStewq3TwU05+clE= github.com/otiai10/copy v1.7.0/go.mod h1:rmRl6QPdJj6EiUqXQ/4Nn2lLXoNQjFCQbbNrxgc/t3U= +github.com/pkg/sftp v1.13.7 h1:uv+I3nNJvlKZIQGSr8JVQLNHFU9YhhNpvC14Y6KgmSM= github.com/pkg/sftp v1.13.7/go.mod h1:KMKI0t3T6hfA+lTR/ssZdunHo+uwq7ghoN09/FSu3DY= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= +github.com/santhosh-tekuri/jsonschema/v5 v5.2.0 h1:WCcC4vZDS1tYNxjWlwRJZQy28r8CMoggKnxNzxsVDMQ= github.com/santhosh-tekuri/jsonschema/v5 v5.2.0/go.mod h1:FKdcjfQW6rpZSnxxUvEA5H/cDPdvJ/SZJQLWWXWGrZ0= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= +github.com/urfave/cli/v2 v2.25.1 h1:zw8dSP7ghX0Gmm8vugrs6q9Ku0wzweqPyshy+syu9Gw= github.com/urfave/cli/v2 v2.25.1/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= +github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/contrib/detectors/gcp v1.29.0 h1:TiaiXB4DpGD3sdzNlYQxruQngn5Apwzi1X0DRhuGvDQ= go.opentelemetry.io/contrib/detectors/gcp v1.29.0/go.mod h1:GW2aWZNwR2ZxDLdv8OyC2G8zkRoQBuURgV7RPQgcPoU= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 h1:r6I7RJCN86bpD/FQwedZ0vSixDpwuWREjW9oRMsmqDc= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok= -go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/metric v1.29.0/go.mod h1:6zZLdCl2fkauYoZIOn/soQIDSWFmNSRcICarHfuhNJQ= -go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= -go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= +golang.org/x/oauth2 v0.25.0 h1:CY4y7XT9v0cRI9oupztF8AgiIu99L/ksR/Xp/6jrZ70= golang.org/x/oauth2 v0.25.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2 h1:IRJeR9r1pYWsHKTRe/IInb7lYvbBVIqOgsX/u0mbOWY= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= +golang.org/x/telemetry v0.0.0-20250710130107-8d8967aff50b/go.mod h1:4ZwOYna0/zsOKwuR5X/m0QFOJpSZvAxFfkQT+Erd9D4= +golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= +golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/tools/go/expect v0.1.0-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY= +golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated/go.mod h1:RVAQXBGNv1ib0J382/DPCRS/BPnsGebyM1Gj5VSDpG8= +google.golang.org/api v0.215.0 h1:jdYF4qnyczlEz2ReWIsosNLDuzXyvFHJtI5gcr0J7t0= google.golang.org/api v0.215.0/go.mod h1:fta3CVtuJYOEdugLNWm6WodzOS8KdFckABwN4I40hzY= +google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 h1:ToEetK57OidYuqD4Q5w+vfEnPvPpuTwedCNVohYJfNk= google.golang.org/genproto v0.0.0-20241118233622-e639e219e697/go.mod h1:JJrvXBWRZaFMxBufik1a4RpFw4HhgVtBBWQeQgUj2cc= +google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 h1:CkkIfIt50+lT6NHAVoRYEyAvQGFM7xEwXUUywFvEb3Q= google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576/go.mod h1:1R3kvZ1dtP3+4p4d3G8uJ8rFk/fWlScl38vanWACI08= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8 h1:TqExAhdPaB60Ux47Cn0oLV07rGnxZzIsaRhQaqS666A= google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA= +google.golang.org/grpc v1.67.3 h1:OgPcDAFKHnH8X3O4WcO4XUc8GRDeKsKReqbQtiCj7N8= google.golang.org/grpc v1.67.3/go.mod h1:YGaHCc6Oap+FzBJTZLBzkGSYt/cvGPFTPxkn7QfSU8s= +google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/implements/bunDatabase.go b/implements/bunDatabase.go new file mode 100644 index 0000000..a076322 --- /dev/null +++ b/implements/bunDatabase.go @@ -0,0 +1,65 @@ +package implements + +import ( + "context" + + "gitea.konchin.com/ytshih/inp2025/game/models" + "gitea.konchin.com/ytshih/inp2025/game/types" + "github.com/uptrace/bun" +) + +type BunDatabase struct { + db *bun.DB +} + +func NewBunDatabase(bunDB *bun.DB) *BunDatabase { + return &BunDatabase{db: bunDB} +} + +func (self *BunDatabase) GetUser( + ctx context.Context, + username string, +) (models.User, error) { + var ret models.User + err := self.db.NewSelect(). + Model(&ret). + Where("username = ?", username). + Scan(ctx) + return ret, err +} + +func (self *BunDatabase) InsertUser( + ctx context.Context, + user models.User, +) error { + res, err := self.db.NewInsert(). + Model(&user). + On("CONFLICT (username) DO NOTHING"). + Exec(ctx) + if err != nil { + return err + } + if cnt, err := res.RowsAffected(); err != nil || cnt == 0 { + if err != nil { + return err + } + if cnt == 0 { + return types.UsernameConflictError + } + } + return nil +} + +func (self *BunDatabase) InsertUserStatus( + ctx context.Context, + userStatus models.UserStatus, +) error { + _, err := self.db.NewInsert(). + Model(&userStatus). + On("CONFLICT (username) DO NOTHING"). + Exec(ctx) + if err != nil { + return err + } + return nil +} diff --git a/interfaces/database.go b/interfaces/database.go new file mode 100644 index 0000000..49368e5 --- /dev/null +++ b/interfaces/database.go @@ -0,0 +1,24 @@ +package interfaces + +import ( + "context" + + "gitea.konchin.com/ytshih/inp2025/game/models" +) + +type Database interface { + GetUser( + ctx context.Context, + username string, + ) (models.User, error) + + InsertUser( + ctx context.Context, + user models.User, + ) error + + InsertUserStatus( + ctx context.Context, + userStatus models.UserStatus, + ) error +} diff --git a/models/room.go b/models/room.go new file mode 100644 index 0000000..ffc20d5 --- /dev/null +++ b/models/room.go @@ -0,0 +1,4 @@ +package models + +type Room struct { +} diff --git a/models/user.go b/models/user.go new file mode 100644 index 0000000..b3eeb1f --- /dev/null +++ b/models/user.go @@ -0,0 +1,14 @@ +package models + +import "github.com/uptrace/bun" + +type User struct { + bun.BaseModel `bun:"table:user" json:"-"` + + Username string `bun:"username,pk"` + Password string `bun:"password"` +} + +type UserStatus struct { + Username string `json:"username"` +} diff --git a/plays/base.go b/plays/base.go new file mode 100644 index 0000000..4b005b6 --- /dev/null +++ b/plays/base.go @@ -0,0 +1,13 @@ +package plays + +import "github.com/go-resty/resty/v2" + +type Base struct { + client *resty.Client +} + +func NewBase(client *resty.Client) *Base { + return &Base{ + client: client, + } +} diff --git a/plays/landing.go b/plays/landing.go new file mode 100644 index 0000000..ff32e8f --- /dev/null +++ b/plays/landing.go @@ -0,0 +1,93 @@ +package plays + +import ( + "fmt" + "strings" + + tea "github.com/charmbracelet/bubbletea" +) + +var ( + landingChoices = []string{"Login", "Register"} +) + +type Landing struct { + *Base + + choice string + cursor int +} + +func NewLanding(base *Base) *Landing { + m := Landing{ + Base: base, + choice: "", + cursor: 0, + } + return &m +} + +func (m *Landing) Init() tea.Cmd { + return tea.ClearScreen +} + +func (m *Landing) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.KeyMsg: + switch msg.String() { + case "ctrl+l": + return m, tea.ClearScreen + + case "ctrl+c", "q": + return m, tea.Quit + + case "enter": + m.choice = landingChoices[m.cursor] + return m, tea.Quit + + case "tab", "shift+tab", "up", "down": + s := msg.String() + + if s == "up" || s == "shift+tab" { + m.cursor-- + } else { + m.cursor++ + } + + if m.cursor >= len(landingChoices) { + m.cursor = 0 + } else if m.cursor < 0 { + m.cursor = len(landingChoices) - 1 + } + + } + } + + return m, nil +} + +func (m *Landing) View() string { + var b strings.Builder + + for i := 0; i < len(landingChoices); i++ { + if m.cursor == i { + fmt.Fprintf(&b, "(•) %s\n", landingChoices[i]) + } else { + fmt.Fprintf(&b, "( ) %s\n", landingChoices[i]) + } + } + + return b.String() +} + +func (m *Landing) Next(queue *[]*tea.Program) error { + switch m.choice { + case "Login": + *queue = append(*queue, + tea.NewProgram(NewLogin(m.Base))) + case "Register": + *queue = append(*queue, + tea.NewProgram(NewRegister(m.Base))) + } + return nil +} diff --git a/plays/lobby.go b/plays/lobby.go new file mode 100644 index 0000000..436fc9c --- /dev/null +++ b/plays/lobby.go @@ -0,0 +1,92 @@ +package plays + +import ( + "strings" + "time" + + "gitea.konchin.com/ytshih/inp2025/game/models" + tea "github.com/charmbracelet/bubbletea" + "go.uber.org/zap" +) + +var ( + lobbyChoices = []string{""} +) + +type Lobby struct { + *Base + + choice string + cursor int + + updateCh chan struct{} + users []models.UserStatus + rooms []models.Room +} + +func NewLobby(base *Base) *Lobby { + m := Lobby{ + Base: base, + choice: "", + cursor: 0, + } + + return &m +} + +func (m *Lobby) Init() tea.Cmd { + go func() { + for { + select { + case <-m.updateCh: + return + default: + _, err := m.Base.client.R(). + SetResult(&m.users). + ForceContentType("application/json"). + Get("/api/lobby/users") + if err != nil { + zap.L(). + Error("failed to get lobby users", + zap.Error(err)) + } + _, err = m.Base.client.R(). + SetResult(&m.rooms). + ForceContentType("application/json"). + Get("/api/lobby/rooms") + if err != nil { + zap.L(). + Error("failed to get lobby rooms", + zap.Error(err)) + } + time.Sleep(time.Second) + } + } + }() + + return tea.Batch(tea.ClearScreen) +} + +func (m *Lobby) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.KeyMsg: + switch msg.String() { + case "ctrl+l": + return m, tea.ClearScreen + case "ctrl+c", "q": + return m, tea.Interrupt + } + } + return m, nil +} + +func (m *Lobby) View() string { + var b strings.Builder + + b.WriteString("nmsl") + return b.String() +} + +func (m *Lobby) Next(queue *[]*tea.Program) error { + return nil +} diff --git a/plays/login.go b/plays/login.go new file mode 100644 index 0000000..1469097 --- /dev/null +++ b/plays/login.go @@ -0,0 +1,137 @@ +package plays + +import ( + "fmt" + "net/http" + "strings" + + "github.com/charmbracelet/bubbles/textinput" + tea "github.com/charmbracelet/bubbletea" +) + +type Login struct { + *Base + + focusIndex int + inputs []textinput.Model +} + +func NewLogin(base *Base) *Login { + m := Login{ + Base: base, + + focusIndex: 0, + inputs: make([]textinput.Model, 2), + } + + for i := range m.inputs { + t := textinput.New() + t.CharLimit = 32 + t.Width = 20 + + switch i { + case 0: + t.Placeholder = "Username" + t.Focus() + case 1: + t.Placeholder = "Password" + t.EchoMode = textinput.EchoPassword + t.EchoCharacter = '•' + } + + m.inputs[i] = t + } + return &m +} + +func (m *Login) Init() tea.Cmd { + return tea.Batch(tea.ClearScreen, textinput.Blink) +} + +func (m *Login) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.KeyMsg: + switch msg.String() { + case "ctrl+l": + return m, tea.ClearScreen + + case "ctrl+c", "q": + return m, tea.Interrupt + + case "tab", "shift+tab", "enter", "up", "down": + s := msg.String() + + if s == "enter" && m.focusIndex == len(m.inputs)-1 { + return m, tea.Quit + } + + if s == "up" || s == "shift+tab" { + m.focusIndex-- + } else { + m.focusIndex++ + } + + if m.focusIndex >= len(m.inputs) { + m.focusIndex = 0 + } else if m.focusIndex < 0 { + m.focusIndex = len(m.inputs) - 1 + } + + cmds := make([]tea.Cmd, len(m.inputs)) + for i := 0; i < len(m.inputs); i++ { + if i == m.focusIndex { + cmds[i] = m.inputs[i].Focus() + continue + } + m.inputs[i].Blur() + } + + return m, tea.Batch(cmds...) + } + } + + cmd := m.updateInputs(msg) + return m, cmd +} + +func (m *Login) updateInputs(msg tea.Msg) tea.Cmd { + cmds := make([]tea.Cmd, len(m.inputs)) + + for i := range m.inputs { + m.inputs[i], cmds[i] = m.inputs[i].Update(msg) + } + + return tea.Batch(cmds...) +} + +func (m *Login) View() string { + var b strings.Builder + + fmt.Fprintf(&b, "User login:\n") + for i := range m.inputs { + b.WriteString(m.inputs[i].View()) + if i < len(m.inputs) { + b.WriteRune('\n') + } + } + + return b.String() +} + +func (m *Login) Next(queue *[]*tea.Program) error { + resp, _ := m.Base.client.R(). + SetBasicAuth(m.inputs[0].Value(), m.inputs[1].Value()). + Get("/auth/login") + + if resp.StatusCode() == http.StatusOK { + *queue = append(*queue, + tea.NewProgram(NewLobby(m.Base))) + } else { + *queue = append(*queue, + tea.NewProgram(NewRedirect("Login failed"))) + *queue = append(*queue, + tea.NewProgram(NewLanding(m.Base))) + } + + return nil +} diff --git a/plays/next.go b/plays/next.go new file mode 100644 index 0000000..cf32f81 --- /dev/null +++ b/plays/next.go @@ -0,0 +1,9 @@ +package plays + +import tea "github.com/charmbracelet/bubbletea" + +type Next interface { + Next( + queue *[]*tea.Program, + ) error +} diff --git a/plays/redirect.go b/plays/redirect.go new file mode 100644 index 0000000..af728d9 --- /dev/null +++ b/plays/redirect.go @@ -0,0 +1,59 @@ +package plays + +import ( + "fmt" + "time" + + tea "github.com/charmbracelet/bubbletea" +) + +type tickMsg time.Time + +type Redirect struct { + Message string + + secLeft int +} + +func NewRedirect(msg string) *Redirect { + return &Redirect{ + Message: msg, + + secLeft: 3, + } +} + +func tick() tea.Cmd { + return tea.Tick(time.Second, func(t time.Time) tea.Msg { + return tickMsg(t) + }) +} + +func (m *Redirect) Init() tea.Cmd { + return tick() +} + +func (m *Redirect) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.KeyMsg: + switch msg.String() { + case "q", "ctrl+c", "enter": + return m, tea.Quit + } + case tickMsg: + m.secLeft-- + if m.secLeft <= 0 { + return m, tea.Quit + } + return m, tick() + } + return m, nil +} + +func (m *Redirect) View() string { + return fmt.Sprintf("%s\n\nExit in %d seconds...", m.Message, m.secLeft) +} + +func (m *Redirect) Next(queue *[]*tea.Program) error { + return nil +} diff --git a/plays/register.go b/plays/register.go new file mode 100644 index 0000000..f675d70 --- /dev/null +++ b/plays/register.go @@ -0,0 +1,143 @@ +package plays + +import ( + "fmt" + "net/http" + "strings" + + "gitea.konchin.com/ytshih/inp2025/game/models" + "github.com/charmbracelet/bubbles/textinput" + tea "github.com/charmbracelet/bubbletea" +) + +type Register struct { + *Base + + focusIndex int + inputs []textinput.Model +} + +func NewRegister(base *Base) *Register { + m := Register{ + Base: base, + focusIndex: 0, + inputs: make([]textinput.Model, 2), + } + + for i := range m.inputs { + t := textinput.New() + t.CharLimit = 32 + t.Width = 20 + + switch i { + case 0: + t.Placeholder = "Username" + t.Focus() + case 1: + t.Placeholder = "Password" + t.EchoMode = textinput.EchoPassword + t.EchoCharacter = '•' + } + + m.inputs[i] = t + } + return &m +} + +func (m *Register) Init() tea.Cmd { + return tea.Batch(tea.ClearScreen, textinput.Blink) +} + +func (m *Register) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.KeyMsg: + switch msg.String() { + case "ctrl+l": + return m, tea.ClearScreen + + case "ctrl+c", "q": + return m, tea.Quit + + case "tab", "shift+tab", "enter", "up", "down": + s := msg.String() + + if s == "enter" && m.focusIndex == len(m.inputs)-1 { + return m, tea.Quit + } + + if s == "up" || s == "shift+tab" { + m.focusIndex-- + } else { + m.focusIndex++ + } + + if m.focusIndex >= len(m.inputs) { + m.focusIndex = 0 + } else if m.focusIndex < 0 { + m.focusIndex = len(m.inputs) - 1 + } + + cmds := make([]tea.Cmd, len(m.inputs)) + for i := 0; i < len(m.inputs); i++ { + if i == m.focusIndex { + cmds[i] = m.inputs[i].Focus() + continue + } + m.inputs[i].Blur() + } + + return m, tea.Batch(cmds...) + } + } + + cmd := m.updateInputs(msg) + return m, cmd +} + +func (m *Register) updateInputs(msg tea.Msg) tea.Cmd { + cmds := make([]tea.Cmd, len(m.inputs)) + + for i := range m.inputs { + m.inputs[i], cmds[i] = m.inputs[i].Update(msg) + } + + return tea.Batch(cmds...) +} + +func (m *Register) View() string { + var b strings.Builder + + fmt.Fprintf(&b, "User register:\n") + for i := range m.inputs { + b.WriteString(m.inputs[i].View()) + if i < len(m.inputs) { + b.WriteRune('\n') + } + } + + return b.String() +} + +func (m *Register) Next(queue *[]*tea.Program) error { + resp, err := m.Base.client.R(). + SetBody(models.User{ + Username: m.inputs[0].Value(), + Password: m.inputs[1].Value(), + }). + Post("/auth/register") + + switch resp.StatusCode() { + case http.StatusOK: + *queue = append(*queue, + tea.NewProgram(NewLogin(m.Base))) + case http.StatusBadRequest: + *queue = append(*queue, + tea.NewProgram(NewRedirect("Username already exist"))) + *queue = append(*queue, + tea.NewProgram(NewRegister(m.Base))) + case http.StatusInternalServerError: + return err + } + + return nil +} diff --git a/types/errors.go b/types/errors.go new file mode 100644 index 0000000..1891f5f --- /dev/null +++ b/types/errors.go @@ -0,0 +1,8 @@ +package types + +import "errors" + +var ( + UsernameConflictError = errors.New("username conflict") + RouteNotExistError = errors.New("route not exist") +) diff --git a/types/types.go b/types/types.go new file mode 100644 index 0000000..d64c057 --- /dev/null +++ b/types/types.go @@ -0,0 +1,5 @@ +package types + +type ( + User string +) diff --git a/utils/initDB.go b/utils/initDB.go new file mode 100644 index 0000000..149bf17 --- /dev/null +++ b/utils/initDB.go @@ -0,0 +1,14 @@ +package utils + +import ( + "context" + + "gitea.konchin.com/ytshih/inp2025/game/models" + "github.com/uptrace/bun" +) + +func InitDB(ctx context.Context, db *bun.DB) error { + return db.ResetModel(ctx, + (*models.User)(nil), + ) +} diff --git a/utils/readConfig.go b/utils/readConfig.go new file mode 100644 index 0000000..179cf0e --- /dev/null +++ b/utils/readConfig.go @@ -0,0 +1,23 @@ +package utils + +import ( + "context" + + "gitea.konchin.com/ytshih/inp2025/game/tracing" + "github.com/spf13/viper" + "go.uber.org/zap" +) + +func ReadConfig(ctx context.Context) { + viper.SetConfigName("config") + viper.SetConfigType("yaml") + viper.AddConfigPath(".") + if err := viper.ReadInConfig(); err != nil { + if _, ok := err.(viper.ConfigFileNotFoundError); !ok { + tracing.Logger.Ctx(ctx). + Panic("failed to read config file", + zap.Error(err)) + panic(err) + } + } +}