diff --git a/cmd/main.go b/cmd/main.go index ab112ee..79cea88 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -1,17 +1,65 @@ package main import ( - "embed" + "context" + "fmt" + "log" + "music-server/internal/server" "music-server/pkg/conf" + "net/http" + "os/signal" + "syscall" + "time" ) -//go:embed swagger -var swagger embed.FS +func gracefulShutdown(apiServer *http.Server, done chan bool) { + // Create context that listens for the interrupt signal from the OS. + ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) + defer stop() + + // Listen for the interrupt signal. + <-ctx.Done() + + log.Println("shutting down gracefully, press Ctrl+C again to force") + conf.CloseDb() + + // The context is used to inform the server it has 5 seconds to finish + // the request it is currently handling + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + if err := apiServer.Shutdown(ctx); err != nil { + log.Printf("Server forced to shutdown with error: %v", err) + } + + log.Println("Server exiting") + + // Notify the main goroutine that the shutdown is complete + done <- true +} func main() { - conf.SetupDb() - conf.SetupRestServer(swagger) + server := server.NewServer() - conf.CloseDb() + // 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() } diff --git a/cmd/web/efs.go b/cmd/web/efs.go index 57b9761..27c9b95 100644 --- a/cmd/web/efs.go +++ b/cmd/web/efs.go @@ -3,4 +3,7 @@ package web import "embed" //go:embed "assets" -var Files embed.FS +var Assets embed.FS + +//go:embed "swagger" +var Swagger embed.FS diff --git a/cmd/swagger/favicon-16x16.png b/cmd/web/swagger/favicon-16x16.png similarity index 100% rename from cmd/swagger/favicon-16x16.png rename to cmd/web/swagger/favicon-16x16.png diff --git a/cmd/swagger/favicon-32x32.png b/cmd/web/swagger/favicon-32x32.png similarity index 100% rename from cmd/swagger/favicon-32x32.png rename to cmd/web/swagger/favicon-32x32.png diff --git a/cmd/swagger/index.html b/cmd/web/swagger/index.html similarity index 100% rename from cmd/swagger/index.html rename to cmd/web/swagger/index.html diff --git a/cmd/swagger/oauth2-redirect.html b/cmd/web/swagger/oauth2-redirect.html similarity index 100% rename from cmd/swagger/oauth2-redirect.html rename to cmd/web/swagger/oauth2-redirect.html diff --git a/cmd/swagger/swagger-ui-bundle.js b/cmd/web/swagger/swagger-ui-bundle.js similarity index 100% rename from cmd/swagger/swagger-ui-bundle.js rename to cmd/web/swagger/swagger-ui-bundle.js diff --git a/cmd/swagger/swagger-ui-bundle.js.map b/cmd/web/swagger/swagger-ui-bundle.js.map similarity index 100% rename from cmd/swagger/swagger-ui-bundle.js.map rename to cmd/web/swagger/swagger-ui-bundle.js.map diff --git a/cmd/swagger/swagger-ui-es-bundle-core.js b/cmd/web/swagger/swagger-ui-es-bundle-core.js similarity index 100% rename from cmd/swagger/swagger-ui-es-bundle-core.js rename to cmd/web/swagger/swagger-ui-es-bundle-core.js diff --git a/cmd/swagger/swagger-ui-es-bundle-core.js.map b/cmd/web/swagger/swagger-ui-es-bundle-core.js.map similarity index 100% rename from cmd/swagger/swagger-ui-es-bundle-core.js.map rename to cmd/web/swagger/swagger-ui-es-bundle-core.js.map diff --git a/cmd/swagger/swagger-ui-es-bundle.js b/cmd/web/swagger/swagger-ui-es-bundle.js similarity index 100% rename from cmd/swagger/swagger-ui-es-bundle.js rename to cmd/web/swagger/swagger-ui-es-bundle.js diff --git a/cmd/swagger/swagger-ui-es-bundle.js.map b/cmd/web/swagger/swagger-ui-es-bundle.js.map similarity index 100% rename from cmd/swagger/swagger-ui-es-bundle.js.map rename to cmd/web/swagger/swagger-ui-es-bundle.js.map diff --git a/cmd/swagger/swagger-ui-standalone-preset.js b/cmd/web/swagger/swagger-ui-standalone-preset.js similarity index 100% rename from cmd/swagger/swagger-ui-standalone-preset.js rename to cmd/web/swagger/swagger-ui-standalone-preset.js diff --git a/cmd/swagger/swagger-ui-standalone-preset.js.map b/cmd/web/swagger/swagger-ui-standalone-preset.js.map similarity index 100% rename from cmd/swagger/swagger-ui-standalone-preset.js.map rename to cmd/web/swagger/swagger-ui-standalone-preset.js.map diff --git a/cmd/swagger/swagger-ui.css b/cmd/web/swagger/swagger-ui.css similarity index 100% rename from cmd/swagger/swagger-ui.css rename to cmd/web/swagger/swagger-ui.css diff --git a/cmd/swagger/swagger-ui.css.map b/cmd/web/swagger/swagger-ui.css.map similarity index 100% rename from cmd/swagger/swagger-ui.css.map rename to cmd/web/swagger/swagger-ui.css.map diff --git a/cmd/swagger/swagger-ui.js b/cmd/web/swagger/swagger-ui.js similarity index 100% rename from cmd/swagger/swagger-ui.js rename to cmd/web/swagger/swagger-ui.js diff --git a/cmd/swagger/swagger-ui.js.map b/cmd/web/swagger/swagger-ui.js.map similarity index 100% rename from cmd/swagger/swagger-ui.js.map rename to cmd/web/swagger/swagger-ui.js.map diff --git a/cmd/swagger/swagger.yaml b/cmd/web/swagger/swagger.yaml similarity index 100% rename from cmd/swagger/swagger.yaml rename to cmd/web/swagger/swagger.yaml diff --git a/go.mod b/go.mod index cc03e5b..19dbcec 100644 --- a/go.mod +++ b/go.mod @@ -1,15 +1,18 @@ module music-server -go 1.22.2 +go 1.23 + +toolchain go1.23.4 require ( github.com/MShekow/directory-checksum v1.4.6 - github.com/a-h/templ v0.2.793 + 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/jackc/pgtype v1.14.3 github.com/jackc/pgx/v5 v5.5.5 + github.com/labstack/echo v3.3.10+incompatible github.com/lib/pq v1.10.9 github.com/spf13/afero v1.11.0 gopkg.in/yaml.v3 v3.0.1 @@ -20,6 +23,7 @@ require ( github.com/bytedance/sonic/loader v0.1.1 // indirect github.com/cloudwego/base64x v0.1.4 // 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/gabriel-vasile/mimetype v1.4.3 // indirect github.com/gin-contrib/sse v0.1.0 // indirect @@ -36,21 +40,25 @@ require ( github.com/jackc/puddle/v2 v2.2.1 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect + github.com/labstack/gommon v0.4.2 // indirect github.com/leodido/go-urn v1.4.0 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // 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/fasttemplate v1.2.2 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0 // indirect go.opentelemetry.io/otel/trace v1.32.0 // indirect go.uber.org/atomic v1.7.0 // indirect golang.org/x/arch v0.8.0 // indirect - golang.org/x/crypto v0.27.0 // indirect - golang.org/x/net v0.29.0 // indirect - golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.25.0 // indirect - golang.org/x/text v0.18.0 // indirect + golang.org/x/crypto v0.31.0 // indirect + golang.org/x/net v0.33.0 // indirect + golang.org/x/sync v0.10.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect google.golang.org/protobuf v1.34.2 // indirect ) diff --git a/go.sum b/go.sum index 736f63e..b19d751 100644 --- a/go.sum +++ b/go.sum @@ -6,8 +6,8 @@ github.com/MShekow/directory-checksum v1.4.6/go.mod h1:bMfFBkaIlNk7O9VgEi8D2X7Q2 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/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= -github.com/a-h/templ v0.2.793 h1:Io+/ocnfGWYO4VHdR0zBbf39PQlnzVCVVD+wEEs6/qY= -github.com/a-h/templ v0.2.793/go.mod h1:lq48JXoUvuQrU0VThrK31yFwdRjTCnIE5bcPCM9IP1w= +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/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0= github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4= github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM= @@ -23,6 +23,8 @@ github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7Do github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/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/go.mod h1:zNK8IwktWzQRm6I/l2Wjp7MakiyaFWv4G1hjmodmMTs= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= @@ -148,6 +150,10 @@ 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.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 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 v3.3.10+incompatible/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cVwCLbBmJyDaka6Cmk1s= +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/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= @@ -158,9 +164,12 @@ github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= 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/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.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.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= @@ -219,6 +228,10 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= 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/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +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/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= @@ -257,8 +270,8 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y 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.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= -golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +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/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= @@ -273,13 +286,13 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug 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.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= -golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +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/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.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +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/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= @@ -294,12 +307,13 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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.5.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.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +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/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-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -315,8 +329,8 @@ 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.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= -golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +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/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.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= diff --git a/internal/server/routes.go b/internal/server/routes.go new file mode 100644 index 0000000..3381aaa --- /dev/null +++ b/internal/server/routes.go @@ -0,0 +1,82 @@ +package server + +import ( + "fmt" + "music-server/cmd/web" + "music-server/pkg/api" + "net/http" + "sort" + "strings" + + "github.com/a-h/templ" + "github.com/labstack/echo" + "github.com/labstack/echo/middleware" +) + +func (s *Server) RegisterRoutes() http.Handler { + e := echo.New() + e.Use(middleware.Logger()) + e.Use(middleware.Recover()) + + e.Use(middleware.CORSWithConfig(middleware.CORSConfig{ + AllowOrigins: []string{"https://*", "http://*"}, + AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"}, + AllowHeaders: []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token"}, + AllowCredentials: true, + MaxAge: 300, + })) + + fileServer := http.FileServer(http.FS(web.Assets)) + e.GET("/assets/*", echo.WrapHandler(fileServer)) + + e.GET("/search", echo.WrapHandler(templ.Handler(web.HelloForm()))) + e.POST("/find", echo.WrapHandler(http.HandlerFunc(web.FindGameWebHandler))) + + e.Static("/", "/frontend") + + swagger := http.FileServer(http.FS(web.Swagger)) + e.GET("/swagger/*", echo.WrapHandler(swagger)) + + index := api.NewIndex() + e.GET("/version", index.GetVersion) + e.GET("/health", index.GetDBTest) + + sync := api.NewSync() + syncGroup := e.Group("/sync") + syncGroup.GET("", sync.SyncGames) + syncGroup.GET("/new", sync.SyncGamesNewOnlyChanges) + syncGroup.GET("/new/full", sync.SyncGamesNewFull) + syncGroup.GET("/quick", sync.SyncGamesQuick) + syncGroup.GET("/reset", sync.ResetGames) + + music := api.NewMusic() + musicGroup := e.Group("/music") + musicGroup.GET("", music.GetSong) + musicGroup.GET("/soundTest", music.GetSoundCheckSong) + musicGroup.GET("/reset", music.ResetMusic) + musicGroup.GET("/rand", music.GetRandomSong) + musicGroup.GET("/rand/low", music.GetRandomSongLowChance) + musicGroup.GET("/rand/classic", music.GetRandomSongClassic) + musicGroup.GET("/info", music.GetSongInfo) + musicGroup.GET("/list", music.GetPlayedSongs) + musicGroup.GET("/next", music.GetNextSong) + musicGroup.GET("/previous", music.GetPreviousSong) + musicGroup.GET("/all", music.GetAllGamesRandom) + musicGroup.GET("/all/order", music.GetAllGames) + musicGroup.GET("/all/random", music.GetAllGamesRandom) + musicGroup.PUT("/played", music.PutPlayed) + musicGroup.GET("/addQue", music.AddLatestToQue) + musicGroup.GET("/addPlayed", music.AddLatestPlayed) + + routes := e.Routes() + sort.Slice(routes, func(i, j int) bool { + return routes[i].Path < routes[j].Path + }) + for _, r := range routes { + if (r.Method == "GET" || r.Method == "POST" || r.Method == "PUT" || r.Method == "DELETE") && !strings.Contains(r.Name, "github") { + fmt.Printf(" %s %s\n", r.Method, r.Path) + } + } + + return e +} diff --git a/internal/server/server.go b/internal/server/server.go new file mode 100644 index 0000000..5e9ba94 --- /dev/null +++ b/internal/server/server.go @@ -0,0 +1,35 @@ +package server + +import ( + "fmt" + "music-server/pkg/conf" + "net/http" + "os" + "strconv" + "time" +) + +type Server struct { + port int +} + +func NewServer() *http.Server { + + port, _ := strconv.Atoi(os.Getenv("PORT")) + NewServer := &Server{ + port: port, + } + + conf.SetupDb() + + // Declare Server config + server := &http.Server{ + Addr: fmt.Sprintf(":%d", NewServer.port), + Handler: NewServer.RegisterRoutes(), + IdleTimeout: time.Minute, + ReadTimeout: 10 * time.Second, + WriteTimeout: 30 * time.Second, + } + + return server +} diff --git a/justfile b/justfile index 723f2c8..1488a2b 100644 --- a/justfile +++ b/justfile @@ -1,3 +1,5 @@ +set dotenv-load + # Build the application all: build test @@ -16,8 +18,12 @@ templ-install: fi; \ fi -tailwind: - @if [ ! -f tailwindcss ]; then curl -sL https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-macos-x64 -o tailwindcss; fi +tailwind-macos: + @if [ ! -f tailwindcss ]; then curl -sL https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-macos-arm64 -o tailwindcss; fi + @chmod +x tailwindcss + +tailwind-linux: + @if [ ! -f tailwindcss ]; then curl -sL https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-linux-x64 -o tailwindcss; fi @chmod +x tailwindcss build: diff --git a/pkg/api/index.go b/pkg/api/index.go index 7b4ad4e..9a8f33f 100644 --- a/pkg/api/index.go +++ b/pkg/api/index.go @@ -1,10 +1,10 @@ package api import ( - "github.com/gin-gonic/gin" - "music-server/pkg/helpers" "music-server/pkg/server" "net/http" + + "github.com/labstack/echo" ) type Index struct { @@ -14,16 +14,15 @@ func NewIndex() *Index { return &Index{} } -func (i *Index) GetVersion(ctx *gin.Context) { +func (i *Index) GetVersion(ctx echo.Context) error { versionHistory := server.GetVersionHistory() if versionHistory.Version == "" { - helpers.NewError(ctx, http.StatusNotFound, nil) - return + return ctx.JSON(http.StatusNotFound, "version not found") } - ctx.JSON(http.StatusOK, versionHistory) + return ctx.JSON(http.StatusOK, versionHistory) } -func (i *Index) GetDBTest(ctx *gin.Context) { +func (i *Index) GetDBTest(ctx echo.Context) error { server.TestDB() - ctx.JSON(http.StatusOK, "TestedDB") + return ctx.JSON(http.StatusOK, "TestedDB") } diff --git a/pkg/api/music.go b/pkg/api/music.go index 0b06429..a30a401 100644 --- a/pkg/api/music.go +++ b/pkg/api/music.go @@ -1,11 +1,12 @@ package api import ( - "github.com/gin-gonic/gin" "music-server/pkg/helpers" "music-server/pkg/models" "music-server/pkg/server" "net/http" + + "github.com/labstack/echo" ) type Music struct { @@ -15,86 +16,87 @@ func NewMusic() *Music { return &Music{} } -func (m *Music) GetSong(ctx *gin.Context) { - song := ctx.Query("song") +func (m *Music) GetSong(ctx echo.Context) error { + song := ctx.QueryParam("song") if song == "" { - ctx.String(http.StatusBadRequest, "song can't be empty") + return ctx.String(http.StatusBadRequest, "song can't be empty") } s := server.GetSong(song) - helpers.SendSong(ctx, s) + return helpers.SendSong(ctx, s) } -func (m *Music) GetSoundCheckSong(ctx *gin.Context) { +func (m *Music) GetSoundCheckSong(ctx echo.Context) error { song := server.GetSoundCheckSong() - helpers.SendSong(ctx, song) + return helpers.SendSong(ctx, song) } -func (m *Music) ResetMusic(ctx *gin.Context) { +func (m *Music) ResetMusic(ctx echo.Context) error { server.Reset() - ctx.Status(http.StatusOK) + return ctx.NoContent(http.StatusOK) } -func (m *Music) GetRandomSong(ctx *gin.Context) { +func (m *Music) GetRandomSong(ctx echo.Context) error { song := server.GetRandomSong() - helpers.SendSong(ctx, song) + return helpers.SendSong(ctx, song) } -func (m *Music) GetRandomSongLowChance(ctx *gin.Context) { +func (m *Music) GetRandomSongLowChance(ctx echo.Context) error { song := server.GetRandomSongLowChance() - helpers.SendSong(ctx, song) + return helpers.SendSong(ctx, song) } -func (m *Music) GetRandomSongClassic(ctx *gin.Context) { +func (m *Music) GetRandomSongClassic(ctx echo.Context) error { song := server.GetRandomSongClassic() - helpers.SendSong(ctx, song) + return helpers.SendSong(ctx, song) } -func (m *Music) GetSongInfo(ctx *gin.Context) { +func (m *Music) GetSongInfo(ctx echo.Context) error { song := server.GetSongInfo() - ctx.JSON(http.StatusOK, song) + return ctx.JSON(http.StatusOK, song) } -func (m *Music) GetPlayedSongs(ctx *gin.Context) { +func (m *Music) GetPlayedSongs(ctx echo.Context) error { songList := server.GetPlayedSongs() - ctx.JSON(http.StatusOK, songList) + return ctx.JSON(http.StatusOK, songList) } -func (m *Music) GetNextSong(ctx *gin.Context) { +func (m *Music) GetNextSong(ctx echo.Context) error { song := server.GetNextSong() - helpers.SendSong(ctx, song) + return helpers.SendSong(ctx, song) } -func (m *Music) GetPreviousSong(ctx *gin.Context) { +func (m *Music) GetPreviousSong(ctx echo.Context) error { song := server.GetPreviousSong() - helpers.SendSong(ctx, song) + return helpers.SendSong(ctx, song) } -func (m *Music) GetAllGames(ctx *gin.Context) { +func (m *Music) GetAllGames(ctx echo.Context) error { gameList := server.GetAllGames() - ctx.JSON(http.StatusOK, gameList) + return ctx.JSON(http.StatusOK, gameList) } -func (m *Music) GetAllGamesRandom(ctx *gin.Context) { +func (m *Music) GetAllGamesRandom(ctx echo.Context) error { gameList := server.GetAllGamesRandom() - ctx.JSON(http.StatusOK, gameList) + return ctx.JSON(http.StatusOK, gameList) } -func (m *Music) PutPlayed(ctx *gin.Context) { +func (m *Music) PutPlayed(ctx echo.Context) error { var played models.Played - if err := ctx.ShouldBindJSON(&played); err != nil { - helpers.NewError(ctx, http.StatusBadRequest, err) - return + err := ctx.Bind(&played) + if err != nil { + //helpers.NewError(ctx, http.StatusBadRequest, err) + return ctx.JSON(http.StatusBadRequest, err) } server.SetPlayed(played.Song) - ctx.Status(http.StatusOK) + return ctx.NoContent(http.StatusOK) } -func (m *Music) AddLatestToQue(ctx *gin.Context) { +func (m *Music) AddLatestToQue(ctx echo.Context) error { server.AddLatestToQue() - ctx.Status(http.StatusOK) + return ctx.NoContent(http.StatusOK) } -func (m *Music) AddLatestPlayed(ctx *gin.Context) { +func (m *Music) AddLatestPlayed(ctx echo.Context) error { server.AddLatestPlayed() - ctx.Status(http.StatusOK) + return ctx.NoContent(http.StatusOK) } diff --git a/pkg/api/sync.go b/pkg/api/sync.go index 5ea1edb..2222832 100644 --- a/pkg/api/sync.go +++ b/pkg/api/sync.go @@ -1,10 +1,11 @@ package api import ( + "log" "music-server/pkg/server" "net/http" - "github.com/gin-gonic/gin" + "github.com/labstack/echo" ) type Sync struct { @@ -14,25 +15,33 @@ func NewSync() *Sync { return &Sync{} } -func (s *Sync) SyncGames(ctx *gin.Context) { +func (s *Sync) SyncGames(ctx echo.Context) error { server.SyncGames() server.Reset() - ctx.JSON(http.StatusOK, "Games are synced") + return ctx.JSON(http.StatusOK, "Games are synced") } -func (s *Sync) SyncGamesQuick(ctx *gin.Context) { +func (s *Sync) SyncGamesQuick(ctx echo.Context) error { server.SyncGamesQuick() server.Reset() - ctx.JSON(http.StatusOK, "Games are synced") + return ctx.JSON(http.StatusOK, "Games are synced") } -func (s *Sync) SyncGamesNew(ctx *gin.Context) { - response := server.SyncGamesNew() +func (s *Sync) SyncGamesNewOnlyChanges(ctx echo.Context) error { + log.Println("Syncing games new") + response := server.SyncGamesNewOnlyChanges() server.Reset() - ctx.JSON(http.StatusOK, response) + return ctx.JSON(http.StatusOK, response) } -func (s *Sync) ResetGames(ctx *gin.Context) { - server.ResetDB() - ctx.JSON(http.StatusOK, "Games and songs are deleted from the database") +func (s *Sync) SyncGamesNewFull(ctx echo.Context) error { + log.Println("Syncing games new full") + response := server.SyncGamesNewFull() + server.Reset() + return ctx.JSON(http.StatusOK, response) +} + +func (s *Sync) ResetGames(ctx echo.Context) error { + server.ResetDB() + return ctx.JSON(http.StatusOK, "Games and songs are deleted from the database") } diff --git a/pkg/conf/conf.go b/pkg/conf/conf.go index 40d00f1..c6d9805 100644 --- a/pkg/conf/conf.go +++ b/pkg/conf/conf.go @@ -1,146 +1,38 @@ package conf import ( - "embed" "fmt" - "io/fs" "log" - "music-server/cmd/web" - "music-server/pkg/api" "music-server/pkg/db" - "music-server/pkg/helpers" - "music-server/pkg/server" - "net/http" "os" - "strconv" +) - "github.com/a-h/templ" - "github.com/gin-contrib/static" - "github.com/gin-gonic/gin" +var ( + host = os.Getenv("DB_HOST") + dbPort = os.Getenv("DB_PORT") + database = os.Getenv("DB_NAME") + username = os.Getenv("DB_USERNAME") + password = os.Getenv("DB_PASSWORD") + musicPath = os.Getenv("MUSIC_PATH") ) func SetupDb() { - /*err := server.ReadConf("conf.yaml") - if err != nil { - log.Fatal(err) - }*/ - - // Get the value of an Environment Variable - host := os.Getenv("DB_HOST") - dbPort, dbPortErr := strconv.Atoi(os.Getenv("DB_PORT")) - if dbPortErr != nil { - dbPort = 0 + if host == "" || dbPort == "" || username == "" || password == "" || database == "" || musicPath == "" { + log.Fatal("Invalid settings") } - username := os.Getenv("DB_USERNAME") - password := os.Getenv("DB_PASSWORD") - dbName := os.Getenv("DB_NAME") fmt.Printf("host: %s, dbPort: %v, username: %s, password: %s, dbName: %s\n", - host, dbPort, username, password, dbName) + host, dbPort, username, password, database) - if host == "" { - host = "localhost" - } - if dbPort == 0 { - dbPort = 5432 - } - if username == "" { - username = "postgres" - } - if password == "" { - password = "postgres" - } - if dbName == "" { - dbName = "music_test_local" - } + log.Printf("Path: %s\n", musicPath) - db.Migrate_db(host, dbPort, username, password, dbName) - - db.InitDB(host, dbPort, username, password, dbName) - - var dir string - if host != "localhost" { - dir = "/sorted/" - } else { - dir = "/Users/sebastian/ResilioSync/Sorterat_test/" - } - - server.Conf = &server.Config{ - Host: host, - Port: dbPort, - User: username, - Password: password, - Dbname: dbName, - Path: dir, - } + db.Migrate_db(host, dbPort, username, password, database) + db.InitDB(host, dbPort, username, password, database) } func CloseDb() { - defer db.CloseDb() -} - -func SetupRestServer(swagger embed.FS) { - - router := gin.Default() - router.Use(helpers.SetCorsAndNoCacheHeaders()) - - sync := api.NewSync() - syncGroup := router.Group("/sync") - { - syncGroup.GET("", sync.SyncGames) - syncGroup.GET("/new", sync.SyncGamesNew) - syncGroup.GET("/quick", sync.SyncGamesQuick) - syncGroup.GET("/reset", sync.ResetGames) - } - - music := api.NewMusic() - musicGroup := router.Group("/music") - { - musicGroup.GET("", music.GetSong) - musicGroup.GET("soundTest", music.GetSoundCheckSong) - musicGroup.GET("reset", music.ResetMusic) - musicGroup.GET("rand", music.GetRandomSong) - musicGroup.GET("rand/low", music.GetRandomSongLowChance) - musicGroup.GET("rand/classic", music.GetRandomSongClassic) - musicGroup.GET("info", music.GetSongInfo) - musicGroup.GET("list", music.GetPlayedSongs) - musicGroup.GET("next", music.GetNextSong) - musicGroup.GET("previous", music.GetPreviousSong) - musicGroup.GET("all", music.GetAllGamesRandom) - musicGroup.GET("all/order", music.GetAllGames) - musicGroup.GET("all/random", music.GetAllGamesRandom) - musicGroup.PUT("played", music.PutPlayed) - musicGroup.GET("addQue", music.AddLatestToQue) - musicGroup.GET("addPlayed", music.AddLatestPlayed) - } - - index := api.NewIndex() - router.GET("/version", index.GetVersion) - router.GET("/health", index.GetDBTest) - router.StaticFS("/swagger", helpers.EmbedFolder(swagger, "swagger", false)) - router.Use(static.Serve("/", static.LocalFile("/frontend", true))) - router.Use(static.Serve("/new", static.LocalFile("/newFrontend", true))) - - staticFiles, _ := fs.Sub(web.Files, "assets") - router.StaticFS("/assets", http.FS(staticFiles)) - router.GET("/search", func(c *gin.Context) { - templ.Handler(web.HelloForm()).ServeHTTP(c.Writer, c.Request) - }) - - router.POST("/find", func(c *gin.Context) { - web.FindGameWebHandler(c.Writer, c.Request) - }) - - port := os.Getenv("PORT") - if port == "" { - port = "8080" - log.Printf("Defaulting to port %s", port) - } - log.Printf("Open http://localhost:%s in the browser", port) - err := router.Run(fmt.Sprintf(":%s", port)) - if err != nil { - panic(err) - } + fmt.Println("Closing connection to database") + db.CloseDb() } diff --git a/pkg/db/dbHelper.go b/pkg/db/dbHelper.go index 37accd8..0515b9b 100644 --- a/pkg/db/dbHelper.go +++ b/pkg/db/dbHelper.go @@ -20,9 +20,9 @@ import ( var Dbpool *pgxpool.Pool var Ctx = context.Background() -func InitDB(host string, port int, user string, password string, dbname string) { +func InitDB(host string, port string, user string, password string, dbname string) { - psqlInfo := fmt.Sprintf("host=%s port=%d user=%s "+ + psqlInfo := fmt.Sprintf("host=%s port=%s user=%s "+ "password=%s dbname=%s sslmode=disable", host, port, user, password, dbname) @@ -72,8 +72,8 @@ func resetGameIdSeq() { } } -func Migrate_db(host string, port int, user string, password string, dbname string) { - migrationInfo := fmt.Sprintf("postgres://%s:%s@%s:%d/%s?sslmode=disable", +func Migrate_db(host string, port string, user string, password string, dbname string) { + migrationInfo := fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=disable", user, password, host, port, dbname) fmt.Println("Migration Info: ", migrationInfo) diff --git a/pkg/helpers/helpers.go b/pkg/helpers/helpers.go index 52e3fda..eec52c4 100644 --- a/pkg/helpers/helpers.go +++ b/pkg/helpers/helpers.go @@ -3,7 +3,6 @@ package helpers import ( "embed" "fmt" - "io" "io/fs" "net/http" "os" @@ -12,6 +11,7 @@ import ( "github.com/gin-contrib/static" "github.com/gin-gonic/gin" + "github.com/labstack/echo" ) func SetCorsAndNoCacheHeaders() gin.HandlerFunc { @@ -61,15 +61,15 @@ func EmbedFolder(fsEmbed embed.FS, targetPath string, index bool) static.ServeFi } } -func SendSong(ctx *gin.Context, Filename string) { +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 + //http.Error(ctx.Writer, "Song not found.", 404) + return ctx.String(http.StatusNotFound, "Song not found.") } defer func(openFile *os.File) { _ = openFile.Close() @@ -91,13 +91,13 @@ func SendSong(ctx *gin.Context, Filename string) { //Send the headers //writer.Header().Set("Content-Disposition", "attachment; filename="+Filename) - ctx.Writer.Header().Set("Content-Type", "audio/mpeg") - ctx.Writer.Header().Set("Content-Length", FileSize) - ctx.Writer.Header().Set("Expires", "Tue, 03 Jul 2001 06:00:00 GMT") - ctx.Writer.Header().Set("Last-Modified", time.Now().String()+" GMT") - ctx.Writer.Header().Set("Cache-Control", "no-cache, no-store, private, max-age=0") - ctx.Writer.Header().Set("Pragma", "no-cache") - ctx.Writer.Header().Set("X-Accel-Expires", "0") + 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", @@ -109,14 +109,14 @@ func SendSong(ctx *gin.Context, Filename string) { } for _, v := range etagHeaders { - if ctx.Request.Header.Get(v) != "" { - ctx.Request.Header.Del(v) + 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 + //_, _ = io.Copy(ctx.Writer, openFile) //'Copy' the file to the client + return ctx.Stream(http.StatusOK, "audio/mpeg", openFile) } diff --git a/pkg/server/config.go b/pkg/server/config.go deleted file mode 100644 index 2d692f5..0000000 --- a/pkg/server/config.go +++ /dev/null @@ -1,34 +0,0 @@ -package server - -import ( - "fmt" - "os" - - "gopkg.in/yaml.v3" -) - -type Config struct { - Host string - Port int - User string - Password string - Dbname string - Path string -} - -var Conf *Config - -func ReadConf(filename string) error { - buf, err := os.ReadFile(filename) - if err != nil { - return err - } - - c := &Config{} - err = yaml.Unmarshal(buf, c) - if err != nil { - return fmt.Errorf("in file %q: %w", filename, err) - } - Conf = c - return err -} diff --git a/pkg/server/sync.go b/pkg/server/sync.go index 361feeb..e709832 100644 --- a/pkg/server/sync.go +++ b/pkg/server/sync.go @@ -260,15 +260,30 @@ func checkBrokenSongs() { } db.RemoveBrokenSongs(brokenSongs) } +func SyncGamesNewFull() Response { + return syncGamesNew(true) +} -func SyncGamesNew() Response { +func SyncGamesNewOnlyChanges() Response { + return syncGamesNew(false) +} + +func syncGamesNew(full bool) Response { + musicPath := os.Getenv("MUSIC_PATH") + fmt.Printf("dir: %s\n", musicPath) repo = repository.New(db.Dbpool) start := time.Now() - fmt.Printf("dir: %s\n", Conf.Path) foldersToSkip := []string{".sync", "dist", "old"} fmt.Println(foldersToSkip) var err error + gamesAdded = nil + gamesReAdded = nil + gamesChangedTitle = nil + gamesChangedContent = nil + gamesRemoved = nil + catchedErrors = nil + brokenSongs = nil gamesBeforeSync, err = repo.FindAllGames(db.Ctx) handleError("FindAllGames Before", err, "") @@ -279,7 +294,7 @@ func SyncGamesNew() Response { err = repo.SetGameDeletionDate(db.Ctx) handleError("SetGameDeletionDate", err, "") - directories, err := os.ReadDir(Conf.Path) + directories, err := os.ReadDir(musicPath) if err != nil { log.Fatal(err) } @@ -288,7 +303,7 @@ func SyncGamesNew() Response { for _, dir := range directories { go func() { defer syncWg.Done() - syncGameNew(dir, foldersToSkip, Conf.Path) + syncGameNew(dir, foldersToSkip, musicPath, full) }() } syncWg.Wait() @@ -339,7 +354,7 @@ func SyncGamesNew() Response { for _, game := range gamesRemovedTemp { var found bool = false - for key, _ := range gamesChangedTitle { + for key := range gamesChangedTitle { if game == key { found = true //fmt.Printf("Game: %s, Found: %v break2\n", game, found) @@ -408,7 +423,7 @@ func checkBrokenSongNew(song repository.Song) { } } -func syncGameNew(file os.DirEntry, foldersToSkip []string, baseDir string) { +func syncGameNew(file os.DirEntry, foldersToSkip []string, baseDir string, full bool) { if file.IsDir() && !contains(foldersToSkip, file.Name()) { gameDir := baseDir + file.Name() + "/" @@ -441,6 +456,9 @@ func syncGameNew(file os.DirEntry, foldersToSkip []string, baseDir string) { } } + if full { + status = TitleChanged + } entries, err := os.ReadDir(gameDir) if err != nil { log.Println(err)