feat: add a new cmd - serve (#49)

Reviewed-on: twhelp/corev3#49
This commit is contained in:
Dawid Wysokiński 2024-01-23 07:13:55 +00:00
parent 43451aa32e
commit d1878c9e97
35 changed files with 936 additions and 7 deletions

View File

@ -18,14 +18,19 @@ install-golangci-lint:
@echo "Installing github.com/golangci/golangci-lint..."
@(test -f $(GOLANGCI_LINT_PATH) && echo "github.com/golangci/golangci-lint is already installed. Skipping...") || curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GOBIN) v1.55.2
.PHONY: install-oapi-codegen
install-oapi-codegen:
@echo "Installing github.com/deepmap/oapi-codegen..."
@go install github.com/deepmap/oapi-codegen/v2/cmd/oapi-codegen@v2.0.0
.PHONY: install-tools
install-tools: install-golangci-lint
install-tools: install-golangci-lint install-oapi-codegen
.PHONY: install
install: install-tools install-git-hooks
.PHONY: generate
generate:
generate: install-oapi-codegen
@echo "Running go generate..."
go generate ./...

144
api/openapi3.yml Normal file
View File

@ -0,0 +1,144 @@
openapi: 3.0.0
info:
version: 2.0.0
title: TWHelp API
description: REST API to interact with [TWHelp](https://tribalwarshelp.com).
contact:
name: Dawid Wysokiński
url: https://dwysokinski.me
email: contact@dwysokinski.me
license:
name: MIT
tags:
- name: versions
servers:
- url: "{scheme}://{hostname}/api"
variables:
scheme:
default: http
enum:
- http
- https
hostname:
default: localhost:9913
paths:
/v2/versions:
get:
operationId: listVersions
tags:
- versions
description: List versions
parameters:
- $ref: "#/components/parameters/CursorQueryParam"
- $ref: "#/components/parameters/LimitQueryParam"
responses:
200:
$ref: "#/components/responses/ListVersionsResponse"
default:
$ref: "#/components/responses/ErrorResponse"
components:
schemas:
Error:
type: object
required:
- slug
- message
additionalProperties: false
properties:
slug:
type: string
message:
type: string
params:
type: object
additionalProperties: true
x-go-type-skip-optional-pointer: true
Version:
type: object
required:
- code
- host
- name
- timezone
properties:
code:
type: string
example: pl
host:
type: string
example: www.tribalwars.net
name:
type: string
example: Poland
timezone:
type: string
example: Europe/Warsaw
PaginationResponse:
type: object
properties:
self:
description: Pagination link pointing to the current page.
type: string
format: uri
x-go-type-skip-optional-pointer: true
first:
description: Pagination link pointing to the first page.
type: string
format: uri
x-go-type-skip-optional-pointer: true
prev:
description: Pagination link pointing to the previous page.
type: string
format: uri
x-go-type-skip-optional-pointer: true
next:
description: Pagination link pointing to the next page.
type: string
format: uri
x-go-type-skip-optional-pointer: true
last:
description: Pagination link pointing to the last page.
type: string
format: uri
x-go-type-skip-optional-pointer: true
parameters:
CursorQueryParam:
in: query
name: cursor
schema:
type: string
required: false
LimitQueryParam:
in: query
name: limit
schema:
type: integer
required: false
responses:
ListVersionsResponse:
description: ""
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/PaginationResponse"
- type: object
required:
- items
properties:
items:
type: array
items:
$ref: "#/components/schemas/Version"
ErrorResponse:
description: Default error response.
content:
application/json:
schema:
type: object
required:
- error
additionalProperties: false
properties:
error:
$ref: "#/components/schemas/Error"

View File

@ -43,7 +43,8 @@ func newApp(name, version string) *appWrapper {
app.Name = name
app.HelpName = name
app.Version = version
app.Commands = []*cli.Command{cmdDB, cmdJob, cmdConsumer}
app.Commands = []*cli.Command{cmdDB, cmdJob, cmdConsumer, cmdServe}
app.DefaultCommand = cmdServe.Name
app.Flags = concatSlices(appFlags, logFlags)
app.Before = app.handleBefore
return app

183
cmd/twhelp/cmd_serve.go Normal file
View File

@ -0,0 +1,183 @@
package main
import (
"context"
"errors"
"fmt"
"log/slog"
"net/http"
"net/url"
"time"
"gitea.dwysokinski.me/twhelp/corev3/internal/chislog"
"gitea.dwysokinski.me/twhelp/corev3/internal/port"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/urfave/cli/v2"
)
var (
apiServerPortFlag = &cli.UintFlag{
Name: "api.port",
EnvVars: []string{"API_PORT"},
Value: 9234, //nolint:gomnd
}
apiServerReadTimeoutFlag = &cli.DurationFlag{
Name: "api.readTimeout",
EnvVars: []string{"API_READ_TIMEOUT"},
Value: 5 * time.Second, //nolint:gomnd
}
apiServerReadHeaderTimeoutFlag = &cli.DurationFlag{
Name: "api.readHeaderTimeout",
EnvVars: []string{"API_READ_HEADER_TIMEOUT"},
Value: time.Second,
}
apiServerWriteTimeoutFlag = &cli.DurationFlag{
Name: "api.writeTimeout",
EnvVars: []string{"API_WRITE_TIMEOUT"},
Value: 10 * time.Second, //nolint:gomnd
}
apiServerIdleTimeoutFlag = &cli.DurationFlag{
Name: "api.idleTimeout",
EnvVars: []string{"API_IDLE_TIMEOUT"},
Value: 180 * time.Second, //nolint:gomnd
}
apiServerShutdownTimeoutFlag = &cli.DurationFlag{
Name: "api.shutdownTimeout",
EnvVars: []string{"API_SHUTDOWN_TIMEOUT"},
Value: 10 * time.Second, //nolint:gomnd
}
apiServerOpenAPIEnabledFlag = &cli.BoolFlag{
Name: "api.openApi.enabled",
EnvVars: []string{"API_OPENAPI_ENABLED"},
Value: true,
}
apiServerOpenAPISwaggerEnabledFlag = &cli.BoolFlag{
Name: "api.openApi.swaggerEnabled",
EnvVars: []string{"API_OPENAPI_SWAGGER_ENABLED"},
Value: true,
}
apiServerOpenAPIServersFlag = &cli.StringSliceFlag{
Name: "api.openApi.servers",
EnvVars: []string{"API_OPENAPI_SERVERS"},
}
apiServerFlags = []cli.Flag{
apiServerPortFlag,
apiServerReadTimeoutFlag,
apiServerReadHeaderTimeoutFlag,
apiServerWriteTimeoutFlag,
apiServerIdleTimeoutFlag,
apiServerOpenAPIEnabledFlag,
apiServerOpenAPISwaggerEnabledFlag,
apiServerOpenAPIServersFlag,
}
)
const apiBasePath = "/api"
var cmdServe = &cli.Command{
Name: "serve",
Usage: "Run the HTTP server",
Flags: concatSlices(apiServerFlags, dbFlags),
Action: func(c *cli.Context) error {
logger := loggerFromCtx(c.Context)
bunDB, err := newBunDBFromFlags(c)
if err != nil {
return err
}
defer func() {
logger.Debug("closing db connections...", slog.Int("db.openConnections", bunDB.Stats().OpenConnections))
if dbCloseErr := bunDB.Close(); dbCloseErr != nil {
logger.Warn("couldn't close db connections", slog.Any("error", dbCloseErr))
} else {
logger.Debug("db connections closed")
}
}()
server, err := newHTTPServer(
httpServerConfig{
port: c.Uint(apiServerPortFlag.Name),
readTimeout: c.Duration(apiServerReadTimeoutFlag.Name),
readHeaderTimeout: c.Duration(apiServerReadHeaderTimeoutFlag.Name),
writeTimeout: c.Duration(apiServerWriteTimeoutFlag.Name),
idleTimeout: c.Duration(apiServerIdleTimeoutFlag.Name),
},
func(r chi.Router) error {
r.Use(newAPIMiddlewares(logger)...)
oapiCfg, oapiCfgErr := newOpenAPIConfigFromFlags(c)
if oapiCfgErr != nil {
return oapiCfgErr
}
r.Mount(
apiBasePath,
port.NewAPIHTTPHandler(port.WithOpenAPIConfig(oapiCfg)),
)
return nil
},
)
if err != nil {
return fmt.Errorf("couldn't construct HTTP server: %w", err)
}
idleConnsClosed := make(chan struct{})
go func() {
waitForShutdownSignal(c.Context)
logger.Debug("received shutdown signal")
ctx, cancel := context.WithTimeout(c.Context, c.Duration(apiServerShutdownTimeoutFlag.Name))
defer cancel()
if err := server.Shutdown(ctx); err != nil {
logger.Warn("shutdown failed", slog.Any("error", err))
}
close(idleConnsClosed)
}()
logger.Info("Server is listening on the addr "+server.Addr, slog.String("addr", server.Addr))
if err := server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
return fmt.Errorf("ListenAndServe failed: %w", err)
}
<-idleConnsClosed
return nil
},
}
func newOpenAPIConfigFromFlags(c *cli.Context) (port.OpenAPIConfig, error) {
rawURLs := c.StringSlice(apiServerOpenAPIServersFlag.Name)
servers := make([]port.OpenAPIConfigServer, 0, len(rawURLs))
for _, raw := range rawURLs {
u, err := url.Parse(raw)
if err != nil {
return port.OpenAPIConfig{}, err
}
servers = append(servers, port.OpenAPIConfigServer{
URL: u,
})
}
return port.OpenAPIConfig{
Enabled: c.Bool(apiServerOpenAPIEnabledFlag.Name),
SwaggerEnabled: c.Bool(apiServerOpenAPISwaggerEnabledFlag.Name),
BasePath: apiBasePath,
Servers: servers,
}, nil
}
func newAPIMiddlewares(logger *slog.Logger) chi.Middlewares {
return chi.Middlewares{
chislog.Logger(logger),
middleware.Recoverer,
}
}

34
cmd/twhelp/http_server.go Normal file
View File

@ -0,0 +1,34 @@
package main
import (
"fmt"
"net/http"
"time"
"github.com/go-chi/chi/v5"
)
type httpServerConfig struct {
port uint
readTimeout time.Duration
readHeaderTimeout time.Duration
writeTimeout time.Duration
idleTimeout time.Duration
}
func newHTTPServer(cfg httpServerConfig, registerHandlers func(r chi.Router) error) (*http.Server, error) {
r := chi.NewRouter()
if err := registerHandlers(r); err != nil {
return nil, fmt.Errorf("couldn't register handlers: %w", err)
}
return &http.Server{
Addr: fmt.Sprintf(":%d", cfg.port),
Handler: r,
ReadTimeout: cfg.readTimeout,
ReadHeaderTimeout: cfg.readHeaderTimeout,
WriteTimeout: cfg.writeTimeout,
IdleTimeout: cfg.idleTimeout,
}, nil
}

12
go.mod
View File

@ -8,9 +8,12 @@ require (
github.com/brianvoe/gofakeit/v6 v6.28.0
github.com/cenkalti/backoff/v4 v4.2.1
github.com/elliotchance/phpserialize v1.3.3
github.com/getkin/kin-openapi v0.122.0
github.com/go-chi/chi/v5 v5.0.11
github.com/go-chi/render v1.0.3
github.com/google/go-cmp v0.6.0
github.com/google/uuid v1.5.0
github.com/oapi-codegen/runtime v1.1.1
github.com/ory/dockertest/v3 v3.10.0
github.com/stretchr/testify v1.8.4
github.com/uptrace/bun v1.1.17
@ -27,6 +30,8 @@ require (
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect
github.com/Microsoft/go-winio v0.6.0 // indirect
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
github.com/ajg/form v1.5.1 // indirect
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
github.com/cenkalti/backoff/v3 v3.2.2 // indirect
github.com/containerd/continuity v0.3.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
@ -37,23 +42,30 @@ require (
github.com/docker/go-units v0.4.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/go-openapi/jsonpointer v0.19.6 // indirect
github.com/go-openapi/swag v0.22.4 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/invopop/yaml v0.2.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/lithammer/shortuuid/v3 v3.0.7 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-sqlite3 v1.14.19 // indirect
github.com/mitchellh/mapstructure v1.4.1 // indirect
github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 // indirect
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/oklog/ulid v1.3.1 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.0.2 // indirect
github.com/opencontainers/runc v1.1.5 // indirect
github.com/perimeterx/marshmallow v1.1.5 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rabbitmq/amqp091-go v1.9.0 // indirect

47
go.sum
View File

@ -5,10 +5,16 @@ github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2y
github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE=
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw=
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
github.com/ThreeDotsLabs/watermill v1.3.5 h1:50JEPEhMGZQMh08ct0tfO1PsgMOAOhV3zxK2WofkbXg=
github.com/ThreeDotsLabs/watermill v1.3.5/go.mod h1:O/u/Ptyrk5MPTxSeWM5vzTtZcZfxXfO9PK9eXTYiFZY=
github.com/ThreeDotsLabs/watermill-amqp/v2 v2.1.1 h1:OxvMB2/3YtcQuC7quC+CGmFpGz9oaxP2ef5wkp+R2oM=
github.com/ThreeDotsLabs/watermill-amqp/v2 v2.1.1/go.mod h1:MCNoh0HUg4w0bY64on9BnhUodHeimz8+vMfXrzyuWN8=
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
github.com/brianvoe/gofakeit/v6 v6.28.0 h1:Xib46XXuQfmlLS2EXRuJpqcw8St6qSZz75OUo0tgAW4=
github.com/brianvoe/gofakeit/v6 v6.28.0/go.mod h1:Xj58BMSnFqcn/fAQeSK+/PLtC5kSb7FJIq4JyGa8vEs=
github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M=
@ -24,6 +30,7 @@ github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
@ -45,10 +52,21 @@ github.com/elliotchance/phpserialize v1.3.3/go.mod h1:gt7XX9+ETUcLXbtTKEuyrqW3lc
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
github.com/getkin/kin-openapi v0.122.0 h1:WB9Jbl0Hp/T79/JF9xlSW5Kl9uYdk/AWD0yAd9HOM10=
github.com/getkin/kin-openapi v0.122.0/go.mod h1:PCWw/lfBrJY4HcdqE3jj+QFkaFK8ABoqo7PvqVhXXqw=
github.com/go-chi/chi/v5 v5.0.11 h1:BnpYbFZ3T3S1WMpD79r7R5ThWX40TaFB7L31Y8xqSwA=
github.com/go-chi/chi/v5 v5.0.11/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4=
github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU=
github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
@ -74,14 +92,21 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/invopop/yaml v0.2.0 h1:7zky/qH+O0DwAyoobXUqvVBwgBFRxKoQ/3FjcVpjTMY=
github.com/invopop/yaml v0.2.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q=
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/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
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=
@ -90,6 +115,8 @@ github.com/lib/pq v0.0.0-20180327071824-d34b9ff171c2 h1:hRGSmZu7j271trc9sneMrpOW
github.com/lib/pq v0.0.0-20180327071824-d34b9ff171c2/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lithammer/shortuuid/v3 v3.0.7 h1:trX0KTHy4Pbwo/6ia8fscyHoGA+mf1jWbPJVuvyJQQ8=
github.com/lithammer/shortuuid/v3 v3.0.7/go.mod h1:vMk8ke37EmiewwolSO1NLW8vP4ZaKlRuDIi8tWWmAts=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
@ -102,9 +129,11 @@ github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR
github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU=
github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 h1:rzf0wL0CHVc8CEsgyygG0Mn9CNCCPZqOPaz8RiiHYQk=
github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/oapi-codegen/runtime v1.1.1 h1:EXLHh0DXIJnWhdRPN2w4MXAzFyE4CskzhNLUmtpMYro=
github.com/oapi-codegen/runtime v1.1.1/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg=
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
@ -117,6 +146,8 @@ github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.m
github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI=
github.com/ory/dockertest/v3 v3.10.0 h1:4K3z2VMe8Woe++invjaTB7VRyQXQy5UY+loujO4aNE4=
github.com/ory/dockertest/v3 v3.10.0/go.mod h1:nr57ZbRWMqfsdGdFNLHz5jjNdDb7VVFnzAeW1n5N1Lg=
github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s=
github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@ -126,6 +157,8 @@ github.com/rabbitmq/amqp091-go v1.9.0 h1:qrQtyzB4H8BQgEuJwhmVQqVHB9O4+MNDJCCAcpc
github.com/rabbitmq/amqp091-go v1.9.0/go.mod h1:+jPrT9iY2eLjRaMSRHUhc3z14E/l85kv/f+6luSD3pc=
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/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
@ -136,17 +169,22 @@ github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic
github.com/sony/gobreaker v0.5.0 h1:dRCvqm0P490vZPmy7ppEk2qCnCieBooFJ+YoXGYB+yg=
github.com/sony/gobreaker v0.5.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
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.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
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/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/uptrace/bun v1.1.17 h1:qxBaEIo0hC/8O3O6GrMDKxqyT+mw5/s0Pn/n6xjyGIk=
github.com/uptrace/bun v1.1.17/go.mod h1:hATAzivtTIRsSJR4B8AXR+uABqnQxr3myKDKEf5iQ9U=
github.com/uptrace/bun/dbfixture v1.1.17 h1:/zvsLC582KizT7Ksignl64OXU5ut5x9sIs/fUhW8ssA=
@ -236,12 +274,13 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
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 h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
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.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0/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=
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=

View File

@ -0,0 +1,54 @@
package port
import (
"net/http"
"sync"
"gitea.dwysokinski.me/twhelp/corev3/internal/port/internal/apimodel"
"gitea.dwysokinski.me/twhelp/corev3/internal/port/internal/swgui"
"github.com/getkin/kin-openapi/openapi3"
"github.com/go-chi/chi/v5"
"github.com/go-chi/render"
)
type apiHTTPHandler struct {
apimodel.Unimplemented
getOpenAPISchema func() (*openapi3.T, error)
}
func WithOpenAPIConfig(oapiCfg OpenAPIConfig) APIHTTPHandlerOption {
return func(cfg *apiHTTPHandlerConfig) {
cfg.openAPI = oapiCfg
}
}
func NewAPIHTTPHandler(opts ...APIHTTPHandlerOption) http.Handler {
cfg := newAPIHTTPHandlerConfig(opts...)
h := &apiHTTPHandler{
getOpenAPISchema: sync.OnceValues(func() (*openapi3.T, error) {
return getOpenAPISchema(cfg.openAPI)
}),
}
r := chi.NewRouter()
if cfg.openAPI.Enabled {
r.Group(func(r chi.Router) {
if cfg.openAPI.SwaggerEnabled {
r.Handle("/v2/swagger/*", swgui.Handler(
cfg.openAPI.BasePath+"/v2/swagger",
cfg.openAPI.BasePath+"/v2/openapi3.json",
))
}
r.Get("/v2/openapi3.json", h.sendOpenAPIJSON)
})
}
return apimodel.HandlerWithOptions(h, apimodel.ChiServerOptions{BaseRouter: r})
}
func (h *apiHTTPHandler) renderJSON(w http.ResponseWriter, r *http.Request, status int, body any) {
render.Status(r, status)
render.JSON(w, r, body)
}

View File

@ -0,0 +1,30 @@
package port
import "net/url"
type OpenAPIConfigServer struct {
URL *url.URL
}
type OpenAPIConfig struct {
Enabled bool
SwaggerEnabled bool
BasePath string
Servers []OpenAPIConfigServer
}
type apiHTTPHandlerConfig struct {
openAPI OpenAPIConfig
}
type APIHTTPHandlerOption func(cfg *apiHTTPHandlerConfig)
func newAPIHTTPHandlerConfig(opts ...APIHTTPHandlerOption) *apiHTTPHandlerConfig {
cfg := &apiHTTPHandlerConfig{}
for _, opt := range opts {
opt(cfg)
}
return cfg
}

View File

@ -0,0 +1,44 @@
package port
import (
"errors"
"net/http"
"gitea.dwysokinski.me/twhelp/corev3/internal/port/internal/apimodel"
"github.com/getkin/kin-openapi/openapi3"
)
func (h *apiHTTPHandler) sendOpenAPIJSON(w http.ResponseWriter, r *http.Request) {
schema, err := h.getOpenAPISchema()
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
h.renderJSON(w, r, http.StatusOK, schema)
}
func getOpenAPISchema(cfg OpenAPIConfig) (*openapi3.T, error) {
if !cfg.Enabled {
return nil, errors.New("openapi is disabled")
}
schema, err := apimodel.GetSwagger()
if err != nil {
return nil, err
}
if len(cfg.Servers) == 0 {
return schema, nil
}
schema.Servers = make(openapi3.Servers, 0, len(cfg.Servers))
for _, s := range cfg.Servers {
schema.Servers = append(schema.Servers, &openapi3.Server{
URL: s.URL.String(),
})
}
return schema, nil
}

View File

@ -0,0 +1,98 @@
package port_test
import (
"io"
"net/http"
"net/url"
"slices"
"testing"
"gitea.dwysokinski.me/twhelp/corev3/internal/port"
"github.com/brianvoe/gofakeit/v6"
"github.com/getkin/kin-openapi/openapi3"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestOpenAPI(t *testing.T) {
t.Parallel()
t.Run("OK: openapi3.json", func(t *testing.T) {
t.Parallel()
u1, err := url.Parse(gofakeit.URL())
require.NoError(t, err)
u2, err := url.Parse(gofakeit.URL())
require.NoError(t, err)
servers := []port.OpenAPIConfigServer{
{
URL: u1,
},
{
URL: u2,
},
}
handler := newAPIHTTPHandler(t, func(cfg *apiHTTPHandlerConfig) {
cfg.options = append(cfg.options, port.WithOpenAPIConfig(port.OpenAPIConfig{
Enabled: true,
Servers: servers,
}))
})
//nolint:bodyclose
resp := doRequest(handler, http.MethodGet, "/v2/openapi3.json", nil)
defer require.NoError(t, resp.Body.Close())
assert.Equal(t, http.StatusOK, resp.StatusCode)
b, err := io.ReadAll(resp.Body)
require.NoError(t, err)
body, err := openapi3.NewLoader().LoadFromData(b)
require.NoError(t, err)
for i, expected := range servers {
idx := slices.IndexFunc(body.Servers, func(s *openapi3.Server) bool {
return s.URL == expected.URL.String()
})
assert.GreaterOrEqualf(t, idx, 0, "expected[%d] not found", i)
}
})
t.Run("OK: Swagger", func(t *testing.T) {
t.Parallel()
handler := newAPIHTTPHandler(t, func(cfg *apiHTTPHandlerConfig) {
cfg.options = append(cfg.options, port.WithOpenAPIConfig(port.OpenAPIConfig{
Enabled: true,
SwaggerEnabled: true,
}))
})
tests := []struct {
target string
expectedContentType string
}{
{
target: "/v2/swagger/",
expectedContentType: "text/html; charset=utf-8",
},
{
target: "/v2/swagger/swagger-initializer.js",
expectedContentType: "text/javascript; charset=utf-8",
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.target, func(t *testing.T) {
t.Parallel()
resp := doRequest(handler, http.MethodGet, tt.target, nil)
defer require.NoError(t, resp.Body.Close())
assert.Equal(t, http.StatusOK, resp.StatusCode)
assert.Equal(t, tt.expectedContentType, resp.Header.Get("Content-Type"))
})
}
})
}

View File

@ -0,0 +1,36 @@
package port_test
import (
"io"
"net/http"
"net/http/httptest"
"testing"
"gitea.dwysokinski.me/twhelp/corev3/internal/port"
)
type apiHTTPHandlerConfig struct {
options []port.APIHTTPHandlerOption
}
func newAPIHTTPHandler(tb testing.TB, opts ...func(cfg *apiHTTPHandlerConfig)) http.Handler {
tb.Helper()
cfg := &apiHTTPHandlerConfig{}
for _, opt := range opts {
opt(cfg)
}
return port.NewAPIHTTPHandler(cfg.options...)
}
func doRequest(h http.Handler, method, target string, body io.Reader) *http.Response {
return doCustomRequest(h, httptest.NewRequest(method, target, body))
}
func doCustomRequest(h http.Handler, r *http.Request) *http.Response {
rr := httptest.NewRecorder()
h.ServeHTTP(rr, r)
return rr.Result()
}

View File

@ -0,0 +1 @@
*.gen.go

View File

@ -0,0 +1,3 @@
package apimodel
//go:generate oapi-codegen --config=config.yml ../../../../api/openapi3.yml

View File

@ -0,0 +1,8 @@
package: apimodel
generate:
chi-server: true
models: true
embedded-spec: true
compatibility:
apply-chi-middleware-first-to-last: true
output: apimodel.gen.go

Binary file not shown.

After

Width:  |  Height:  |  Size: 665 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 628 B

View File

@ -0,0 +1,16 @@
html {
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
body {
margin: 0;
background: #fafafa;
}

View File

@ -0,0 +1,19 @@
<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" />
<link rel="stylesheet" type="text/css" href="./index.css" />
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
</head>
<body>
<div id="swagger-ui"></div>
<script src="./swagger-ui-bundle.js" charset="UTF-8"> </script>
<script src="./swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
<script src="./swagger-initializer.js" charset="UTF-8"> </script>
</body>
</html>

View File

@ -0,0 +1,79 @@
<!doctype html>
<html lang="en-US">
<head>
<title>Swagger UI: OAuth2 Redirect</title>
</head>
<body>
<script>
'use strict';
function run () {
var oauth2 = window.opener.swaggerUIRedirectOauth2;
var sentState = oauth2.state;
var redirectUrl = oauth2.redirectUrl;
var isValid, qp, arr;
if (/code|token|error/.test(window.location.hash)) {
qp = window.location.hash.substring(1).replace('?', '&');
} else {
qp = location.search.substring(1);
}
arr = qp.split("&");
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';});
qp = qp ? JSON.parse('{' + arr.join() + '}',
function (key, value) {
return key === "" ? value : decodeURIComponent(value);
}
) : {};
isValid = qp.state === sentState;
if ((
oauth2.auth.schema.get("flow") === "accessCode" ||
oauth2.auth.schema.get("flow") === "authorizationCode" ||
oauth2.auth.schema.get("flow") === "authorization_code"
) && !oauth2.auth.code) {
if (!isValid) {
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "warning",
message: "Authorization may be unsafe, passed state was changed in server. The passed state wasn't returned from auth server."
});
}
if (qp.code) {
delete oauth2.state;
oauth2.auth.code = qp.code;
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
} else {
let oauthErrorMsg;
if (qp.error) {
oauthErrorMsg = "["+qp.error+"]: " +
(qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
(qp.error_uri ? "More info: "+qp.error_uri : "");
}
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "error",
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server."
});
}
} else {
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});
}
window.close();
}
if (document.readyState !== 'loading') {
run();
} else {
document.addEventListener('DOMContentLoaded', function () {
run();
});
}
</script>
</body>
</html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,47 @@
package swgui
import (
"embed"
"fmt"
"net/http"
)
//go:embed *.png *.js *.html *.css
var fs embed.FS
const initializerTpl = `
window.onload = function() {
//<editor-fold desc="Changeable Configuration Block">
window.ui = SwaggerUIBundle({
url: "%s",
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
});
//</editor-fold>
};
`
func Handler(basePath string, openAPISchemaURL string) http.Handler {
fileServer := http.StripPrefix(basePath, http.FileServer(http.FS(fs)))
swaggerInitializer := []byte(fmt.Sprintf(initializerTpl, openAPISchemaURL))
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodGet && r.URL.Path == basePath+"/swagger-initializer.js" {
w.Header().Set("Content-Type", "text/javascript; charset=utf-8")
_, _ = w.Write(swaggerInitializer)
return
}
fileServer.ServeHTTP(w, r)
})
}

52
k8s/base/api.yml Normal file
View File

@ -0,0 +1,52 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: twhelp-api-v2-deployment
spec:
selector:
matchLabels:
app: twhelp-api-v2
template:
metadata:
labels:
app: twhelp-api-v2
spec:
containers:
- name: twhelp-api-v2
image: twhelp
args: [serve]
env:
- name: APP_MODE
value: development
- name: LOG_LEVEL
value: debug
- name: DB_CONNECTION_STRING
valueFrom:
secretKeyRef:
name: twhelp-secret
key: db-connection-string
- name: RABBITMQ_CONNECTION_STRING
valueFrom:
secretKeyRef:
name: twhelp-secret
key: rabbitmq-connection-string
resources:
requests:
cpu: 100m
memory: 100Mi
limits:
cpu: 200m
memory: 300Mi
---
apiVersion: v1
kind: Service
metadata:
name: twhelp-api-v2-service
spec:
ports:
- port: 9234
targetPort: 9234
protocol: TCP
name: http
selector:
app: twhelp-api-v2

View File

@ -7,6 +7,7 @@ resources:
- player-consumer.yml
- village-consumer.yml
- ennoblement-consumer.yml
- api.yml
images:
- name: twhelp
newName: twhelp