Moved around more code. Implemented more sqlc. Added support to generate swagger.
Added support for profiling. Removed the pkg module altogether. Everything except old sync is now using code generated by sqlc.
This commit is contained in:
13
Dockerfile
13
Dockerfile
@@ -7,12 +7,13 @@ COPY go.mod go.sum ./
|
|||||||
RUN go mod download
|
RUN go mod download
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN go install github.com/a-h/templ/cmd/templ@latest && \
|
|
||||||
templ generate && \
|
|
||||||
curl -sL https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-linux-x64 -o tailwindcss && \
|
|
||||||
chmod +x tailwindcss && \
|
|
||||||
./tailwindcss -i cmd/web/assets/css/input.css -o cmd/web/assets/css/output.css
|
|
||||||
|
|
||||||
|
RUN go install github.com/a-h/templ/cmd/templ@latest
|
||||||
|
RUN curl -sL https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-linux-x64 -o tailwindcss
|
||||||
|
RUN chmod +x tailwindcss
|
||||||
|
|
||||||
|
RUN templ generate
|
||||||
|
RUN ./tailwindcss -i cmd/web/assets/css/input.css -o cmd/web/assets/css/output.css
|
||||||
RUN go build -o main cmd/main.go
|
RUN go build -o main cmd/main.go
|
||||||
|
|
||||||
# Stage 2, distribution container
|
# Stage 2, distribution container
|
||||||
@@ -21,11 +22,13 @@ EXPOSE 8080
|
|||||||
VOLUME /sorted
|
VOLUME /sorted
|
||||||
VOLUME /frontend
|
VOLUME /frontend
|
||||||
|
|
||||||
|
ENV PORT 8080
|
||||||
ENV DB_HOST ""
|
ENV DB_HOST ""
|
||||||
ENV DB_PORT ""
|
ENV DB_PORT ""
|
||||||
ENV DB_USERNAME ""
|
ENV DB_USERNAME ""
|
||||||
ENV DB_PASSWORD ""
|
ENV DB_PASSWORD ""
|
||||||
ENV DB_NAME ""
|
ENV DB_NAME ""
|
||||||
|
ENV MUSIC_PATH ""
|
||||||
|
|
||||||
COPY --from=build_go /app/main .
|
COPY --from=build_go /app/main .
|
||||||
COPY ./songs/ ./songs/
|
COPY ./songs/ ./songs/
|
||||||
|
|||||||
44
cmd/docs/docs.go
Normal file
44
cmd/docs/docs.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
// Package docs Code generated by swaggo/swag. DO NOT EDIT
|
||||||
|
package docs
|
||||||
|
|
||||||
|
import "github.com/swaggo/swag"
|
||||||
|
|
||||||
|
const docTemplate = `{
|
||||||
|
"schemes": {{ marshal .Schemes }},
|
||||||
|
"swagger": "2.0",
|
||||||
|
"info": {
|
||||||
|
"description": "{{escape .Description}}",
|
||||||
|
"title": "{{.Title}}",
|
||||||
|
"termsOfService": "http://swagger.io/terms/",
|
||||||
|
"contact": {
|
||||||
|
"name": "Sebastian Olsson",
|
||||||
|
"email": "zarnor91@gmail.com"
|
||||||
|
},
|
||||||
|
"license": {
|
||||||
|
"name": "Apache 2.0",
|
||||||
|
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
|
||||||
|
},
|
||||||
|
"version": "{{.Version}}"
|
||||||
|
},
|
||||||
|
"host": "{{.Host}}",
|
||||||
|
"basePath": "{{.BasePath}}",
|
||||||
|
"paths": {}
|
||||||
|
}`
|
||||||
|
|
||||||
|
// SwaggerInfo holds exported Swagger Info so clients can modify it
|
||||||
|
var SwaggerInfo = &swag.Spec{
|
||||||
|
Version: "0.5",
|
||||||
|
Host: "localhost:8080",
|
||||||
|
BasePath: "",
|
||||||
|
Schemes: []string{},
|
||||||
|
Title: "Swagger Example API",
|
||||||
|
Description: "This is a sample server Petstore server.",
|
||||||
|
InfoInstanceName: "swagger",
|
||||||
|
SwaggerTemplate: docTemplate,
|
||||||
|
LeftDelim: "{{",
|
||||||
|
RightDelim: "}}",
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo)
|
||||||
|
}
|
||||||
19
cmd/docs/swagger.json
Normal file
19
cmd/docs/swagger.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"swagger": "2.0",
|
||||||
|
"info": {
|
||||||
|
"description": "This is a sample server Petstore server.",
|
||||||
|
"title": "Swagger Example API",
|
||||||
|
"termsOfService": "http://swagger.io/terms/",
|
||||||
|
"contact": {
|
||||||
|
"name": "Sebastian Olsson",
|
||||||
|
"email": "zarnor91@gmail.com"
|
||||||
|
},
|
||||||
|
"license": {
|
||||||
|
"name": "Apache 2.0",
|
||||||
|
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
|
||||||
|
},
|
||||||
|
"version": "0.5"
|
||||||
|
},
|
||||||
|
"host": "localhost:8080",
|
||||||
|
"paths": {}
|
||||||
|
}
|
||||||
14
cmd/docs/swagger.yaml
Normal file
14
cmd/docs/swagger.yaml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
host: localhost:8080
|
||||||
|
info:
|
||||||
|
contact:
|
||||||
|
email: zarnor91@gmail.com
|
||||||
|
name: Sebastian Olsson
|
||||||
|
description: This is a sample server Petstore server.
|
||||||
|
license:
|
||||||
|
name: Apache 2.0
|
||||||
|
url: http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
termsOfService: http://swagger.io/terms/
|
||||||
|
title: Swagger Example API
|
||||||
|
version: "0.5"
|
||||||
|
paths: {}
|
||||||
|
swagger: "2.0"
|
||||||
71
cmd/main.go
71
cmd/main.go
@@ -4,14 +4,56 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"music-server/internal/db"
|
||||||
"music-server/internal/server"
|
"music-server/internal/server"
|
||||||
"music-server/pkg/db"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"runtime/pprof"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// @title Swagger Example API
|
||||||
|
// @version 0.5
|
||||||
|
// @description This is a sample server Petstore server.
|
||||||
|
// @termsOfService http://swagger.io/terms/
|
||||||
|
|
||||||
|
// @contact.name Sebastian Olsson
|
||||||
|
// @contact.email zarnor91@gmail.com
|
||||||
|
|
||||||
|
// @license.name Apache 2.0
|
||||||
|
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
|
||||||
|
// @host localhost:8080
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
f, perr := os.Create("cpu.pprof")
|
||||||
|
if perr != nil {
|
||||||
|
log.Fatal(perr)
|
||||||
|
}
|
||||||
|
pprof.StartCPUProfile(f)
|
||||||
|
defer pprof.StopCPUProfile()
|
||||||
|
|
||||||
|
server := server.NewServer()
|
||||||
|
|
||||||
|
// Create a done channel to signal when the shutdown is complete
|
||||||
|
done := make(chan bool, 1)
|
||||||
|
|
||||||
|
// Run graceful shutdown in a separate goroutine
|
||||||
|
go gracefulShutdown(server, done)
|
||||||
|
|
||||||
|
log.Printf("Open http://localhost%s in the browser", server.Addr)
|
||||||
|
err := server.ListenAndServe()
|
||||||
|
if err != nil && err != http.ErrServerClosed {
|
||||||
|
panic(fmt.Sprintf("http server error: %s", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for the graceful shutdown to complete
|
||||||
|
<-done
|
||||||
|
log.Println("Graceful shutdown complete.")
|
||||||
|
}
|
||||||
|
|
||||||
func gracefulShutdown(apiServer *http.Server, done chan bool) {
|
func gracefulShutdown(apiServer *http.Server, done chan bool) {
|
||||||
// Create context that listens for the interrupt signal from the OS.
|
// Create context that listens for the interrupt signal from the OS.
|
||||||
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
|
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
|
||||||
@@ -36,30 +78,3 @@ func gracefulShutdown(apiServer *http.Server, done chan bool) {
|
|||||||
// Notify the main goroutine that the shutdown is complete
|
// Notify the main goroutine that the shutdown is complete
|
||||||
done <- true
|
done <- true
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
|
||||||
|
|
||||||
server := server.NewServer()
|
|
||||||
|
|
||||||
// Create a done channel to signal when the shutdown is complete
|
|
||||||
done := make(chan bool, 1)
|
|
||||||
|
|
||||||
// Run graceful shutdown in a separate goroutine
|
|
||||||
go gracefulShutdown(server, done)
|
|
||||||
|
|
||||||
log.Printf("Open http://localhost%s in the browser", server.Addr)
|
|
||||||
err := server.ListenAndServe()
|
|
||||||
if err != nil && err != http.ErrServerClosed {
|
|
||||||
panic(fmt.Sprintf("http server error: %s", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for the graceful shutdown to complete
|
|
||||||
<-done
|
|
||||||
log.Println("Graceful shutdown complete.")
|
|
||||||
|
|
||||||
//conf.SetupDb()
|
|
||||||
|
|
||||||
//conf.SetupRestServer(swagger)
|
|
||||||
|
|
||||||
//conf.CloseDb()
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
package newDb
|
|
||||||
|
|
||||||
import "embed"
|
|
||||||
|
|
||||||
//go:embed "migrations/*.sql"
|
|
||||||
var MigrationsFs embed.FS
|
|
||||||
44
go.mod
44
go.mod
@@ -7,58 +7,48 @@ toolchain go1.23.4
|
|||||||
require (
|
require (
|
||||||
github.com/MShekow/directory-checksum v1.4.6
|
github.com/MShekow/directory-checksum v1.4.6
|
||||||
github.com/a-h/templ v0.3.819
|
github.com/a-h/templ v0.3.819
|
||||||
github.com/gin-contrib/static v1.1.2
|
|
||||||
github.com/gin-gonic/gin v1.10.0
|
|
||||||
github.com/golang-migrate/migrate/v4 v4.18.1
|
github.com/golang-migrate/migrate/v4 v4.18.1
|
||||||
github.com/jackc/pgtype v1.14.3
|
|
||||||
github.com/jackc/pgx/v5 v5.5.5
|
github.com/jackc/pgx/v5 v5.5.5
|
||||||
github.com/labstack/echo v3.3.10+incompatible
|
github.com/labstack/echo/v4 v4.13.3
|
||||||
github.com/lib/pq v1.10.9
|
github.com/lib/pq v1.10.9
|
||||||
github.com/spf13/afero v1.11.0
|
github.com/spf13/afero v1.11.0
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
github.com/swaggo/echo-swagger v1.4.1
|
||||||
|
github.com/swaggo/swag v1.16.4
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/bytedance/sonic v1.11.6 // indirect
|
github.com/KyleBanks/depth v1.2.1 // indirect
|
||||||
github.com/bytedance/sonic/loader v0.1.1 // indirect
|
github.com/PuerkitoBio/purell v1.1.1 // indirect
|
||||||
github.com/cloudwego/base64x v0.1.4 // indirect
|
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
|
||||||
github.com/cloudwego/iasm v0.2.0 // indirect
|
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
|
|
||||||
github.com/docker/docker v27.3.1+incompatible // indirect
|
github.com/docker/docker v27.3.1+incompatible // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
github.com/ghodss/yaml v1.0.0 // indirect
|
||||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
|
||||||
github.com/go-errors/errors v1.5.1 // indirect
|
github.com/go-errors/errors v1.5.1 // indirect
|
||||||
github.com/go-playground/locales v0.14.1 // indirect
|
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-openapi/jsonreference v0.19.6 // indirect
|
||||||
github.com/go-playground/validator/v10 v10.20.0 // indirect
|
github.com/go-openapi/spec v0.20.4 // indirect
|
||||||
github.com/goccy/go-json v0.10.2 // indirect
|
github.com/go-openapi/swag v0.19.15 // indirect
|
||||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||||
github.com/jackc/pgio v1.0.0 // indirect
|
|
||||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||||
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect
|
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect
|
||||||
github.com/jackc/puddle/v2 v2.2.1 // indirect
|
github.com/jackc/puddle/v2 v2.2.1 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
|
||||||
github.com/labstack/gommon v0.4.2 // indirect
|
github.com/labstack/gommon v0.4.2 // indirect
|
||||||
github.com/leodido/go-urn v1.4.0 // indirect
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/swaggo/files/v2 v2.0.0 // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
|
||||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
|
||||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
|
||||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
github.com/valyala/fasttemplate v1.2.2 // indirect
|
github.com/valyala/fasttemplate v1.2.2 // indirect
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0 // indirect
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0 // indirect
|
||||||
go.opentelemetry.io/otel/trace v1.32.0 // indirect
|
go.opentelemetry.io/otel/trace v1.32.0 // indirect
|
||||||
go.uber.org/atomic v1.7.0 // indirect
|
go.uber.org/atomic v1.7.0 // indirect
|
||||||
golang.org/x/arch v0.8.0 // indirect
|
|
||||||
golang.org/x/crypto v0.31.0 // indirect
|
golang.org/x/crypto v0.31.0 // indirect
|
||||||
golang.org/x/net v0.33.0 // indirect
|
golang.org/x/net v0.33.0 // indirect
|
||||||
golang.org/x/sync v0.10.0 // indirect
|
golang.org/x/sync v0.10.0 // indirect
|
||||||
golang.org/x/sys v0.28.0 // indirect
|
golang.org/x/sys v0.28.0 // indirect
|
||||||
golang.org/x/text v0.21.0 // indirect
|
golang.org/x/text v0.21.0 // indirect
|
||||||
google.golang.org/protobuf v1.34.2 // indirect
|
golang.org/x/time v0.8.0 // indirect
|
||||||
|
golang.org/x/tools v0.24.0 // indirect
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
290
go.sum
290
go.sum
@@ -1,30 +1,21 @@
|
|||||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
|
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
|
||||||
|
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
|
||||||
github.com/MShekow/directory-checksum v1.4.6 h1:2fhlCYbpjEN1iH9S0tdmEM0p1wvNT9x5x0rIchGI7nE=
|
github.com/MShekow/directory-checksum v1.4.6 h1:2fhlCYbpjEN1iH9S0tdmEM0p1wvNT9x5x0rIchGI7nE=
|
||||||
github.com/MShekow/directory-checksum v1.4.6/go.mod h1:bMfFBkaIlNk7O9VgEi8D2X7Q2Jfk3c7d67z3t6cpIi4=
|
github.com/MShekow/directory-checksum v1.4.6/go.mod h1:bMfFBkaIlNk7O9VgEi8D2X7Q2Jfk3c7d67z3t6cpIi4=
|
||||||
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
|
|
||||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||||
|
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/a-h/templ v0.3.819 h1:KDJ5jTFN15FyJnmSmo2gNirIqt7hfvBD2VXVDTySckM=
|
github.com/a-h/templ v0.3.819 h1:KDJ5jTFN15FyJnmSmo2gNirIqt7hfvBD2VXVDTySckM=
|
||||||
github.com/a-h/templ v0.3.819/go.mod h1:iDJKJktpttVKdWoTkRNNLcllRI+BlpopJc+8au3gOUo=
|
github.com/a-h/templ v0.3.819/go.mod h1:iDJKJktpttVKdWoTkRNNLcllRI+BlpopJc+8au3gOUo=
|
||||||
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
|
|
||||||
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
|
|
||||||
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
|
||||||
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
|
|
||||||
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
|
||||||
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
|
|
||||||
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
|
|
||||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
|
||||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
|
||||||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
|
||||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
|
||||||
github.com/dhui/dktest v0.4.3 h1:wquqUxAFdcUgabAVLvSCOKOlag5cIZuaOjYIBOWdsR0=
|
github.com/dhui/dktest v0.4.3 h1:wquqUxAFdcUgabAVLvSCOKOlag5cIZuaOjYIBOWdsR0=
|
||||||
github.com/dhui/dktest v0.4.3/go.mod h1:zNK8IwktWzQRm6I/l2Wjp7MakiyaFWv4G1hjmodmMTs=
|
github.com/dhui/dktest v0.4.3/go.mod h1:zNK8IwktWzQRm6I/l2Wjp7MakiyaFWv4G1hjmodmMTs=
|
||||||
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
||||||
@@ -37,138 +28,65 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4
|
|||||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
|
||||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
|
||||||
github.com/gin-contrib/static v1.1.2 h1:c3kT4bFkUJn2aoRU3s6XnMjJT8J6nNWJkR0NglqmlZ4=
|
|
||||||
github.com/gin-contrib/static v1.1.2/go.mod h1:Fw90ozjHCmZBWbgrsqrDvO28YbhKEKzKp8GixhR4yLw=
|
|
||||||
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
|
|
||||||
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
|
|
||||||
github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk=
|
github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk=
|
||||||
github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
||||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
|
||||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
|
||||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
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.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
|
||||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs=
|
||||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns=
|
||||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
github.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M=
|
||||||
github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
|
github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I=
|
||||||
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM=
|
||||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
|
||||||
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
|
||||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
github.com/golang-migrate/migrate/v4 v4.18.1 h1:JML/k+t4tpHCpQTCAD62Nu43NUFzHY4CV3uAuvHGC+Y=
|
github.com/golang-migrate/migrate/v4 v4.18.1 h1:JML/k+t4tpHCpQTCAD62Nu43NUFzHY4CV3uAuvHGC+Y=
|
||||||
github.com/golang-migrate/migrate/v4 v4.18.1/go.mod h1:HAX6m3sQgcdO81tdjn5exv20+3Kb13cmGli1hrD6hks=
|
github.com/golang-migrate/migrate/v4 v4.18.1/go.mod h1:HAX6m3sQgcdO81tdjn5exv20+3Kb13cmGli1hrD6hks=
|
||||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
|
||||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
||||||
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||||
github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0=
|
|
||||||
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
|
|
||||||
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
|
|
||||||
github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
|
|
||||||
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
|
|
||||||
github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
|
|
||||||
github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
|
|
||||||
github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
|
|
||||||
github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
|
|
||||||
github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
|
|
||||||
github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
|
|
||||||
github.com/jackc/pgconn v1.14.3 h1:bVoTr12EGANZz66nZPkMInAV/KHD2TxH9npjXXgiB3w=
|
|
||||||
github.com/jackc/pgconn v1.14.3/go.mod h1:RZbme4uasqzybK2RK5c65VsHxoyaml09lx3tXOcO/VM=
|
|
||||||
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
|
|
||||||
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
|
|
||||||
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
|
|
||||||
github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c=
|
|
||||||
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak=
|
|
||||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||||
github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A=
|
|
||||||
github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
|
|
||||||
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
|
|
||||||
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
|
|
||||||
github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
|
|
||||||
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
|
|
||||||
github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
|
||||||
github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
|
||||||
github.com/jackc/pgproto3/v2 v2.3.3 h1:1HLSx5H+tXR9pW3in3zaztoEwQYRC9SQaYUHjTSUOag=
|
|
||||||
github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
|
||||||
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
|
|
||||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
|
||||||
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA=
|
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA=
|
||||||
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||||
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
|
|
||||||
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
|
|
||||||
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
|
|
||||||
github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
|
|
||||||
github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
|
|
||||||
github.com/jackc/pgtype v1.14.3 h1:h6W9cPuHsRWQFTWUZMAKMgG5jSwQI0Zurzdvlx3Plus=
|
|
||||||
github.com/jackc/pgtype v1.14.3/go.mod h1:aKeozOde08iifGosdJpz9MBZonJOUJxqNpPBcMJTlVA=
|
|
||||||
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
|
|
||||||
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
|
|
||||||
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
|
|
||||||
github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
|
|
||||||
github.com/jackc/pgx/v4 v4.18.2 h1:xVpYkNR5pk5bMCZGfClbO962UIqVABcAGt7ha1s/FeU=
|
|
||||||
github.com/jackc/pgx/v4 v4.18.2/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw=
|
|
||||||
github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw=
|
github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw=
|
||||||
github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
|
github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
|
||||||
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
|
||||||
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
|
||||||
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
|
||||||
github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
|
||||||
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
|
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
|
||||||
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
|
||||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
|
||||||
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
|
|
||||||
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
|
||||||
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
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 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/labstack/echo v3.3.10+incompatible h1:pGRcYk231ExFAyoAjAfD85kQzRJCRI8bbnE7CX5OEgg=
|
github.com/labstack/echo/v4 v4.13.3 h1:pwhpCPrTl5qry5HRdM5FwdXnhXSLSY+WE+YQSeCaafY=
|
||||||
github.com/labstack/echo v3.3.10+incompatible/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cVwCLbBmJyDaka6Cmk1s=
|
github.com/labstack/echo/v4 v4.13.3/go.mod h1:o90YNEeQWjDozo584l7AwhJMHN0bOC4tAfg+Xox9q5g=
|
||||||
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
|
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
|
||||||
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
|
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
|
||||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
|
||||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
|
||||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
|
||||||
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
|
||||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
|
||||||
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
|
||||||
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
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-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
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-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
|
||||||
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
|
||||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
|
||||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
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-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
@@ -176,64 +94,37 @@ github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3N
|
|||||||
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
||||||
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
|
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
|
||||||
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
|
||||||
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/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||||
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||||
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
|
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
|
||||||
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
|
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
|
||||||
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
|
||||||
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
|
||||||
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 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
|
||||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
|
||||||
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
|
|
||||||
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
|
|
||||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
|
||||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
|
||||||
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
|
||||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
|
||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
|
||||||
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
||||||
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
|
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
|
||||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
|
||||||
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/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
|
||||||
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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/swaggo/echo-swagger v1.4.1 h1:Yf0uPaJWp1uRtDloZALyLnvdBeoEL5Kc7DtnjzO/TUk=
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/swaggo/echo-swagger v1.4.1/go.mod h1:C8bSi+9yH2FLZsnhqMZLIZddpUxZdBYuNHbtaS1Hljc=
|
||||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
github.com/swaggo/files/v2 v2.0.0 h1:hmAt8Dkynw7Ssz46F6pn8ok6YmGZqHSVLZ+HQM7i0kw=
|
||||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/swaggo/files/v2 v2.0.0/go.mod h1:24kk2Y9NYEJ5lHuCra6iVwkMjIekMCaFq/0JQj66kyM=
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
github.com/swaggo/swag v1.16.4 h1:clWJtd9LStiG3VeijiCfOVODP6VpHtKdQy9ELFG3s1A=
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
github.com/swaggo/swag v1.16.4/go.mod h1:VBsHJRsDvfYvqoiMKnsdwhNV9LEMHgEDZcyVYX0sxPg=
|
||||||
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
|
|
||||||
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
|
||||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||||
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
|
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
|
||||||
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
|
||||||
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0 h1:DheMAlT6POBP+gh8RUH19EOTnQIor5QE0uSRPtzCpSw=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0 h1:DheMAlT6POBP+gh8RUH19EOTnQIor5QE0uSRPtzCpSw=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0/go.mod h1:wZcGmeVO9nzP67aYSLDqXNWK87EZWhi7JWj1v7ZXf94=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0/go.mod h1:wZcGmeVO9nzP67aYSLDqXNWK87EZWhi7JWj1v7ZXf94=
|
||||||
go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U=
|
go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U=
|
||||||
@@ -242,123 +133,42 @@ go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZk
|
|||||||
go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8=
|
go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8=
|
||||||
go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM=
|
go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM=
|
||||||
go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8=
|
go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8=
|
||||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
|
||||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
|
||||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
|
||||||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
|
||||||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
|
||||||
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
|
||||||
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
|
||||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
|
||||||
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
|
||||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
|
||||||
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
|
||||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
|
||||||
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
|
|
||||||
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
|
||||||
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
|
||||||
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
|
||||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
|
||||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
|
||||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
|
||||||
golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ=
|
|
||||||
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
||||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
|
||||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
|
||||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
|
||||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
|
||||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
|
||||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
|
||||||
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
|
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.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
|
||||||
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
||||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
|
||||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
|
||||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|
||||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
|
||||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
|
||||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
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.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||||
|
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 v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
|
||||||
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
|
||||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
|
||||||
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
|
||||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
|
||||||
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
|
||||||
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
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-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 h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
|
||||||
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
|
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
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 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
|
||||||
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
|
||||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
|
||||||
|
|||||||
@@ -1,18 +1,23 @@
|
|||||||
package backend
|
package backend
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"music-server/pkg/db"
|
"music-server/internal/db"
|
||||||
"music-server/pkg/models"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDB() {
|
func TestDB() {
|
||||||
db.Testf()
|
db.Testf()
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetVersionHistory() models.VersionData {
|
type VersionData struct {
|
||||||
data := models.VersionData{Version: "3.2",
|
Version string `json:"version" example:"1.0.0"`
|
||||||
|
Changelog string `json:"changelog" example:"account name"`
|
||||||
|
History []VersionData `json:"history"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetVersionHistory() VersionData {
|
||||||
|
data := VersionData{Version: "3.2",
|
||||||
Changelog: "Upgraded Go version and the version of all dependencies. Fixed som more bugs.",
|
Changelog: "Upgraded Go version and the version of all dependencies. Fixed som more bugs.",
|
||||||
History: []models.VersionData{
|
History: []VersionData{
|
||||||
{
|
{
|
||||||
Version: "3.1",
|
Version: "3.1",
|
||||||
Changelog: "Fixed some bugs with songs not found made the application crash. Now checking if song exists and if not, remove song from DB and find another one. Frontend is now decoupled from the backend.",
|
Changelog: "Fixed some bugs with songs not found made the application crash. Now checking if song exists and if not, remove song from DB and find another one. Frontend is now decoupled from the backend.",
|
||||||
|
|||||||
@@ -3,17 +3,48 @@ package backend
|
|||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"music-server/pkg/db"
|
"music-server/internal/db"
|
||||||
"music-server/pkg/models"
|
"music-server/internal/db/repository"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type SongInfo struct {
|
||||||
|
Game string `json:"Game"`
|
||||||
|
GamePlayed int32 `json:"GamePlayed"`
|
||||||
|
Song string `json:"Song"`
|
||||||
|
SongPlayed int32 `json:"SongPlayed"`
|
||||||
|
CurrentlyPlaying bool `json:"CurrentlyPlaying"`
|
||||||
|
SongNo int `json:"SongNo"`
|
||||||
|
}
|
||||||
|
|
||||||
var currentSong = -1
|
var currentSong = -1
|
||||||
var games []models.GameData
|
|
||||||
var songQue []models.SongData
|
// var games []models.GameData
|
||||||
var lastFetched models.SongData
|
var gamesNew []repository.Game
|
||||||
|
|
||||||
|
// var songQue []models.SongData
|
||||||
|
var songQueNew []repository.Song
|
||||||
|
|
||||||
|
// var lastFetched models.SongData
|
||||||
|
var lastFetchedNew repository.Song
|
||||||
|
var repo *repository.Queries
|
||||||
|
|
||||||
|
func initRepo() {
|
||||||
|
if repo == nil {
|
||||||
|
repo = repository.New(db.Dbpool)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAllGames() []repository.Game {
|
||||||
|
if len(gamesNew) == 0 {
|
||||||
|
initRepo()
|
||||||
|
gamesNew, _ = repo.FindAllGames(db.Ctx)
|
||||||
|
}
|
||||||
|
return gamesNew
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func GetSoundCheckSong() string {
|
func GetSoundCheckSong() string {
|
||||||
files, err := os.ReadDir("songs")
|
files, err := os.ReadDir("songs")
|
||||||
@@ -25,105 +56,125 @@ func GetSoundCheckSong() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Reset() {
|
func Reset() {
|
||||||
songQue = nil
|
songQueNew = nil
|
||||||
currentSong = -1
|
currentSong = -1
|
||||||
games = db.FindAllGames()
|
initRepo()
|
||||||
|
gamesNew, _ = repo.FindAllGames(db.Ctx)
|
||||||
|
//games = db.FindAllGames()
|
||||||
}
|
}
|
||||||
|
|
||||||
func AddLatestToQue() {
|
func AddLatestToQue() {
|
||||||
if lastFetched.Path != "" {
|
if lastFetchedNew.Path != "" {
|
||||||
currentSong = len(songQue)
|
currentSong = len(songQueNew)
|
||||||
songQue = append(songQue, lastFetched)
|
songQueNew = append(songQueNew, lastFetchedNew)
|
||||||
lastFetched = models.SongData{}
|
lastFetchedNew = repository.Song{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func AddLatestPlayed() {
|
func AddLatestPlayed() {
|
||||||
if len(songQue) == 0 {
|
if len(songQueNew) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var currentSongData = songQue[currentSong]
|
currentSongData := songQueNew[currentSong]
|
||||||
|
|
||||||
db.AddGamePlayed(currentSongData.GameId)
|
initRepo()
|
||||||
db.AddSongPlayed(currentSongData.GameId, currentSongData.SongName)
|
repo.AddGamePlayed(db.Ctx, currentSongData.GameID)
|
||||||
|
repo.AddSongPlayed(db.Ctx, repository.AddSongPlayedParams{GameID: currentSongData.GameID, SongName: currentSongData.SongName})
|
||||||
|
//db.AddGamePlayed(currentSongData.GameId)
|
||||||
|
//db.AddSongPlayed(currentSongData.GameId, currentSongData.SongName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetPlayed(songNumber int) {
|
func SetPlayed(songNumber int) {
|
||||||
if len(songQue) == 0 || songNumber >= len(songQue) {
|
if len(songQueNew) == 0 || songNumber >= len(songQueNew) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var songData = songQue[songNumber]
|
songData := songQueNew[songNumber]
|
||||||
db.AddGamePlayed(songData.GameId)
|
initRepo()
|
||||||
db.AddSongPlayed(songData.GameId, songData.SongName)
|
repo.AddGamePlayed(db.Ctx, songData.GameID)
|
||||||
|
repo.AddSongPlayed(db.Ctx, repository.AddSongPlayedParams{GameID: songData.GameID, SongName: songData.SongName})
|
||||||
|
//db.AddGamePlayed(songData.GameId)
|
||||||
|
//db.AddSongPlayed(songData.GameId, songData.SongName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetRandomSong() string {
|
func GetRandomSong() string {
|
||||||
if len(games) == 0 {
|
/*if len(games) == 0 {
|
||||||
games = db.FindAllGames()
|
games = db.FindAllGames()
|
||||||
}
|
}*/
|
||||||
if len(games) == 0 {
|
getAllGames()
|
||||||
|
if len(gamesNew) == 0 {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
song := getSongFromList(games)
|
song := getSongFromList(gamesNew)
|
||||||
lastFetched = song
|
lastFetchedNew = song
|
||||||
return song.Path
|
return song.Path
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetRandomSongLowChance() string {
|
func GetRandomSongLowChance() string {
|
||||||
if len(games) == 0 {
|
/*if len(games) == 0 {
|
||||||
games = db.FindAllGames()
|
games = db.FindAllGames()
|
||||||
}
|
}*/
|
||||||
|
getAllGames()
|
||||||
|
|
||||||
var listOfGames []models.GameData
|
//var listOfGames []models.GameData
|
||||||
|
var listOfGames []repository.Game
|
||||||
|
|
||||||
var averagePlayed = getAveragePlayed(games)
|
var averagePlayed = getAveragePlayed()
|
||||||
|
|
||||||
for _, data := range games {
|
for _, data := range gamesNew {
|
||||||
var timesToAdd = averagePlayed - data.TimesPlayed
|
timesToAdd := averagePlayed - data.TimesPlayed
|
||||||
if timesToAdd <= 0 {
|
if timesToAdd <= 0 {
|
||||||
listOfGames = append(listOfGames, data)
|
listOfGames = append(listOfGames, data)
|
||||||
} else {
|
} else {
|
||||||
for i := 0; i < timesToAdd; i++ {
|
for i := int32(0); i < timesToAdd; i++ {
|
||||||
listOfGames = append(listOfGames, data)
|
listOfGames = append(listOfGames, data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
song := getSongFromList(listOfGames)
|
song := getSongFromList(listOfGames)
|
||||||
|
|
||||||
lastFetched = song
|
lastFetchedNew = song
|
||||||
return song.Path
|
return song.Path
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetRandomSongClassic() string {
|
func GetRandomSongClassic() string {
|
||||||
if games == nil || len(games) == 0 {
|
/*if games == nil || len(games) == 0 {
|
||||||
games = db.FindAllGames()
|
games = db.FindAllGames()
|
||||||
}
|
}*/
|
||||||
|
|
||||||
var listOfAllSongs []models.SongData
|
getAllGames()
|
||||||
for _, game := range games {
|
|
||||||
listOfAllSongs = append(listOfAllSongs, db.FindSongsFromGame(game.Id)...)
|
var listOfAllSongs []repository.Song
|
||||||
|
for _, game := range gamesNew {
|
||||||
|
//listOfAllSongs = append(listOfAllSongs, db.FindSongsFromGame(game.Id)...)
|
||||||
|
songList, _ := repo.FindSongsFromGame(db.Ctx, game.ID)
|
||||||
|
listOfAllSongs = append(listOfAllSongs, songList...)
|
||||||
}
|
}
|
||||||
|
|
||||||
songFound := false
|
songFound := false
|
||||||
var song models.SongData
|
var song repository.Song
|
||||||
for !songFound {
|
for !songFound {
|
||||||
song = listOfAllSongs[rand.Intn(len(listOfAllSongs))]
|
song = listOfAllSongs[rand.Intn(len(listOfAllSongs))]
|
||||||
gameData, err := db.GetGameById(song.GameId)
|
//gameData, err := db.GetGameById(song.GameId)
|
||||||
|
gameData, err := repo.GetGameById(db.Ctx, song.GameID)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
db.RemoveBrokenSong(song)
|
//db.RemoveBrokenSong(song)
|
||||||
log.Println("Song not found, song '" + song.SongName + "' deleted from game '" + gameData.GameName + "' FileName: " + song.FileName)
|
repo.RemoveBrokenSong(db.Ctx, song.Path)
|
||||||
|
//log.Println("Song not found, song '" + song.SongName + "' deleted from game '" + gameData.GameName + "' FileName: " + song.FileName)
|
||||||
|
log.Printf("Song not found, song '%s' deleted from game '%s' FileName: %v\n", song.SongName, gameData.GameName, song.FileName)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
//Check if file exists and open
|
//Check if file exists and open
|
||||||
openFile, err := os.Open(song.Path)
|
openFile, err := os.Open(song.Path)
|
||||||
if err != nil || gameData.Path+song.FileName != song.Path {
|
if err != nil || (song.FileName != nil && gameData.Path+*song.FileName != song.Path) {
|
||||||
//File not found
|
//File not found
|
||||||
db.RemoveBrokenSong(song)
|
//db.RemoveBrokenSong(song)
|
||||||
log.Println("Song not found, song '" + song.SongName + "' deleted from game '" + gameData.GameName + "' FileName: " + song.FileName)
|
repo.RemoveBrokenSong(db.Ctx, song.Path)
|
||||||
|
//log.Println("Song not found, song '" + song.SongName + "' deleted from game '" + gameData.GameName + "' FileName: " + song.FileName)
|
||||||
|
log.Printf("Song not found, song '%s' deleted from game '%s' FileName: %v\n", song.SongName, gameData.GameName, song.FileName)
|
||||||
} else {
|
} else {
|
||||||
songFound = true
|
songFound = true
|
||||||
}
|
}
|
||||||
@@ -132,19 +183,19 @@ func GetRandomSongClassic() string {
|
|||||||
log.Println(err)
|
log.Println(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lastFetched = song
|
lastFetchedNew = song
|
||||||
return song.Path
|
return song.Path
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetSongInfo() models.SongInfo {
|
func GetSongInfo() SongInfo {
|
||||||
if songQue == nil {
|
if songQueNew == nil {
|
||||||
return models.SongInfo{}
|
return SongInfo{}
|
||||||
}
|
}
|
||||||
var currentSongData = songQue[currentSong]
|
var currentSongData = songQueNew[currentSong]
|
||||||
|
|
||||||
currentGameData := getCurrentGame(currentSongData)
|
currentGameData := getCurrentGame(currentSongData)
|
||||||
|
|
||||||
return models.SongInfo{
|
return SongInfo{
|
||||||
Game: currentGameData.GameName,
|
Game: currentGameData.GameName,
|
||||||
GamePlayed: currentGameData.TimesPlayed,
|
GamePlayed: currentGameData.TimesPlayed,
|
||||||
Song: currentSongData.SongName,
|
Song: currentSongData.SongName,
|
||||||
@@ -154,12 +205,12 @@ func GetSongInfo() models.SongInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetPlayedSongs() []models.SongInfo {
|
func GetPlayedSongs() []SongInfo {
|
||||||
var songList []models.SongInfo
|
var songList []SongInfo
|
||||||
|
|
||||||
for i, song := range songQue {
|
for i, song := range songQueNew {
|
||||||
gameData := getCurrentGame(song)
|
gameData := getCurrentGame(song)
|
||||||
songList = append(songList, models.SongInfo{
|
songList = append(songList, SongInfo{
|
||||||
Game: gameData.GameName,
|
Game: gameData.GameName,
|
||||||
GamePlayed: gameData.TimesPlayed,
|
GamePlayed: gameData.TimesPlayed,
|
||||||
Song: song.SongName,
|
Song: song.SongName,
|
||||||
@@ -173,34 +224,36 @@ func GetPlayedSongs() []models.SongInfo {
|
|||||||
|
|
||||||
func GetSong(song string) string {
|
func GetSong(song string) string {
|
||||||
currentSong, _ = strconv.Atoi(song)
|
currentSong, _ = strconv.Atoi(song)
|
||||||
if currentSong >= len(songQue) {
|
if currentSong >= len(songQueNew) {
|
||||||
currentSong = len(songQue) - 1
|
currentSong = len(songQueNew) - 1
|
||||||
} else if currentSong < 0 {
|
} else if currentSong < 0 {
|
||||||
currentSong = 0
|
currentSong = 0
|
||||||
}
|
}
|
||||||
var songData = songQue[currentSong]
|
songData := songQueNew[currentSong]
|
||||||
return songData.Path
|
return songData.Path
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAllGames() []string {
|
func GetAllGames() []string {
|
||||||
if games == nil || len(games) == 0 {
|
/*if games == nil || len(games) == 0 {
|
||||||
games = db.FindAllGames()
|
games = db.FindAllGames()
|
||||||
}
|
}*/
|
||||||
|
getAllGames()
|
||||||
|
|
||||||
var jsonArray []string
|
var jsonArray []string
|
||||||
for _, game := range games {
|
for _, game := range gamesNew {
|
||||||
jsonArray = append(jsonArray, game.GameName)
|
jsonArray = append(jsonArray, game.GameName)
|
||||||
}
|
}
|
||||||
return jsonArray
|
return jsonArray
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAllGamesRandom() []string {
|
func GetAllGamesRandom() []string {
|
||||||
if games == nil || len(games) == 0 {
|
/*if games == nil || len(games) == 0 {
|
||||||
games = db.FindAllGames()
|
games = db.FindAllGames()
|
||||||
}
|
}*/
|
||||||
|
getAllGames()
|
||||||
|
|
||||||
var jsonArray []string
|
var jsonArray []string
|
||||||
for _, game := range games {
|
for _, game := range gamesNew {
|
||||||
jsonArray = append(jsonArray, game.GameName)
|
jsonArray = append(jsonArray, game.GameName)
|
||||||
}
|
}
|
||||||
rand.Shuffle(len(jsonArray), func(i, j int) { jsonArray[i], jsonArray[j] = jsonArray[j], jsonArray[i] })
|
rand.Shuffle(len(jsonArray), func(i, j int) { jsonArray[i], jsonArray[j] = jsonArray[j], jsonArray[i] })
|
||||||
@@ -208,40 +261,41 @@ func GetAllGamesRandom() []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetNextSong() string {
|
func GetNextSong() string {
|
||||||
if songQue == nil {
|
if songQueNew == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
if currentSong == len(songQue)-1 || currentSong == -1 {
|
if currentSong == len(songQueNew)-1 || currentSong == -1 {
|
||||||
var songData = songQue[currentSong]
|
songData := songQueNew[currentSong]
|
||||||
return songData.Path
|
return songData.Path
|
||||||
} else {
|
} else {
|
||||||
currentSong = currentSong + 1
|
currentSong = currentSong + 1
|
||||||
var songData = songQue[currentSong]
|
songData := songQueNew[currentSong]
|
||||||
return songData.Path
|
return songData.Path
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetPreviousSong() string {
|
func GetPreviousSong() string {
|
||||||
if songQue == nil {
|
if songQueNew == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
if currentSong == -1 || currentSong == 0 {
|
if currentSong == -1 || currentSong == 0 {
|
||||||
var songData = songQue[0]
|
songData := songQueNew[0]
|
||||||
return songData.Path
|
return songData.Path
|
||||||
} else {
|
} else {
|
||||||
currentSong = currentSong - 1
|
currentSong = currentSong - 1
|
||||||
var songData = songQue[currentSong]
|
songData := songQueNew[currentSong]
|
||||||
return songData.Path
|
return songData.Path
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSongFromList(games []models.GameData) models.SongData {
|
func getSongFromList(games []repository.Game) repository.Song {
|
||||||
songFound := false
|
songFound := false
|
||||||
var song models.SongData
|
var song repository.Song
|
||||||
for !songFound {
|
for !songFound {
|
||||||
game := getRandomGame(games)
|
game := getRandomGame(games)
|
||||||
//log.Println("game = ", game)
|
//log.Println("game = ", game)
|
||||||
songs := db.FindSongsFromGame(game.Id)
|
//songs := db.FindSongsFromGame(game.Id)
|
||||||
|
songs, _ := repo.FindSongsFromGame(db.Ctx, game.ID)
|
||||||
//log.Println("songs = ", songs)
|
//log.Println("songs = ", songs)
|
||||||
if len(songs) == 0 {
|
if len(songs) == 0 {
|
||||||
continue
|
continue
|
||||||
@@ -254,10 +308,12 @@ func getSongFromList(games []models.GameData) models.SongData {
|
|||||||
//log.Println("game.Path+song.FileName: ", game.Path+song.FileName)
|
//log.Println("game.Path+song.FileName: ", game.Path+song.FileName)
|
||||||
//log.Println("song.Path: ", song.Path)
|
//log.Println("song.Path: ", song.Path)
|
||||||
//log.Println("game.Path+song.FileName != song.Path: ", game.Path+song.FileName != song.Path)
|
//log.Println("game.Path+song.FileName != song.Path: ", game.Path+song.FileName != song.Path)
|
||||||
if err != nil || game.Path+song.FileName != song.Path || strings.HasSuffix(song.FileName, ".wav") {
|
if err != nil || (song.FileName != nil && game.Path+*song.FileName != song.Path) || (song.FileName != nil && strings.HasSuffix(*song.FileName, ".wav")) {
|
||||||
//File not found
|
//File not found
|
||||||
db.RemoveBrokenSong(song)
|
//db.RemoveBrokenSong(song)
|
||||||
log.Println("Song not found, song '" + song.SongName + "' deleted from game '" + game.GameName + "' FileName: " + song.FileName)
|
repo.RemoveBrokenSong(db.Ctx, song.Path)
|
||||||
|
//log.Println("Song not found, song '" + song.SongName + "' deleted from game '" + game.GameName + "' FileName: " + song.FileName)
|
||||||
|
log.Printf("Song not found, song '%s' deleted from game '%s' FileName: %v\n", song.SongName, game.GameName, song.FileName)
|
||||||
} else {
|
} else {
|
||||||
songFound = true
|
songFound = true
|
||||||
}
|
}
|
||||||
@@ -270,23 +326,24 @@ func getSongFromList(games []models.GameData) models.SongData {
|
|||||||
return song
|
return song
|
||||||
}
|
}
|
||||||
|
|
||||||
func getCurrentGame(currentSongData models.SongData) models.GameData {
|
func getCurrentGame(currentSongData repository.Song) repository.Game {
|
||||||
for _, game := range games {
|
for _, game := range gamesNew {
|
||||||
if game.Id == currentSongData.GameId {
|
if game.ID == currentSongData.GameID {
|
||||||
return game
|
return game
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return models.GameData{}
|
return repository.Game{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAveragePlayed(gameList []models.GameData) int {
|
func getAveragePlayed() int32 {
|
||||||
var sum int
|
getAllGames()
|
||||||
for _, data := range gameList {
|
var sum int32
|
||||||
|
for _, data := range gamesNew {
|
||||||
sum += data.TimesPlayed
|
sum += data.TimesPlayed
|
||||||
}
|
}
|
||||||
return sum / len(gameList)
|
return sum / int32(len(gamesNew))
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRandomGame(listOfGames []models.GameData) models.GameData {
|
func getRandomGame(listOfGames []repository.Game) repository.Game {
|
||||||
return listOfGames[rand.Intn(len(listOfGames))]
|
return listOfGames[rand.Intn(len(listOfGames))]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,9 +8,8 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"log"
|
"log"
|
||||||
"music-server/db/repository"
|
"music-server/internal/db"
|
||||||
"music-server/pkg/db"
|
"music-server/internal/db/repository"
|
||||||
"music-server/pkg/models"
|
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -63,203 +62,14 @@ func (gs GameStatus) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var syncWg sync.WaitGroup
|
var syncWg sync.WaitGroup
|
||||||
var repo *repository.Queries
|
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
|
|
||||||
func SyncGames() {
|
|
||||||
start := time.Now()
|
|
||||||
host := os.Getenv("DB_HOST")
|
|
||||||
var dir string
|
|
||||||
if host != "" {
|
|
||||||
dir = "/sorted/"
|
|
||||||
} else {
|
|
||||||
dir = "/Users/sebastian/ResilioSync/Sorterat_test/"
|
|
||||||
}
|
|
||||||
fmt.Printf("dir: %s\n", dir)
|
|
||||||
foldersToSkip := []string{".sync", "dist", "old", "characters"}
|
|
||||||
fmt.Println(foldersToSkip)
|
|
||||||
db.SetGameDeletionDate()
|
|
||||||
checkBrokenSongs()
|
|
||||||
|
|
||||||
files, err := os.ReadDir(dir)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, file := range files {
|
|
||||||
syncGame(file, foldersToSkip, dir)
|
|
||||||
}
|
|
||||||
finished := time.Now()
|
|
||||||
totalTime := finished.Sub(start)
|
|
||||||
out := time.Time{}.Add(totalTime)
|
|
||||||
fmt.Printf("\nTotal time: %v\n", totalTime)
|
|
||||||
fmt.Printf("Total time: %v\n", out.Format("15:04:05.00000"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func SyncGamesQuick() {
|
|
||||||
start := time.Now()
|
|
||||||
host := os.Getenv("DB_HOST")
|
|
||||||
var dir string
|
|
||||||
if host != "" {
|
|
||||||
dir = "/sorted/"
|
|
||||||
} else {
|
|
||||||
dir = "/Users/sebastian/ResilioSync/Sorterat_test/"
|
|
||||||
}
|
|
||||||
fmt.Printf("dir: %s\n", dir)
|
|
||||||
foldersToSkip := []string{".sync", "dist", "old", "characters"}
|
|
||||||
fmt.Println(foldersToSkip)
|
|
||||||
db.SetGameDeletionDate()
|
|
||||||
checkBrokenSongs()
|
|
||||||
|
|
||||||
files, err := os.ReadDir(dir)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, file := range files {
|
|
||||||
wg.Add(1)
|
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
syncGame(file, foldersToSkip, dir)
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
wg.Wait()
|
|
||||||
finished := time.Now()
|
|
||||||
totalTime := finished.Sub(start)
|
|
||||||
out := time.Time{}.Add(totalTime)
|
|
||||||
fmt.Printf("\nTotal time: %v\n", totalTime)
|
|
||||||
fmt.Printf("Total time: %v\n", out.Format("15:04:05.00000"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func syncGame(file os.DirEntry, foldersToSkip []string, dir string) {
|
|
||||||
if file.IsDir() && !contains(foldersToSkip, file.Name()) {
|
|
||||||
fmt.Println(file.Name())
|
|
||||||
path := dir + file.Name() + "/"
|
|
||||||
fmt.Println(path)
|
|
||||||
|
|
||||||
entries, err := os.ReadDir(path)
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
}
|
|
||||||
id := -1
|
|
||||||
for _, entry := range entries {
|
|
||||||
fileInfo, err := entry.Info()
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
}
|
|
||||||
id = getIdFromFile(fileInfo)
|
|
||||||
if id != -1 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if id == -1 {
|
|
||||||
addNewGame(file.Name(), path)
|
|
||||||
} else {
|
|
||||||
checkIfChanged(id, file.Name(), path)
|
|
||||||
checkSongs(path, id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ResetDB() {
|
func ResetDB() {
|
||||||
db.ClearSongs(-1)
|
//db.ClearSongs(-1)
|
||||||
db.ClearGames()
|
repo.ClearSongs(db.Ctx)
|
||||||
|
//db.ClearGames()
|
||||||
|
repo.ClearGames(db.Ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getIdFromFile(file os.FileInfo) int {
|
|
||||||
name := file.Name()
|
|
||||||
if !file.IsDir() && strings.HasSuffix(name, ".id") {
|
|
||||||
name = strings.Replace(name, ".id", "", 1)
|
|
||||||
name = strings.Replace(name, ".", "", 1)
|
|
||||||
i, _ := strconv.Atoi(name)
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkIfChanged(id int, name string, path string) {
|
|
||||||
fmt.Printf("Id from file: %v\n", id)
|
|
||||||
nameFromDb := db.GetGameName(id)
|
|
||||||
fmt.Printf("Name from file: %v\n", name)
|
|
||||||
fmt.Printf("Name from DB: %v\n", nameFromDb)
|
|
||||||
if nameFromDb == "" {
|
|
||||||
fmt.Println("Not in db")
|
|
||||||
db.InsertGameWithExistingId(id, name, path)
|
|
||||||
fmt.Println("Added to db")
|
|
||||||
} else if name != nameFromDb {
|
|
||||||
fmt.Println("Diff name")
|
|
||||||
db.UpdateGameName(id, name, path)
|
|
||||||
checkBrokenSongs()
|
|
||||||
}
|
|
||||||
db.RemoveDeletionDate(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
func addNewGame(name string, path string) {
|
|
||||||
newId := db.GetIdByGameName(name)
|
|
||||||
if newId != -1 {
|
|
||||||
checkBrokenSongs()
|
|
||||||
db.RemoveDeletionDate(newId)
|
|
||||||
} else {
|
|
||||||
newId = db.InsertGame(name, path)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("newId = %v", newId)
|
|
||||||
fileName := path + "/." + strconv.Itoa(newId) + ".id"
|
|
||||||
fmt.Printf("fileName = %v", fileName)
|
|
||||||
|
|
||||||
err := os.WriteFile(fileName, nil, 0644)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
checkSongs(path, newId)
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkSongs(gameDir string, gameId int) {
|
|
||||||
files, err := os.ReadDir(gameDir)
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
}
|
|
||||||
for _, file := range files {
|
|
||||||
entry, err := file.Info()
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
}
|
|
||||||
if isSong(entry) {
|
|
||||||
path := gameDir + entry.Name()
|
|
||||||
fileName := entry.Name()
|
|
||||||
songName, _ := strings.CutSuffix(fileName, ".mp3")
|
|
||||||
if db.CheckSong(path) {
|
|
||||||
db.UpdateSong(songName, fileName, path)
|
|
||||||
} else {
|
|
||||||
db.AddSong(models.SongData{GameId: gameId, SongName: songName, Path: path, FileName: fileName})
|
|
||||||
}
|
|
||||||
} else if isCoverImage(entry) {
|
|
||||||
//TODO: Later add cover art image here in db
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//TODO: Add number of songs here
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkBrokenSongs() {
|
|
||||||
allSongs := db.FetchAllSongs()
|
|
||||||
var brokenSongs []models.SongData
|
|
||||||
for _, song := range allSongs {
|
|
||||||
//Check if file exists and open
|
|
||||||
openFile, err := os.Open(song.Path)
|
|
||||||
if err != nil {
|
|
||||||
//File not found
|
|
||||||
brokenSongs = append(brokenSongs, song)
|
|
||||||
fmt.Printf("song broken: %v", song.Path)
|
|
||||||
} else {
|
|
||||||
err = openFile.Close()
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
db.RemoveBrokenSongs(brokenSongs)
|
|
||||||
}
|
|
||||||
func SyncGamesNewFull() Response {
|
func SyncGamesNewFull() Response {
|
||||||
return syncGamesNew(true)
|
return syncGamesNew(true)
|
||||||
}
|
}
|
||||||
@@ -271,7 +81,7 @@ func SyncGamesNewOnlyChanges() Response {
|
|||||||
func syncGamesNew(full bool) Response {
|
func syncGamesNew(full bool) Response {
|
||||||
musicPath := os.Getenv("MUSIC_PATH")
|
musicPath := os.Getenv("MUSIC_PATH")
|
||||||
fmt.Printf("dir: %s\n", musicPath)
|
fmt.Printf("dir: %s\n", musicPath)
|
||||||
repo = repository.New(db.Dbpool)
|
initRepo()
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
foldersToSkip := []string{".sync", "dist", "old", "characters"}
|
foldersToSkip := []string{".sync", "dist", "old", "characters"}
|
||||||
fmt.Println(foldersToSkip)
|
fmt.Println(foldersToSkip)
|
||||||
|
|||||||
103
internal/database/game.go
Normal file
103
internal/database/game.go
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
package database
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"music-server/internal/db"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type gameData struct {
|
||||||
|
Id int
|
||||||
|
GameName string
|
||||||
|
Added time.Time
|
||||||
|
Deleted time.Time
|
||||||
|
LastChanged time.Time
|
||||||
|
Path string
|
||||||
|
TimesPlayed int
|
||||||
|
LastPlayed time.Time
|
||||||
|
NumberOfSongs int32
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetGameName(gameId int) string {
|
||||||
|
var gameName = ""
|
||||||
|
err := db.Dbpool.QueryRow(db.Ctx,
|
||||||
|
"SELECT game_name FROM game WHERE id = $1", gameId).Scan(&gameName)
|
||||||
|
if err != nil {
|
||||||
|
if compareError.Error() != err.Error() {
|
||||||
|
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return gameName
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetGameDeletionDate() {
|
||||||
|
_, err := db.Dbpool.Exec(db.Ctx,
|
||||||
|
"UPDATE game SET deleted=$1 WHERE deleted IS NULL", time.Now())
|
||||||
|
if err != nil {
|
||||||
|
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateGameName(id int, name string, path string) {
|
||||||
|
_, err := db.Dbpool.Exec(db.Ctx,
|
||||||
|
"UPDATE game SET game_name=$1, path=$2, last_changed=$3 WHERE id=$4",
|
||||||
|
name, path, time.Now(), id)
|
||||||
|
if err != nil {
|
||||||
|
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func RemoveDeletionDate(id int) {
|
||||||
|
_, err := db.Dbpool.Exec(db.Ctx,
|
||||||
|
"UPDATE game SET deleted=null WHERE id=$1", id)
|
||||||
|
if err != nil {
|
||||||
|
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetIdByGameName(name string) int {
|
||||||
|
var gameId = -1
|
||||||
|
err := db.Dbpool.QueryRow(db.Ctx,
|
||||||
|
"SELECT id FROM game WHERE game_name = $1", name).Scan(&gameId)
|
||||||
|
if err != nil {
|
||||||
|
if compareError.Error() != err.Error() {
|
||||||
|
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
return gameId
|
||||||
|
}
|
||||||
|
|
||||||
|
func InsertGame(name string, path string) int {
|
||||||
|
gameId := -1
|
||||||
|
err := db.Dbpool.QueryRow(db.Ctx,
|
||||||
|
"INSERT INTO game(game_name, path, added) VALUES ($1, $2, $3) RETURNING id",
|
||||||
|
name, path, time.Now()).Scan(&gameId)
|
||||||
|
if err != nil {
|
||||||
|
if compareError.Error() != err.Error() {
|
||||||
|
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
||||||
|
}
|
||||||
|
db.ResetGameIdSeq()
|
||||||
|
err2 := db.Dbpool.QueryRow(db.Ctx,
|
||||||
|
"INSERT INTO game(game_name, path, added) VALUES ($1, $2, $3) RETURNING id",
|
||||||
|
name, path, time.Now()).Scan(&gameId)
|
||||||
|
if err2 != nil {
|
||||||
|
if compareError.Error() != err2.Error() {
|
||||||
|
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return gameId
|
||||||
|
}
|
||||||
|
|
||||||
|
func InsertGameWithExistingId(id int, name string, path string) {
|
||||||
|
_, err := db.Dbpool.Exec(db.Ctx,
|
||||||
|
"INSERT INTO game(id, game_name, path, added) VALUES ($1, $2, $3, $4)",
|
||||||
|
id, name, path, time.Now())
|
||||||
|
if err != nil {
|
||||||
|
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
206
internal/database/oldSync.go
Normal file
206
internal/database/oldSync.go
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
package database
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
|
func SyncGames() {
|
||||||
|
start := time.Now()
|
||||||
|
dir := os.Getenv("MUSIC_PATH")
|
||||||
|
fmt.Printf("dir: %s\n", dir)
|
||||||
|
foldersToSkip := []string{".sync", "dist", "old", "characters"}
|
||||||
|
fmt.Println(foldersToSkip)
|
||||||
|
SetGameDeletionDate()
|
||||||
|
checkBrokenSongs()
|
||||||
|
|
||||||
|
files, err := os.ReadDir(dir)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, file := range files {
|
||||||
|
syncGame(file, foldersToSkip, dir)
|
||||||
|
}
|
||||||
|
finished := time.Now()
|
||||||
|
totalTime := finished.Sub(start)
|
||||||
|
out := time.Time{}.Add(totalTime)
|
||||||
|
fmt.Printf("\nTotal time: %v\n", totalTime)
|
||||||
|
fmt.Printf("Total time: %v\n", out.Format("15:04:05.00000"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func SyncGamesQuick() {
|
||||||
|
start := time.Now()
|
||||||
|
dir := os.Getenv("MUSIC_PATH")
|
||||||
|
fmt.Printf("dir: %s\n", dir)
|
||||||
|
foldersToSkip := []string{".sync", "dist", "old", "characters"}
|
||||||
|
fmt.Println(foldersToSkip)
|
||||||
|
SetGameDeletionDate()
|
||||||
|
checkBrokenSongs()
|
||||||
|
|
||||||
|
files, err := os.ReadDir(dir)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, file := range files {
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
syncGame(file, foldersToSkip, dir)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
finished := time.Now()
|
||||||
|
totalTime := finished.Sub(start)
|
||||||
|
out := time.Time{}.Add(totalTime)
|
||||||
|
fmt.Printf("\nTotal time: %v\n", totalTime)
|
||||||
|
fmt.Printf("Total time: %v\n", out.Format("15:04:05.00000"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func syncGame(file os.DirEntry, foldersToSkip []string, dir string) {
|
||||||
|
if file.IsDir() && !contains(foldersToSkip, file.Name()) {
|
||||||
|
fmt.Println(file.Name())
|
||||||
|
path := dir + file.Name() + "/"
|
||||||
|
fmt.Println(path)
|
||||||
|
|
||||||
|
entries, err := os.ReadDir(path)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
id := -1
|
||||||
|
for _, entry := range entries {
|
||||||
|
fileInfo, err := entry.Info()
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
id = getIdFromFile(fileInfo)
|
||||||
|
if id != -1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if id == -1 {
|
||||||
|
addNewGame(file.Name(), path)
|
||||||
|
} else {
|
||||||
|
checkIfChanged(id, file.Name(), path)
|
||||||
|
checkSongs(path, id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getIdFromFile(file os.FileInfo) int {
|
||||||
|
name := file.Name()
|
||||||
|
if !file.IsDir() && strings.HasSuffix(name, ".id") {
|
||||||
|
name = strings.Replace(name, ".id", "", 1)
|
||||||
|
name = strings.Replace(name, ".", "", 1)
|
||||||
|
i, _ := strconv.Atoi(name)
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkIfChanged(id int, name string, path string) {
|
||||||
|
fmt.Printf("Id from file: %v\n", id)
|
||||||
|
nameFromDb := GetGameName(id)
|
||||||
|
fmt.Printf("Name from file: %v\n", name)
|
||||||
|
fmt.Printf("Name from DB: %v\n", nameFromDb)
|
||||||
|
if nameFromDb == "" {
|
||||||
|
fmt.Println("Not in db")
|
||||||
|
InsertGameWithExistingId(id, name, path)
|
||||||
|
fmt.Println("Added to db")
|
||||||
|
} else if name != nameFromDb {
|
||||||
|
fmt.Println("Diff name")
|
||||||
|
UpdateGameName(id, name, path)
|
||||||
|
checkBrokenSongs()
|
||||||
|
}
|
||||||
|
RemoveDeletionDate(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func addNewGame(name string, path string) {
|
||||||
|
newId := GetIdByGameName(name)
|
||||||
|
if newId != -1 {
|
||||||
|
checkBrokenSongs()
|
||||||
|
RemoveDeletionDate(newId)
|
||||||
|
} else {
|
||||||
|
newId = InsertGame(name, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("newId = %v", newId)
|
||||||
|
fileName := path + "/." + strconv.Itoa(newId) + ".id"
|
||||||
|
fmt.Printf("fileName = %v", fileName)
|
||||||
|
|
||||||
|
err := os.WriteFile(fileName, nil, 0644)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
checkSongs(path, newId)
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkSongs(gameDir string, gameId int) {
|
||||||
|
files, err := os.ReadDir(gameDir)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
for _, file := range files {
|
||||||
|
entry, err := file.Info()
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
if isSong(entry) {
|
||||||
|
path := gameDir + entry.Name()
|
||||||
|
fileName := entry.Name()
|
||||||
|
songName, _ := strings.CutSuffix(fileName, ".mp3")
|
||||||
|
if CheckSong(path) {
|
||||||
|
UpdateSong(songName, fileName, path)
|
||||||
|
} else {
|
||||||
|
AddSong(SongData{GameId: gameId, SongName: songName, Path: path, FileName: fileName})
|
||||||
|
}
|
||||||
|
} else if isCoverImage(entry) {
|
||||||
|
//TODO: Later add cover art image here in db
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//TODO: Add number of songs here
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkBrokenSongs() {
|
||||||
|
allSongs := FetchAllSongs()
|
||||||
|
var brokenSongs []SongData
|
||||||
|
for _, song := range allSongs {
|
||||||
|
//Check if file exists and open
|
||||||
|
openFile, err := os.Open(song.Path)
|
||||||
|
if err != nil {
|
||||||
|
//File not found
|
||||||
|
brokenSongs = append(brokenSongs, song)
|
||||||
|
fmt.Printf("song broken: %v", song.Path)
|
||||||
|
} else {
|
||||||
|
err = openFile.Close()
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RemoveBrokenSongs(brokenSongs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isSong(entry fs.FileInfo) bool {
|
||||||
|
return !entry.IsDir() && strings.HasSuffix(entry.Name(), ".mp3")
|
||||||
|
}
|
||||||
|
|
||||||
|
func isCoverImage(entry fs.FileInfo) bool {
|
||||||
|
return !entry.IsDir() && strings.Contains(entry.Name(), "cover") &&
|
||||||
|
(strings.HasSuffix(entry.Name(), ".jpg") || strings.HasSuffix(entry.Name(), ".png"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func contains(s []string, searchTerm string) bool {
|
||||||
|
i := sort.SearchStrings(s, searchTerm)
|
||||||
|
return i < len(s) && s[i] == searchTerm
|
||||||
|
}
|
||||||
92
internal/database/song.go
Normal file
92
internal/database/song.go
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
package database
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"music-server/internal/db"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SongData struct {
|
||||||
|
GameId int
|
||||||
|
SongName string
|
||||||
|
Path string
|
||||||
|
TimesPlayed int
|
||||||
|
FileName string
|
||||||
|
}
|
||||||
|
|
||||||
|
var compareError = errors.New("no rows in result set")
|
||||||
|
|
||||||
|
func AddSong(song SongData) {
|
||||||
|
_, err := db.Dbpool.Exec(db.Ctx,
|
||||||
|
"INSERT INTO song(game_id, song_name, path, file_name) VALUES ($1, $2, $3, $4)",
|
||||||
|
song.GameId, song.SongName, song.Path, song.FileName)
|
||||||
|
if err != nil {
|
||||||
|
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func CheckSong(songPath string) bool {
|
||||||
|
var path string
|
||||||
|
err := db.Dbpool.QueryRow(db.Ctx,
|
||||||
|
"SELECT path FROM song WHERE path = $1", songPath).Scan(&path)
|
||||||
|
if err != nil {
|
||||||
|
if compareError.Error() != err.Error() {
|
||||||
|
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return path != ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateSong(songName string, fileName string, path string) {
|
||||||
|
_, err := db.Dbpool.Exec(db.Ctx,
|
||||||
|
"UPDATE song SET song_name=$1, file_name=$2 WHERE path = $3",
|
||||||
|
songName, fileName, path)
|
||||||
|
if err != nil {
|
||||||
|
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func FetchAllSongs() []SongData {
|
||||||
|
rows, err := db.Dbpool.Query(db.Ctx,
|
||||||
|
"SELECT song_name, path FROM song")
|
||||||
|
if err != nil {
|
||||||
|
if compareError.Error() != err.Error() {
|
||||||
|
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var songDataList []SongData
|
||||||
|
for rows.Next() {
|
||||||
|
var songName string
|
||||||
|
var path string
|
||||||
|
|
||||||
|
err := rows.Scan(&songName, &path)
|
||||||
|
if err != nil {
|
||||||
|
if compareError.Error() != err.Error() {
|
||||||
|
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
songDataList = append(songDataList, SongData{
|
||||||
|
SongName: songName,
|
||||||
|
Path: path,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return songDataList
|
||||||
|
}
|
||||||
|
|
||||||
|
func RemoveBrokenSongs(songs []SongData) {
|
||||||
|
joined := ""
|
||||||
|
for _, song := range songs {
|
||||||
|
joined += "'" + song.Path + "',"
|
||||||
|
}
|
||||||
|
joined = strings.TrimSuffix(joined, ",")
|
||||||
|
|
||||||
|
_, err := db.Dbpool.Exec(db.Ctx, "DELETE FROM song where path in ($1)", joined)
|
||||||
|
if err != nil {
|
||||||
|
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,10 +3,12 @@ package db
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"embed"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
newDb "music-server/db"
|
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/golang-migrate/migrate/v4"
|
"github.com/golang-migrate/migrate/v4"
|
||||||
"github.com/golang-migrate/migrate/v4/database/postgres"
|
"github.com/golang-migrate/migrate/v4/database/postgres"
|
||||||
@@ -20,6 +22,9 @@ import (
|
|||||||
var Dbpool *pgxpool.Pool
|
var Dbpool *pgxpool.Pool
|
||||||
var Ctx = context.Background()
|
var Ctx = context.Background()
|
||||||
|
|
||||||
|
//go:embed "migrations/*.sql"
|
||||||
|
var MigrationsFs embed.FS
|
||||||
|
|
||||||
func InitDB(host string, port string, user string, password string, dbname string) {
|
func InitDB(host string, port string, user string, password string, dbname string) {
|
||||||
|
|
||||||
psqlInfo := fmt.Sprintf("host=%s port=%s user=%s "+
|
psqlInfo := fmt.Sprintf("host=%s port=%s user=%s "+
|
||||||
@@ -66,7 +71,7 @@ func Testf() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func resetGameIdSeq() {
|
func ResetGameIdSeq() {
|
||||||
_, err := Dbpool.Query(Ctx, "SELECT setval('game_id_seq', (SELECT MAX(id) FROM game)+1);")
|
_, err := Dbpool.Query(Ctx, "SELECT setval('game_id_seq', (SELECT MAX(id) FROM game)+1);")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
|
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
|
||||||
@@ -87,7 +92,7 @@ func Migrate_db(host string, port string, user string, password string, dbname s
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
}
|
}
|
||||||
files, err := iofs.New(newDb.MigrationsFs, "migrations")
|
files, err := iofs.New(MigrationsFs, "migrations")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -132,3 +137,63 @@ func Migrate_db(host string, port string, user string, password string, dbname s
|
|||||||
|
|
||||||
db.Close()
|
db.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Health checks the health of the database connection by pinging the database.
|
||||||
|
// It returns a map with keys indicating various health statistics.
|
||||||
|
func Health() map[string]string {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
stats := make(map[string]string)
|
||||||
|
|
||||||
|
// Ping the database
|
||||||
|
//err := s.db.PingContext(ctx)
|
||||||
|
err := Dbpool.Ping(ctx)
|
||||||
|
if err != nil {
|
||||||
|
stats["status"] = "down"
|
||||||
|
stats["error"] = fmt.Sprintf("db down: %v", err)
|
||||||
|
log.Fatalf("db down: %v", err) // Log the error and terminate the program
|
||||||
|
return stats
|
||||||
|
}
|
||||||
|
|
||||||
|
// Database is up, add more statistics
|
||||||
|
stats["status"] = "up"
|
||||||
|
stats["message"] = "It's healthy"
|
||||||
|
|
||||||
|
// Get database stats (like open connections, in use, idle, etc.)
|
||||||
|
//dbStats := s.db.Stats()
|
||||||
|
dbStats := Dbpool.Stat()
|
||||||
|
//stats["open_connections"] = strconv.Itoa(dbStats.OpenConnections)
|
||||||
|
stats["open_connections"] = strconv.Itoa(int(dbStats.NewConnsCount()))
|
||||||
|
//stats["in_use"] = strconv.Itoa(dbStats.InUse)
|
||||||
|
stats["in_use"] = strconv.Itoa(int(dbStats.AcquiredConns()))
|
||||||
|
//stats["idle"] = strconv.Itoa(dbStats.Idle)
|
||||||
|
stats["idle"] = strconv.Itoa(int(dbStats.IdleConns()))
|
||||||
|
//stats["wait_count"] = strconv.FormatInt(dbStats.WaitCount, 10)
|
||||||
|
stats["wait_count"] = strconv.FormatInt(dbStats.AcquireCount(), 10)
|
||||||
|
//stats["wait_duration"] = dbStats.WaitDuration.String()
|
||||||
|
stats["wait_duration"] = dbStats.AcquireDuration().String()
|
||||||
|
//stats["max_idle_closed"] = strconv.FormatInt(dbStats.MaxIdleClosed, 10)
|
||||||
|
stats["max_idle_closed"] = strconv.FormatInt(dbStats.MaxIdleDestroyCount(), 10)
|
||||||
|
//stats["max_lifetime_closed"] = strconv.FormatInt(dbStats.MaxLifetimeClosed, 10)
|
||||||
|
stats["max_lifetime_closed"] = strconv.FormatInt(dbStats.MaxLifetimeDestroyCount(), 10)
|
||||||
|
|
||||||
|
// Evaluate stats to provide a health message
|
||||||
|
if int(dbStats.NewConnsCount()) > 40 { // Assuming 50 is the max for this example
|
||||||
|
stats["message"] = "The database is experiencing heavy load."
|
||||||
|
}
|
||||||
|
|
||||||
|
if dbStats.AcquireCount() > 1000 {
|
||||||
|
stats["message"] = "The database has a high number of wait events, indicating potential bottlenecks."
|
||||||
|
}
|
||||||
|
|
||||||
|
if dbStats.MaxIdleDestroyCount() > int64(dbStats.NewConnsCount())/2 {
|
||||||
|
stats["message"] = "Many idle connections are being closed, consider revising the connection pool settings."
|
||||||
|
}
|
||||||
|
|
||||||
|
if dbStats.MaxLifetimeDestroyCount() > int64(dbStats.NewConnsCount())/2 {
|
||||||
|
stats["message"] = "Many connections are being closed due to max lifetime, consider increasing max lifetime or revising the connection usage pattern."
|
||||||
|
}
|
||||||
|
|
||||||
|
return stats
|
||||||
|
}
|
||||||
5
internal/db/migrations/000003_fix_times_played.down.sql
Normal file
5
internal/db/migrations/000003_fix_times_played.down.sql
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
Alter table game
|
||||||
|
alter column times_played set null;
|
||||||
|
|
||||||
|
Alter table song
|
||||||
|
alter column times_played set null;
|
||||||
5
internal/db/migrations/000003_fix_times_played.up.sql
Normal file
5
internal/db/migrations/000003_fix_times_played.up.sql
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
Alter table game
|
||||||
|
alter column times_played set not null;
|
||||||
|
|
||||||
|
Alter table song
|
||||||
|
alter column times_played set not null;
|
||||||
@@ -15,7 +15,7 @@ type Game struct {
|
|||||||
Deleted *time.Time `json:"deleted"`
|
Deleted *time.Time `json:"deleted"`
|
||||||
LastChanged *time.Time `json:"last_changed"`
|
LastChanged *time.Time `json:"last_changed"`
|
||||||
Path string `json:"path"`
|
Path string `json:"path"`
|
||||||
TimesPlayed *int32 `json:"times_played"`
|
TimesPlayed int32 `json:"times_played"`
|
||||||
LastPlayed *time.Time `json:"last_played"`
|
LastPlayed *time.Time `json:"last_played"`
|
||||||
NumberOfSongs int32 `json:"number_of_songs"`
|
NumberOfSongs int32 `json:"number_of_songs"`
|
||||||
Hash string `json:"hash"`
|
Hash string `json:"hash"`
|
||||||
@@ -25,7 +25,7 @@ type Song struct {
|
|||||||
GameID int32 `json:"game_id"`
|
GameID int32 `json:"game_id"`
|
||||||
SongName string `json:"song_name"`
|
SongName string `json:"song_name"`
|
||||||
Path string `json:"path"`
|
Path string `json:"path"`
|
||||||
TimesPlayed *int32 `json:"times_played"`
|
TimesPlayed int32 `json:"times_played"`
|
||||||
Hash string `json:"hash"`
|
Hash string `json:"hash"`
|
||||||
FileName *string `json:"file_name"`
|
FileName *string `json:"file_name"`
|
||||||
}
|
}
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
package helpers
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/labstack/echo"
|
|
||||||
)
|
|
||||||
|
|
||||||
func SendSong(ctx echo.Context, Filename string) error {
|
|
||||||
fmt.Println("Client requests: " + Filename)
|
|
||||||
|
|
||||||
//Check if file exists and open
|
|
||||||
openFile, err := os.Open(Filename)
|
|
||||||
if err != nil {
|
|
||||||
//File not found, send 404
|
|
||||||
//http.Error(ctx.Writer, "Song not found.", 404)
|
|
||||||
return ctx.String(http.StatusNotFound, "Song not found.")
|
|
||||||
}
|
|
||||||
defer func(openFile *os.File) {
|
|
||||||
_ = openFile.Close()
|
|
||||||
}(openFile) //Close after function return
|
|
||||||
|
|
||||||
//File is found, create and send the correct headers
|
|
||||||
|
|
||||||
//Get the Content-Type of the file
|
|
||||||
//Create a buffer to store the header of the file in
|
|
||||||
FileHeader := make([]byte, 512)
|
|
||||||
//Copy the headers into the FileHeader buffer
|
|
||||||
_, _ = openFile.Read(FileHeader)
|
|
||||||
//Get content type of file
|
|
||||||
//FileContentType := http.DetectContentType(FileHeader)
|
|
||||||
|
|
||||||
//Get the file size
|
|
||||||
FileStat, _ := openFile.Stat() //Get info from file
|
|
||||||
FileSize := strconv.FormatInt(FileStat.Size(), 10) //Get file size as a string
|
|
||||||
|
|
||||||
//Send the headers
|
|
||||||
//writer.Header().Set("Content-Disposition", "attachment; filename="+Filename)
|
|
||||||
ctx.Response().Header().Set("Content-Type", "audio/mpeg")
|
|
||||||
ctx.Response().Header().Set("Content-Length", FileSize)
|
|
||||||
ctx.Response().Header().Set("Expires", "Tue, 03 Jul 2001 06:00:00 GMT")
|
|
||||||
ctx.Response().Header().Set("Last-Modified", time.Now().String()+" GMT")
|
|
||||||
ctx.Response().Header().Set("Cache-Control", "no-cache, no-store, private, max-age=0")
|
|
||||||
ctx.Response().Header().Set("Pragma", "no-cache")
|
|
||||||
ctx.Response().Header().Set("X-Accel-Expires", "0")
|
|
||||||
|
|
||||||
var etagHeaders = []string{
|
|
||||||
"ETag",
|
|
||||||
"If-Modified-Since",
|
|
||||||
"If-Match",
|
|
||||||
"If-None-Match",
|
|
||||||
"If-Range",
|
|
||||||
"If-Unmodified-Since",
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, v := range etagHeaders {
|
|
||||||
if ctx.Request().Header.Get(v) != "" {
|
|
||||||
ctx.Request().Header.Del(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Send the file
|
|
||||||
//We read 512 bytes from the file already, so we reset the offset back to 0
|
|
||||||
_, _ = openFile.Seek(0, 0)
|
|
||||||
//_, _ = io.Copy(ctx.Writer, openFile) //'Copy' the file to the client
|
|
||||||
return ctx.Stream(http.StatusOK, "audio/mpeg", openFile)
|
|
||||||
}
|
|
||||||
@@ -2,9 +2,10 @@ package server
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"music-server/internal/backend"
|
"music-server/internal/backend"
|
||||||
|
"music-server/internal/db"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/labstack/echo"
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
type IndexHandler struct {
|
type IndexHandler struct {
|
||||||
@@ -14,6 +15,16 @@ func NewIndexHandler() *IndexHandler {
|
|||||||
return &IndexHandler{}
|
return &IndexHandler{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetVersion godoc
|
||||||
|
//
|
||||||
|
// @Summary Getting the version of the backend
|
||||||
|
// @Description get string by ID
|
||||||
|
// @Tags accounts
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} backend.VersionData
|
||||||
|
// @Failure 404 {object} string
|
||||||
|
// @Router /version [get]
|
||||||
func (i *IndexHandler) GetVersion(ctx echo.Context) error {
|
func (i *IndexHandler) GetVersion(ctx echo.Context) error {
|
||||||
versionHistory := backend.GetVersionHistory()
|
versionHistory := backend.GetVersionHistory()
|
||||||
if versionHistory.Version == "" {
|
if versionHistory.Version == "" {
|
||||||
@@ -27,6 +38,10 @@ func (i *IndexHandler) GetDBTest(ctx echo.Context) error {
|
|||||||
return ctx.JSON(http.StatusOK, "TestedDB")
|
return ctx.JSON(http.StatusOK, "TestedDB")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *IndexHandler) HealthCheck(ctx echo.Context) error {
|
||||||
|
return ctx.JSON(http.StatusOK, db.Health())
|
||||||
|
}
|
||||||
|
|
||||||
func (i *IndexHandler) GetCharacters(ctx echo.Context) error {
|
func (i *IndexHandler) GetCharacters(ctx echo.Context) error {
|
||||||
characters := backend.GetCharacters()
|
characters := backend.GetCharacters()
|
||||||
return ctx.JSON(http.StatusOK, characters)
|
return ctx.JSON(http.StatusOK, characters)
|
||||||
|
|||||||
@@ -2,11 +2,10 @@ package server
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"music-server/internal/backend"
|
"music-server/internal/backend"
|
||||||
"music-server/internal/helpers"
|
|
||||||
"music-server/pkg/models"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
|
|
||||||
"github.com/labstack/echo"
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MusicHandler struct {
|
type MusicHandler struct {
|
||||||
@@ -21,13 +20,23 @@ func (m *MusicHandler) GetSong(ctx echo.Context) error {
|
|||||||
if song == "" {
|
if song == "" {
|
||||||
return ctx.String(http.StatusBadRequest, "song can't be empty")
|
return ctx.String(http.StatusBadRequest, "song can't be empty")
|
||||||
}
|
}
|
||||||
s := backend.GetSong(song)
|
songPath := backend.GetSong(song)
|
||||||
return helpers.SendSong(ctx, s)
|
file, err := os.Open(songPath)
|
||||||
|
if err != nil {
|
||||||
|
return echo.NewHTTPError(http.StatusNotFound, err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
return ctx.Stream(http.StatusOK, "audio/mpeg", file)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MusicHandler) GetSoundCheckSong(ctx echo.Context) error {
|
func (m *MusicHandler) GetSoundCheckSong(ctx echo.Context) error {
|
||||||
song := backend.GetSoundCheckSong()
|
songPath := backend.GetSoundCheckSong()
|
||||||
return helpers.SendSong(ctx, song)
|
file, err := os.Open(songPath)
|
||||||
|
if err != nil {
|
||||||
|
return echo.NewHTTPError(http.StatusNotFound, err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
return ctx.Stream(http.StatusOK, "audio/mpeg", file)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MusicHandler) ResetMusic(ctx echo.Context) error {
|
func (m *MusicHandler) ResetMusic(ctx echo.Context) error {
|
||||||
@@ -36,18 +45,33 @@ func (m *MusicHandler) ResetMusic(ctx echo.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *MusicHandler) GetRandomSong(ctx echo.Context) error {
|
func (m *MusicHandler) GetRandomSong(ctx echo.Context) error {
|
||||||
song := backend.GetRandomSong()
|
songPath := backend.GetRandomSong()
|
||||||
return helpers.SendSong(ctx, song)
|
file, err := os.Open(songPath)
|
||||||
|
if err != nil {
|
||||||
|
return echo.NewHTTPError(http.StatusNotFound, err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
return ctx.Stream(http.StatusOK, "audio/mpeg", file)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MusicHandler) GetRandomSongLowChance(ctx echo.Context) error {
|
func (m *MusicHandler) GetRandomSongLowChance(ctx echo.Context) error {
|
||||||
song := backend.GetRandomSongLowChance()
|
songPath := backend.GetRandomSongLowChance()
|
||||||
return helpers.SendSong(ctx, song)
|
file, err := os.Open(songPath)
|
||||||
|
if err != nil {
|
||||||
|
return echo.NewHTTPError(http.StatusNotFound, err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
return ctx.Stream(http.StatusOK, "audio/mpeg", file)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MusicHandler) GetRandomSongClassic(ctx echo.Context) error {
|
func (m *MusicHandler) GetRandomSongClassic(ctx echo.Context) error {
|
||||||
song := backend.GetRandomSongClassic()
|
songPath := backend.GetRandomSongClassic()
|
||||||
return helpers.SendSong(ctx, song)
|
file, err := os.Open(songPath)
|
||||||
|
if err != nil {
|
||||||
|
return echo.NewHTTPError(http.StatusNotFound, err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
return ctx.Stream(http.StatusOK, "audio/mpeg", file)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MusicHandler) GetSongInfo(ctx echo.Context) error {
|
func (m *MusicHandler) GetSongInfo(ctx echo.Context) error {
|
||||||
@@ -61,13 +85,23 @@ func (m *MusicHandler) GetPlayedSongs(ctx echo.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *MusicHandler) GetNextSong(ctx echo.Context) error {
|
func (m *MusicHandler) GetNextSong(ctx echo.Context) error {
|
||||||
song := backend.GetNextSong()
|
songPath := backend.GetNextSong()
|
||||||
return helpers.SendSong(ctx, song)
|
file, err := os.Open(songPath)
|
||||||
|
if err != nil {
|
||||||
|
return echo.NewHTTPError(http.StatusNotFound, err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
return ctx.Stream(http.StatusOK, "audio/mpeg", file)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MusicHandler) GetPreviousSong(ctx echo.Context) error {
|
func (m *MusicHandler) GetPreviousSong(ctx echo.Context) error {
|
||||||
song := backend.GetPreviousSong()
|
songPath := backend.GetPreviousSong()
|
||||||
return helpers.SendSong(ctx, song)
|
file, err := os.Open(songPath)
|
||||||
|
if err != nil {
|
||||||
|
return echo.NewHTTPError(http.StatusNotFound, err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
return ctx.Stream(http.StatusOK, "audio/mpeg", file)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MusicHandler) GetAllGames(ctx echo.Context) error {
|
func (m *MusicHandler) GetAllGames(ctx echo.Context) error {
|
||||||
@@ -80,11 +114,14 @@ func (m *MusicHandler) GetAllGamesRandom(ctx echo.Context) error {
|
|||||||
return ctx.JSON(http.StatusOK, gameList)
|
return ctx.JSON(http.StatusOK, gameList)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type played struct {
|
||||||
|
Song int
|
||||||
|
}
|
||||||
|
|
||||||
func (m *MusicHandler) PutPlayed(ctx echo.Context) error {
|
func (m *MusicHandler) PutPlayed(ctx echo.Context) error {
|
||||||
var played models.Played
|
var played played
|
||||||
err := ctx.Bind(&played)
|
err := ctx.Bind(&played)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
//helpers.NewError(ctx, http.StatusBadRequest, err)
|
|
||||||
return ctx.JSON(http.StatusBadRequest, err)
|
return ctx.JSON(http.StatusBadRequest, err)
|
||||||
}
|
}
|
||||||
backend.SetPlayed(played.Song)
|
backend.SetPlayed(played.Song)
|
||||||
|
|||||||
@@ -7,9 +7,13 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
_ "music-server/cmd/docs"
|
||||||
|
|
||||||
"github.com/a-h/templ"
|
"github.com/a-h/templ"
|
||||||
"github.com/labstack/echo"
|
"github.com/labstack/echo/v4"
|
||||||
"github.com/labstack/echo/middleware"
|
"github.com/labstack/echo/v4/middleware"
|
||||||
|
echoSwagger "github.com/swaggo/echo-swagger" // echo-swagger middleware
|
||||||
|
//_ "github.com/swaggo/echo-swagger/example/docs" // docs is generated by Swag CLI, you have to import it.
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Server) RegisterRoutes() http.Handler {
|
func (s *Server) RegisterRoutes() http.Handler {
|
||||||
@@ -36,9 +40,17 @@ func (s *Server) RegisterRoutes() http.Handler {
|
|||||||
swagger := http.FileServer(http.FS(web.Swagger))
|
swagger := http.FileServer(http.FS(web.Swagger))
|
||||||
e.GET("/swagger/*", echo.WrapHandler(swagger))
|
e.GET("/swagger/*", echo.WrapHandler(swagger))
|
||||||
|
|
||||||
|
swaggerRedirect := func(c echo.Context) error {
|
||||||
|
return c.Redirect(http.StatusMovedPermanently, "/doc/index.html")
|
||||||
|
}
|
||||||
|
e.GET("/doc", swaggerRedirect)
|
||||||
|
e.GET("/doc/", swaggerRedirect)
|
||||||
|
e.GET("/doc/*", echoSwagger.WrapHandler)
|
||||||
|
|
||||||
index := NewIndexHandler()
|
index := NewIndexHandler()
|
||||||
e.GET("/version", index.GetVersion)
|
e.GET("/version", index.GetVersion)
|
||||||
e.GET("/health", index.GetDBTest)
|
e.GET("/dbtest", index.GetDBTest)
|
||||||
|
e.GET("/health", index.HealthCheck)
|
||||||
e.GET("/character", index.GetCharacter)
|
e.GET("/character", index.GetCharacter)
|
||||||
e.GET("/characters", index.GetCharacters)
|
e.GET("/characters", index.GetCharacters)
|
||||||
|
|
||||||
@@ -78,6 +90,5 @@ func (s *Server) RegisterRoutes() http.Handler {
|
|||||||
fmt.Printf(" %s %s\n", r.Method, r.Path)
|
fmt.Printf(" %s %s\n", r.Method, r.Path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package server
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"music-server/pkg/db"
|
"music-server/internal/db"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -17,7 +17,7 @@ type Server struct {
|
|||||||
var (
|
var (
|
||||||
host = os.Getenv("DB_HOST")
|
host = os.Getenv("DB_HOST")
|
||||||
dbPort = os.Getenv("DB_PORT")
|
dbPort = os.Getenv("DB_PORT")
|
||||||
database = os.Getenv("DB_NAME")
|
dbName = os.Getenv("DB_NAME")
|
||||||
username = os.Getenv("DB_USERNAME")
|
username = os.Getenv("DB_USERNAME")
|
||||||
password = os.Getenv("DB_PASSWORD")
|
password = os.Getenv("DB_PASSWORD")
|
||||||
musicPath = os.Getenv("MUSIC_PATH")
|
musicPath = os.Getenv("MUSIC_PATH")
|
||||||
@@ -31,18 +31,18 @@ func NewServer() *http.Server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//conf.SetupDb()
|
//conf.SetupDb()
|
||||||
if host == "" || dbPort == "" || username == "" || password == "" || database == "" || musicPath == "" {
|
if host == "" || dbPort == "" || username == "" || password == "" || dbName == "" || musicPath == "" {
|
||||||
log.Fatal("Invalid settings")
|
log.Fatal("Invalid settings")
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("host: %s, dbPort: %v, username: %s, password: %s, dbName: %s\n",
|
fmt.Printf("host: %s, dbPort: %v, username: %s, password: %s, dbName: %s\n",
|
||||||
host, dbPort, username, password, database)
|
host, dbPort, username, password, dbName)
|
||||||
|
|
||||||
log.Printf("Path: %s\n", musicPath)
|
log.Printf("Path: %s\n", musicPath)
|
||||||
|
|
||||||
db.Migrate_db(host, dbPort, username, password, database)
|
db.Migrate_db(host, dbPort, username, password, dbName)
|
||||||
|
|
||||||
db.InitDB(host, dbPort, username, password, database)
|
db.InitDB(host, dbPort, username, password, dbName)
|
||||||
|
|
||||||
// Declare Server config
|
// Declare Server config
|
||||||
server := &http.Server{
|
server := &http.Server{
|
||||||
|
|||||||
@@ -3,9 +3,10 @@ package server
|
|||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
"music-server/internal/backend"
|
"music-server/internal/backend"
|
||||||
|
"music-server/internal/database"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/labstack/echo"
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SyncHandler struct {
|
type SyncHandler struct {
|
||||||
@@ -16,13 +17,13 @@ func NewSyncHandler() *SyncHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *SyncHandler) SyncGames(ctx echo.Context) error {
|
func (s *SyncHandler) SyncGames(ctx echo.Context) error {
|
||||||
backend.SyncGames()
|
database.SyncGames()
|
||||||
backend.Reset()
|
backend.Reset()
|
||||||
return ctx.JSON(http.StatusOK, "Games are synced")
|
return ctx.JSON(http.StatusOK, "Games are synced")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SyncHandler) SyncGamesQuick(ctx echo.Context) error {
|
func (s *SyncHandler) SyncGamesQuick(ctx echo.Context) error {
|
||||||
backend.SyncGamesQuick()
|
database.SyncGamesQuick()
|
||||||
backend.Reset()
|
backend.Reset()
|
||||||
return ctx.JSON(http.StatusOK, "Games are synced")
|
return ctx.JSON(http.StatusOK, "Games are synced")
|
||||||
}
|
}
|
||||||
|
|||||||
8
justfile
8
justfile
@@ -26,10 +26,18 @@ tailwind-linux:
|
|||||||
@if [ ! -f tailwindcss ]; then curl -sL https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-linux-x64 -o tailwindcss; fi
|
@if [ ! -f tailwindcss ]; then curl -sL https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-linux-x64 -o tailwindcss; fi
|
||||||
@chmod +x tailwindcss
|
@chmod +x tailwindcss
|
||||||
|
|
||||||
|
sqlc-generate:
|
||||||
|
@sqlc generate
|
||||||
|
|
||||||
|
migrate-create name:
|
||||||
|
@migrate create -ext sql -dir internal/db/migrations -seq {{name}}
|
||||||
|
|
||||||
build:
|
build:
|
||||||
@echo "Building..."
|
@echo "Building..."
|
||||||
|
@sqlc generate
|
||||||
@templ generate
|
@templ generate
|
||||||
@./tailwindcss -i cmd/web/assets/css/input.css -o cmd/web/assets/css/output.css
|
@./tailwindcss -i cmd/web/assets/css/input.css -o cmd/web/assets/css/output.css
|
||||||
|
@swag init -d ./cmd/,./internal/backend/ -o ./cmd/docs
|
||||||
@go build -o main cmd/main.go
|
@go build -o main cmd/main.go
|
||||||
|
|
||||||
run:
|
run:
|
||||||
|
|||||||
173
pkg/db/game.go
173
pkg/db/game.go
@@ -1,173 +0,0 @@
|
|||||||
package db
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"music-server/pkg/models"
|
|
||||||
"os"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/jackc/pgtype"
|
|
||||||
)
|
|
||||||
|
|
||||||
func GetGameName(gameId int) string {
|
|
||||||
var gameName = ""
|
|
||||||
err := Dbpool.QueryRow(Ctx,
|
|
||||||
"SELECT game_name FROM game WHERE id = $1", gameId).Scan(&gameName)
|
|
||||||
if err != nil {
|
|
||||||
if compareError.Error() != err.Error() {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return gameName
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetGameById(gameId int) (models.GameData, error) {
|
|
||||||
var id, timesPlayed int
|
|
||||||
var numberOfSongs pgtype.Int4
|
|
||||||
var gameName, path string
|
|
||||||
var added, deleted, lastChanged, lastPlayed pgtype.Timestamp
|
|
||||||
err := Dbpool.QueryRow(Ctx,
|
|
||||||
"SELECT id, game_name, added, deleted, last_changed, path, times_played, last_played, number_of_songs "+
|
|
||||||
"FROM game WHERE id = $1 AND deleted IS NULL ", gameId).Scan(&id, &gameName, &added, &deleted, &lastChanged, &path, ×Played, &lastPlayed, &numberOfSongs)
|
|
||||||
if err != nil {
|
|
||||||
if compareError.Error() != err.Error() {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
|
||||||
}
|
|
||||||
return models.GameData{}, errors.New("Game not found")
|
|
||||||
}
|
|
||||||
return models.GameData{
|
|
||||||
Id: id,
|
|
||||||
GameName: gameName,
|
|
||||||
Added: added.Time,
|
|
||||||
Deleted: deleted.Time,
|
|
||||||
LastChanged: lastChanged.Time,
|
|
||||||
Path: path,
|
|
||||||
TimesPlayed: timesPlayed,
|
|
||||||
LastPlayed: lastPlayed.Time,
|
|
||||||
NumberOfSongs: numberOfSongs.Int,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func SetGameDeletionDate() {
|
|
||||||
_, err := Dbpool.Exec(Ctx,
|
|
||||||
"UPDATE game SET deleted=$1 WHERE deleted IS NULL", time.Now())
|
|
||||||
if err != nil {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ClearGames() {
|
|
||||||
_, err := Dbpool.Exec(Ctx, "DELETE FROM game")
|
|
||||||
if err != nil {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func UpdateGameName(id int, name string, path string) {
|
|
||||||
_, err := Dbpool.Exec(Ctx,
|
|
||||||
"UPDATE game SET game_name=$1, path=$2, last_changed=$3 WHERE id=$4",
|
|
||||||
name, path, time.Now(), id)
|
|
||||||
if err != nil {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func RemoveDeletionDate(id int) {
|
|
||||||
_, err := Dbpool.Exec(Ctx,
|
|
||||||
"UPDATE game SET deleted=null WHERE id=$1", id)
|
|
||||||
if err != nil {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetIdByGameName(name string) int {
|
|
||||||
var gameId = -1
|
|
||||||
err := Dbpool.QueryRow(Ctx,
|
|
||||||
"SELECT id FROM game WHERE game_name = $1", name).Scan(&gameId)
|
|
||||||
if err != nil {
|
|
||||||
if compareError.Error() != err.Error() {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
|
||||||
}
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
return gameId
|
|
||||||
}
|
|
||||||
|
|
||||||
func InsertGame(name string, path string) int {
|
|
||||||
gameId := -1
|
|
||||||
err := Dbpool.QueryRow(Ctx,
|
|
||||||
"INSERT INTO game(game_name, path, added) VALUES ($1, $2, $3) RETURNING id",
|
|
||||||
name, path, time.Now()).Scan(&gameId)
|
|
||||||
if err != nil {
|
|
||||||
if compareError.Error() != err.Error() {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
|
||||||
}
|
|
||||||
resetGameIdSeq()
|
|
||||||
err2 := Dbpool.QueryRow(Ctx,
|
|
||||||
"INSERT INTO game(game_name, path, added) VALUES ($1, $2, $3) RETURNING id",
|
|
||||||
name, path, time.Now()).Scan(&gameId)
|
|
||||||
if err2 != nil {
|
|
||||||
if compareError.Error() != err2.Error() {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
|
||||||
}
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return gameId
|
|
||||||
}
|
|
||||||
|
|
||||||
func InsertGameWithExistingId(id int, name string, path string) {
|
|
||||||
_, err := Dbpool.Exec(Ctx,
|
|
||||||
"INSERT INTO game(id, game_name, path, added) VALUES ($1, $2, $3, $4)",
|
|
||||||
id, name, path, time.Now())
|
|
||||||
if err != nil {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func FindAllGames() []models.GameData {
|
|
||||||
rows, err := Dbpool.Query(Ctx,
|
|
||||||
"SELECT id, game_name, added, deleted, last_changed, path, times_played, last_played, number_of_songs "+
|
|
||||||
"FROM game WHERE deleted IS NULL "+
|
|
||||||
"ORDER BY game_name")
|
|
||||||
if err != nil {
|
|
||||||
if compareError.Error() != err.Error() {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var gameList []models.GameData
|
|
||||||
for rows.Next() {
|
|
||||||
var id, timesPlayed int
|
|
||||||
var numberOfSongs pgtype.Int4
|
|
||||||
var gameName, path string
|
|
||||||
var added, deleted, lastChanged, lastPlayed pgtype.Timestamp
|
|
||||||
err := rows.Scan(&id, &gameName, &added, &deleted, &lastChanged, &path, ×Played, &lastPlayed, &numberOfSongs)
|
|
||||||
if err != nil {
|
|
||||||
if compareError.Error() != err.Error() {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
gameList = append(gameList, models.GameData{
|
|
||||||
Id: id,
|
|
||||||
GameName: gameName,
|
|
||||||
Added: added.Time,
|
|
||||||
Deleted: deleted.Time,
|
|
||||||
LastChanged: lastChanged.Time,
|
|
||||||
Path: path,
|
|
||||||
TimesPlayed: timesPlayed,
|
|
||||||
LastPlayed: lastPlayed.Time,
|
|
||||||
NumberOfSongs: numberOfSongs.Int,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return gameList
|
|
||||||
}
|
|
||||||
|
|
||||||
func AddGamePlayed(id int) {
|
|
||||||
_, err := Dbpool.Exec(Ctx,
|
|
||||||
"UPDATE game SET times_played=times_played+1, last_played=now() WHERE id=$1", id)
|
|
||||||
if err != nil {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
148
pkg/db/song.go
148
pkg/db/song.go
@@ -1,148 +0,0 @@
|
|||||||
package db
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"music-server/pkg/models"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
var compareError = errors.New("no rows in result set")
|
|
||||||
|
|
||||||
func ClearSongs(gameId int) {
|
|
||||||
if gameId == -1 {
|
|
||||||
_, err := Dbpool.Exec(Ctx, "DELETE FROM song")
|
|
||||||
if err != nil {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_, err := Dbpool.Exec(Ctx, "DELETE FROM song where game_id=$1", gameId)
|
|
||||||
if err != nil {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func AddSong(song models.SongData) {
|
|
||||||
_, err := Dbpool.Exec(Ctx,
|
|
||||||
"INSERT INTO song(game_id, song_name, path, file_name) VALUES ($1, $2, $3, $4)",
|
|
||||||
song.GameId, song.SongName, song.Path, song.FileName)
|
|
||||||
if err != nil {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func CheckSong(songPath string) bool {
|
|
||||||
var path string
|
|
||||||
err := Dbpool.QueryRow(Ctx,
|
|
||||||
"SELECT path FROM song WHERE path = $1", songPath).Scan(&path)
|
|
||||||
if err != nil {
|
|
||||||
if compareError.Error() != err.Error() {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return path != ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func UpdateSong(songName string, fileName string, path string) {
|
|
||||||
_, err := Dbpool.Exec(Ctx,
|
|
||||||
"UPDATE song SET song_name=$1, file_name=$2 WHERE path = $3",
|
|
||||||
songName, fileName, path)
|
|
||||||
if err != nil {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func FindSongsFromGame(id int) []models.SongData {
|
|
||||||
rows, err := Dbpool.Query(Ctx,
|
|
||||||
"SELECT song_name, path, file_name, times_played FROM song WHERE game_id = $1", id)
|
|
||||||
if err != nil {
|
|
||||||
if compareError.Error() != err.Error() {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var songDataList []models.SongData
|
|
||||||
for rows.Next() {
|
|
||||||
var songName string
|
|
||||||
var path string
|
|
||||||
var fileName string
|
|
||||||
var timesPlayed int
|
|
||||||
|
|
||||||
err := rows.Scan(&songName, &path, &fileName, ×Played)
|
|
||||||
if err != nil {
|
|
||||||
if compareError.Error() != err.Error() {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
songDataList = append(songDataList, models.SongData{
|
|
||||||
GameId: id,
|
|
||||||
SongName: songName,
|
|
||||||
Path: path,
|
|
||||||
FileName: fileName,
|
|
||||||
TimesPlayed: timesPlayed,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return songDataList
|
|
||||||
}
|
|
||||||
|
|
||||||
func AddSongPlayed(id int, name string) {
|
|
||||||
_, err := Dbpool.Exec(Ctx,
|
|
||||||
"UPDATE song SET times_played=times_played+1 WHERE game_id=$1 AND song_name=$2", id, name)
|
|
||||||
if err != nil {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func FetchAllSongs() []models.SongData {
|
|
||||||
rows, err := Dbpool.Query(Ctx,
|
|
||||||
"SELECT song_name, path FROM song")
|
|
||||||
if err != nil {
|
|
||||||
if compareError.Error() != err.Error() {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var songDataList []models.SongData
|
|
||||||
for rows.Next() {
|
|
||||||
var songName string
|
|
||||||
var path string
|
|
||||||
|
|
||||||
err := rows.Scan(&songName, &path)
|
|
||||||
if err != nil {
|
|
||||||
if compareError.Error() != err.Error() {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
songDataList = append(songDataList, models.SongData{
|
|
||||||
SongName: songName,
|
|
||||||
Path: path,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return songDataList
|
|
||||||
}
|
|
||||||
|
|
||||||
func RemoveBrokenSong(song models.SongData) {
|
|
||||||
_, err := Dbpool.Exec(Ctx, "DELETE FROM song where path=$1", song.Path)
|
|
||||||
if err != nil {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func RemoveBrokenSongs(songs []models.SongData) {
|
|
||||||
joined := ""
|
|
||||||
for _, song := range songs {
|
|
||||||
joined += "'" + song.Path + "',"
|
|
||||||
}
|
|
||||||
joined = strings.TrimSuffix(joined, ",")
|
|
||||||
|
|
||||||
_, err := Dbpool.Exec(Ctx, "DELETE FROM song where path in ($1)", joined)
|
|
||||||
if err != nil {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
package db
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"music-server/pkg/models"
|
|
||||||
"os"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func InsertSongInList(song models.SongListData) {
|
|
||||||
_, err := Dbpool.Exec(Ctx,
|
|
||||||
`INSERT INTO song_list (match_date, match_id, song_no, game_name, song_name) VALUES ($1, $2, $3, $4, $5)`,
|
|
||||||
song.MatchDate, song.MatchId, song.SongNo, song.GameName, song.SongName)
|
|
||||||
if err != nil {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetSongList(matchId int) []models.SongListData {
|
|
||||||
rows, err := Dbpool.Query(Ctx,
|
|
||||||
"SELECT match_date, match_id, song_no, game_name, song_name "+
|
|
||||||
"FROM song_list WHERE match_date = $1"+
|
|
||||||
"ORDER BY song_no DESC", matchId)
|
|
||||||
if err != nil {
|
|
||||||
if compareError.Error() != err.Error() {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var songList []models.SongListData
|
|
||||||
for rows.Next() {
|
|
||||||
var matchId, songNo int
|
|
||||||
var matchDate time.Time
|
|
||||||
var gameName, songName string
|
|
||||||
err := rows.Scan(&matchDate, &matchId, &songNo, &gameName, &songName)
|
|
||||||
if err != nil {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "Scan failed: %v\n", err)
|
|
||||||
}
|
|
||||||
songList = append(songList, models.SongListData{
|
|
||||||
MatchDate: matchDate,
|
|
||||||
MatchId: matchId,
|
|
||||||
SongNo: songNo,
|
|
||||||
GameName: gameName,
|
|
||||||
SongName: songName,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return songList
|
|
||||||
}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
package models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Played struct {
|
|
||||||
Song int
|
|
||||||
}
|
|
||||||
|
|
||||||
type VersionData struct {
|
|
||||||
Version string `json:"version" example:"1.0.0swagger.yaml"`
|
|
||||||
Changelog string `json:"changelog" example:"account name"`
|
|
||||||
History []VersionData `json:"history"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type SongInfo struct {
|
|
||||||
Game string `json:"Game"`
|
|
||||||
GamePlayed int `json:"GamePlayed"`
|
|
||||||
Song string `json:"Song"`
|
|
||||||
SongPlayed int `json:"SongPlayed"`
|
|
||||||
CurrentlyPlaying bool `json:"CurrentlyPlaying"`
|
|
||||||
SongNo int `json:"SongNo"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type GameData struct {
|
|
||||||
Id int
|
|
||||||
GameName string
|
|
||||||
Added time.Time
|
|
||||||
Deleted time.Time
|
|
||||||
LastChanged time.Time
|
|
||||||
Path string
|
|
||||||
TimesPlayed int
|
|
||||||
LastPlayed time.Time
|
|
||||||
NumberOfSongs int32
|
|
||||||
}
|
|
||||||
|
|
||||||
type SongData struct {
|
|
||||||
GameId int
|
|
||||||
SongName string
|
|
||||||
Path string
|
|
||||||
TimesPlayed int
|
|
||||||
FileName string
|
|
||||||
}
|
|
||||||
|
|
||||||
type SongListData struct {
|
|
||||||
MatchDate time.Time
|
|
||||||
MatchId int
|
|
||||||
SongNo int
|
|
||||||
GameName string
|
|
||||||
SongName string
|
|
||||||
}
|
|
||||||
|
|
||||||
type VgmqData struct {
|
|
||||||
SongNo int
|
|
||||||
Path string
|
|
||||||
Clue string
|
|
||||||
Answered bool
|
|
||||||
Answer string
|
|
||||||
}
|
|
||||||
10
sqlc.yaml
10
sqlc.yaml
@@ -1,13 +1,13 @@
|
|||||||
version: "2"
|
version: "2"
|
||||||
sql:
|
sql:
|
||||||
- engine: "postgresql"
|
- engine: "postgresql"
|
||||||
queries: "./db/queries"
|
queries: "./internal/db/queries"
|
||||||
schema: "./db/migrations"
|
schema: "./internal/db/migrations"
|
||||||
gen:
|
gen:
|
||||||
go:
|
go:
|
||||||
emit_json_tags: true
|
emit_json_tags: true
|
||||||
package: "repository"
|
package: "repository"
|
||||||
out: "db/repository"
|
out: "internal/db/repository"
|
||||||
sql_package: "pgx/v5"
|
sql_package: "pgx/v5"
|
||||||
overrides:
|
overrides:
|
||||||
- db_type: "pg_catalog.timestamp"
|
- db_type: "pg_catalog.timestamp"
|
||||||
@@ -30,6 +30,10 @@ sql:
|
|||||||
go_type:
|
go_type:
|
||||||
pointer: true
|
pointer: true
|
||||||
type: "int32"
|
type: "int32"
|
||||||
|
- db_type: "int4"
|
||||||
|
nullable: false
|
||||||
|
go_type:
|
||||||
|
type: "int32"
|
||||||
- db_type: "date"
|
- db_type: "date"
|
||||||
nullable: false
|
nullable: false
|
||||||
go_type:
|
go_type:
|
||||||
|
|||||||
Reference in New Issue
Block a user