10 Commits

17 changed files with 11456 additions and 28118 deletions
+10916 -27824
View File
File diff suppressed because it is too large Load Diff
+45 -36
View File
@@ -7,42 +7,51 @@
"build": "vue-cli-service build", "build": "vue-cli-service build",
"lint": "vue-cli-service lint" "lint": "vue-cli-service lint"
}, },
"dependencies": { "dependencies": {
"axios": "^0.21.1", "axios": "^1.7.2",
"config.js": "^0.1.0", "core-js": "^3.37.1",
"core-js": "^3.8.2", "cors": "^2.8.5",
"cors": "^2.8.5", "express": "^4.19.2",
"express": "^4.17.1", "vue": "^3.4.31",
"nodemon": "^2.0.7", "vue-axios": "^3.5.2",
"vue": "^3.0.5", "vuex": "^4.1.0"
"vue-axios": "^3.2.2", },
"vuex": "^4.0.0-rc.2" "devDependencies": {
}, "@vue/cli-plugin-babel": "^5.0.8",
"devDependencies": { "@vue/cli-plugin-eslint": "^5.0.8",
"@vue/cli-plugin-babel": "^4.5.10", "@vue/cli-service": "^5.0.8",
"@vue/cli-plugin-eslint": "^4.5.10", "@vue/compiler-sfc": "^3.4.31",
"@vue/cli-service": "^4.5.10", "@babel/eslint-parser": "^7.25.1",
"@vue/compiler-sfc": "^3.0.5", "eslint": "^8.57.0",
"babel-eslint": "^10.1.0", "eslint-plugin-vue": "^9.27.0"
"eslint": "^6.7.2", },
"eslint-plugin-vue": "^7.4.1" "eslintConfig": {
}, "root": true,
"eslintConfig": { "env": {
"root": true, "node": true
"env": { },
"node": true "extends": [
}, "plugin:vue/vue3-essential",
"extends": [ "eslint:recommended"
"plugin:vue/vue3-essential", ],
"eslint:recommended" "parserOptions": {
], "parser": "@babel/eslint-parser",
"parserOptions": { "requireConfigFile": false,
"parser": "babel-eslint" "ecmaVersion": 2020,
}, "sourceType": "module",
"rules": { "ecmaFeatures": {
"no-debugger": 1 "globalReturn": false,
} "impliedStrict": true,
}, "jsx": true
},
"babelOptions": {
"presets": ["@babel/preset-env"]
}
},
"rules": {
"no-debugger": 1
}
},
"browserslist": [ "browserslist": [
"> 1%", "> 1%",
"last 2 versions", "last 2 versions",
-18
View File
@@ -1,18 +0,0 @@
@import "tailwindcss";
#search-container {
text-align: center;
}
#search_term {
width: 60vw;
font-size: 2vh;
}
#clear {
font-size: 2vh;
}
#games-container{
font-size: 2vh;
}
+94
View File
@@ -0,0 +1,94 @@
/* Pure CSS styles for Music Search */
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html, body {
height: 100%;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
line-height: 1.5;
background-color: #f3f4f6;
}
main {
max-width: 1200px;
margin: 0 auto;
padding: 1rem;
}
#search-container {
text-align: center;
margin-bottom: 2rem;
}
#search_term {
width: 60vw;
max-width: 600px;
font-size: 1.5rem;
padding: 0.5rem;
border: 1px solid #9ca3af;
border-radius: 0.5rem;
background-color: #e5e7eb;
color: #000;
}
#search_term:focus {
outline: none;
border-color: #6b7280;
}
#clear {
font-size: 1.5rem;
padding: 0.5rem 1rem;
border: none;
border-radius: 0.5rem;
background-color: #f97316;
color: #fff;
cursor: pointer;
margin-left: 1rem;
}
#clear:hover {
background-color: #ea580c;
}
#games-container {
font-size: 1.5rem;
}
/* Game result cards */
.bg-green-100 {
background-color: #dcfce7;
}
.p-4 {
padding: 1rem;
}
.shadow-md {
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1);
}
.rounded-lg {
border-radius: 0.5rem;
}
.mt-6 {
margin-top: 1.5rem;
}
/* Responsive adjustments */
@media (max-width: 768px) {
#search_term {
width: 80vw;
font-size: 1.2rem;
}
#clear {
font-size: 1.2rem;
padding: 0.4rem 0.8rem;
}
}
+4 -4
View File
@@ -2,15 +2,15 @@ package web
templ Base() { templ Base() {
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en" class="h-screen"> <html lang="en">
<head> <head>
<meta charset="utf-8"/> <meta charset="utf-8"/>
<title>Music Search</title> <title>Music Search</title>
<link href="assets/css/output.css" rel="stylesheet"/> <link href="assets/css/styles.css" rel="stylesheet"/>
<script src="assets/js/htmx.min.js"></script> <script src="assets/js/htmx.min.js"></script>
</head> </head>
<body class="bg-gray-100"> <body>
<main class="mx-auto p-4"> <main>
{ children... } { children... }
</main> </main>
</body> </body>
+3 -3
View File
@@ -3,12 +3,12 @@ package web
templ HelloForm() { templ HelloForm() {
@Base() { @Base() {
<div id="search-container"> <div id="search-container">
<input class="bg-gray-200 text-black p-2 border border-gray-400 rounded-lg" id="search_term" name="search_term" type="text" hx-post="/find" hx-trigger="keyup changed delay:0.25s" hx-target="#games-container"/> <input id="search_term" name="search_term" type="text" hx-post="/find" hx-trigger="keyup changed delay:0.25s" hx-target="#games-container"/>
<button type="button" class="bg-orange-500 hover:bg-orange-700 text-white py-2 px-4 rounded" id="clear" name="clear">Clear</button> <button type="button" id="clear" name="clear">Clear</button>
</div> </div>
<div id="games-container"></div> <div id="games-container"></div>
<script> <script>
document.addEventListener('readystatechange', () => { document.addEventListener('readystatechange', () => {
if (document.readyState == 'complete') { if (document.readyState == 'complete') {
htmx.ajax('POST', '/find', '#games-container'); htmx.ajax('POST', '/find', '#games-container');
document.getElementById("search_term").focus(); document.getElementById("search_term").focus();
+33 -38
View File
@@ -3,54 +3,49 @@ module music-server
go 1.25.0 go 1.25.0
require ( require (
github.com/MShekow/directory-checksum v1.4.9 github.com/MShekow/directory-checksum v1.4.18
github.com/a-h/templ v0.3.937 github.com/a-h/templ v0.3.1020
github.com/golang-migrate/migrate/v4 v4.18.3 github.com/golang-migrate/migrate/v4 v4.19.1
github.com/jackc/pgx/v5 v5.7.5 github.com/jackc/pgx/v5 v5.9.2
github.com/labstack/echo/v4 v4.15.2 github.com/labstack/echo/v5 v5.1.1
github.com/lib/pq v1.10.9 github.com/lib/pq v1.12.3
github.com/panjf2000/ants/v2 v2.11.3 github.com/panjf2000/ants/v2 v2.12.0
github.com/spf13/afero v1.14.0 github.com/spf13/afero v1.15.0
github.com/swaggo/echo-swagger v1.5.2 github.com/swaggo/echo-swagger/v2 v2.0.1
github.com/swaggo/swag v1.16.6 github.com/swaggo/swag v1.16.6
) )
require ( require (
github.com/KyleBanks/depth v1.2.1 // indirect github.com/KyleBanks/depth v1.2.1 // indirect
github.com/docker/docker v27.3.1+incompatible // indirect
github.com/go-errors/errors v1.5.1 // indirect github.com/go-errors/errors v1.5.1 // indirect
github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonpointer v0.23.1 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/jsonreference v0.21.5 // indirect
github.com/go-openapi/spec v0.20.9 // indirect github.com/go-openapi/spec v0.22.4 // indirect
github.com/go-openapi/swag v0.22.3 // indirect github.com/go-openapi/swag/conv v0.26.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect github.com/go-openapi/swag/jsonname v0.26.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/go-openapi/swag/jsonutils v0.26.0 // indirect
github.com/go-openapi/swag/loading v0.26.0 // indirect
github.com/go-openapi/swag/stringutils v0.26.0 // indirect
github.com/go-openapi/swag/typeutils v0.26.0 // indirect
github.com/go-openapi/swag/yamlutils v0.26.0 // indirect
github.com/google/go-cmp v0.7.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-20240606120523-5a60cdf6a761 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/josharian/intern v1.0.0 // indirect github.com/kr/text v0.2.0 // indirect
github.com/labstack/gommon v0.5.0 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect
github.com/mailru/easyjson v0.7.7 // indirect github.com/sv-tools/openapi v0.4.0 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect github.com/swaggo/files/v2 v2.0.2 // indirect
github.com/mattn/go-isatty v0.0.22 // indirect github.com/swaggo/swag/v2 v2.0.0-rc5 // indirect
github.com/pkg/errors v0.9.1 // indirect go.uber.org/multierr v1.10.0 // indirect
github.com/sv-tools/openapi v0.2.1 // indirect go.uber.org/zap v1.28.0 // indirect
github.com/swaggo/files/v2 v2.0.0 // indirect go.yaml.in/yaml/v2 v2.4.4 // indirect
github.com/swaggo/swag/v2 v2.0.0-rc4 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect golang.org/x/mod v0.36.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/crypto v0.50.0 // indirect
golang.org/x/mod v0.34.0 // indirect
golang.org/x/net v0.53.0 // indirect
golang.org/x/sync v0.20.0 // indirect golang.org/x/sync v0.20.0 // indirect
golang.org/x/sys v0.43.0 // indirect golang.org/x/text v0.37.0 // indirect
golang.org/x/text v0.36.0 // indirect
golang.org/x/time v0.15.0 // indirect golang.org/x/time v0.15.0 // indirect
golang.org/x/tools v0.43.0 // indirect golang.org/x/tools v0.45.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect sigs.k8s.io/yaml v1.6.0 // indirect
) )
+98 -112
View File
@@ -2,22 +2,26 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25
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/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
github.com/MShekow/directory-checksum v1.4.9 h1:olzWbrq9ylwfi7afuoivzHM8AV2z2KOaT7FJ6Ri2ppU= github.com/MShekow/directory-checksum v1.4.18 h1:1nPPVl7uREa6WMTAPKoWW/GylhnASs0C9C+GPiwLwXA=
github.com/MShekow/directory-checksum v1.4.9/go.mod h1:LhNeWmPftlKTlc3TNurdihPK/whw9j76VnLaTRu2SkU= github.com/MShekow/directory-checksum v1.4.18/go.mod h1:iUupsPb0X0BumQQymLrpD5Pkqe/CbV13OSgosw1oFc4=
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/a-h/templ v0.3.937 h1:Ta+0Tf9YuZplUyKTUxReV36FCRKtK6FRMWpmXERHDnM= github.com/a-h/templ v0.3.1020 h1:ypAT/L5ySWEnZ6Zft/5yfoWXYYkhFNvEFOeeqecg4tw=
github.com/a-h/templ v0.3.937/go.mod h1:oCZcnKRf5jjsGpf2yELzQfodLphd2mwecwG4Crk5HBo= github.com/a-h/templ v0.3.1020/go.mod h1:A2DlK61v+K+NRoGnhmYbNYVmtYHcFO5/AisMvBdDxTM=
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.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.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dhui/dktest v0.4.5 h1:uUfYBIVREmj/Rw6MvgmqNAYzTiKOHJak+enB5Di73MM= github.com/dhui/dktest v0.4.6 h1:+DPKyScKSEp3VLtbMDHcUq6V5Lm5zfZZVb0Sk7Ahom4=
github.com/dhui/dktest v0.4.5/go.mod h1:tmcyeHDKagvlDrz7gDKq4UAJOLIfVZYkfD5OnHDwcCo= github.com/dhui/dktest v0.4.6/go.mod h1:JHTSYDtKkvFNFHJKqCzVzqXecyv+tKt8EzceOmQOgbU=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/docker v27.3.1+incompatible h1:KttF0XoteNTicmUtBO0L2tP+J7FGRFTjaEF4k6WdhfI= github.com/docker/docker v28.3.3+incompatible h1:Dypm25kh4rmk49v1eiVbsAtpAsYURjYkaKubwuBdxEI=
github.com/docker/docker v27.3.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v28.3.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
@@ -26,150 +30,132 @@ github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
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-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/logr v1.4.3/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-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.23.1 h1:1HBACs7XIwR2RcmItfdSFlALhGbe6S92p0ry4d1GWg4=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.23.1/go.mod h1:iWRmZTrGn7XwYhtPt/fvdSFj1OfNBngqRT2UG3BxSqY=
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonreference v0.21.5 h1:6uCGVXU/aNF13AQNggxfysJ+5ZcU4nEAe+pJyVWRdiE=
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonreference v0.21.5/go.mod h1:u25Bw85sX4E2jzFodh1FOKMTZLcfifd1Q+iKKOUxExw=
github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= github.com/go-openapi/spec v0.22.4 h1:4pxGjipMKu0FzFiu/DPwN3CTBRlVM2yLf/YTWorYfDQ=
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= github.com/go-openapi/spec v0.22.4/go.mod h1:WQ6Ai0VPWMZgMT4XySjlRIE6GP1bGQOtEThn3gcWLtQ=
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
github.com/go-openapi/spec v0.20.9 h1:xnlYNQAwKd2VQRRfwTEI0DcK+2cbuvI/0c7jx3gA8/8=
github.com/go-openapi/spec v0.20.9/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-openapi/swag/conv v0.26.0 h1:5yGGsPYI1ZCva93U0AoKi/iZrNhaJEjr324YVsiD89I=
github.com/go-openapi/swag/conv v0.26.0/go.mod h1:tpAmIL7X58VPnHHiSO4uE3jBeRamGsFsfdDeDtb5ECE=
github.com/go-openapi/swag/jsonname v0.26.0 h1:gV1NFX9M8avo0YSpmWogqfQISigCmpaiNci8cGECU5w=
github.com/go-openapi/swag/jsonname v0.26.0/go.mod h1:urBBR8bZNoDYGr653ynhIx+gTeIz0ARZxHkAPktJK2M=
github.com/go-openapi/swag/jsonutils v0.26.0 h1:FawFML2iAXsPqmERscuMPIHmFsoP1tOqWkxBaKNMsnA=
github.com/go-openapi/swag/jsonutils v0.26.0/go.mod h1:2VmA0CJlyFqgawOaPI9psnjFDqzyivIqLYN34t9p91E=
github.com/go-openapi/swag/jsonutils/fixtures_test v0.26.0 h1:apqeINu/ICHouqiRZbyFvuDge5jCmmLTqGQ9V95EaOM=
github.com/go-openapi/swag/jsonutils/fixtures_test v0.26.0/go.mod h1:AyM6QT8uz5IdKxk5akv0y6u4QvcL9GWERt0Jx/F/R8Y=
github.com/go-openapi/swag/loading v0.26.0 h1:Apg6zaKhCJurpJer0DCxq99qwmhFddBhaMX7kilDcko=
github.com/go-openapi/swag/loading v0.26.0/go.mod h1:dBxQ/6V2uBaAQdevN18VELE6xSpJWZxLX4txe12JwDg=
github.com/go-openapi/swag/stringutils v0.26.0 h1:qZQngLxs5s7SLijc3N2ZO+fUq2o8LjuWAASSrJuh+xg=
github.com/go-openapi/swag/stringutils v0.26.0/go.mod h1:sWn5uY+QIIspwPhvgnqJsH8xqFT2ZbYcvbcFanRyhFE=
github.com/go-openapi/swag/typeutils v0.26.0 h1:2kdEwdiNWy+JJdOvu5MA2IIg2SylWAFuuyQIKYybfq4=
github.com/go-openapi/swag/typeutils v0.26.0/go.mod h1:oovDuIUvTrEHVMqWilQzKzV4YlSKgyZmFh7AlfABNVE=
github.com/go-openapi/swag/yamlutils v0.26.0 h1:H7O8l/8NJJQ/oiReEN+oMpnGMyt8G0hl460nRZxhLMQ=
github.com/go-openapi/swag/yamlutils v0.26.0/go.mod h1:1evKEGAtP37Pkwcc7EWMF0hedX0/x3Rkvei2wtG/TbU=
github.com/go-openapi/testify/enable/yaml/v2 v2.4.2 h1:5zRca5jw7lzVREKCZVNBpysDNBjj74rBh0N2BGQbSR0=
github.com/go-openapi/testify/enable/yaml/v2 v2.4.2/go.mod h1:XVevPw5hUXuV+5AkI1u1PeAm27EQVrhXTTCPAF85LmE=
github.com/go-openapi/testify/v2 v2.4.2 h1:tiByHpvE9uHrrKjOszax7ZvKB7QOgizBWGBLuq0ePx4=
github.com/go-openapi/testify/v2 v2.4.2/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw=
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.3 h1:EYGkoOsvgHHfm5U/naS1RP/6PL/Xv3S4B/swMiAmDLs= github.com/golang-migrate/migrate/v4 v4.19.1 h1:OCyb44lFuQfYXYLx1SCxPZQGU7mcaZ7gH9yH4jSFbBA=
github.com/golang-migrate/migrate/v4 v4.18.3/go.mod h1:99BKpIi6ruaaXRM1A77eqZ+FWPQ3cfRa+ZVy5bmWMaY= github.com/golang-migrate/migrate/v4 v4.19.1/go.mod h1:CTcgfjxhaUtsLipnLoQRWCrjYXycRz/g5+RWDuYgPrE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/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/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/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
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/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.7.5 h1:JHGfMnQY+IEtGM63d+NGMjoRpysB2JBwDr5fsngwmJs= github.com/jackc/pgx/v5 v5.9.2 h1:3ZhOzMWnR4yJ+RW1XImIPsD1aNSz4T4fyP7zlQb56hw=
github.com/jackc/pgx/v5 v5.7.5/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M= github.com/jackc/pgx/v5 v5.9.2/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4=
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.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/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/v4 v4.15.2 h1:nnh2sCzGCVYnU+wCisMPiYapEg/QVo/gcI9ePKg5/T4= github.com/labstack/echo/v5 v5.1.1 h1:4QkvKoS8ps5ch49t8b72QS9Z581ytgxhTzxuB/CBA2I=
github.com/labstack/echo/v4 v4.15.2/go.mod h1:Xzp1Ns1RA2c9fY7nSgUJkpkUZGNbEIVHZbtbOMPktBI= github.com/labstack/echo/v5 v5.1.1/go.mod h1:SyvlSdObGjRXeQfCCXW/sybkZdOOQZBmpKF0bvALaeo=
github.com/labstack/gommon v0.5.0 h1:6VSQ2NOzsnEJ5W6+84E0RbcaDDmgB6NIAzWCczTEe6c= github.com/lib/pq v1.12.3 h1:tTWxr2YLKwIvK90ZXEw8GP7UFHtcbTtty8zsI+YjrfQ=
github.com/labstack/gommon v0.5.0/go.mod h1:Rzlg7HHy1maLfzBYGg9NZcVuz1sA68HHhLjhcEllYE0= github.com/lib/pq v1.12.3/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4=
github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
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/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/panjf2000/ants/v2 v2.11.3 h1:AfI0ngBoXJmYOpDh9m516vjqoUu2sLrIVgppI9TZVpg= github.com/panjf2000/ants/v2 v2.12.0 h1:u9JhESo83i/GkZnhfTNuFMMWcNt7mnV1bGJ6FT4wXH8=
github.com/panjf2000/ants/v2 v2.11.3/go.mod h1:8u92CYMUc6gyvTIw8Ru7Mt7+/ESnJahz5EVtqfrilek= github.com/panjf2000/ants/v2 v2.12.0/go.mod h1:tSQuaNQ6r6NRhPt+IZVUevvDyFMTs+eS4ztZc52uJTY=
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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
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.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.6.1/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.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.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/sv-tools/openapi v0.2.1 h1:ES1tMQMJFGibWndMagvdoo34T1Vllxr1Nlm5wz6b1aA= github.com/sv-tools/openapi v0.4.0 h1:UhD9DVnGox1hfTePNclpUzUFgos57FvzT2jmcAuTOJ4=
github.com/sv-tools/openapi v0.2.1/go.mod h1:k5VuZamTw1HuiS9p2Wl5YIDWzYnHG6/FgPOSFXLAhGg= github.com/sv-tools/openapi v0.4.0/go.mod h1:kD/dG+KP0+Fom1r6nvcj/ORtLus8d8enXT6dyRZDirE=
github.com/swaggo/echo-swagger v1.5.2 h1:KUM4QuEO1r/maky6Ybb9wS5MFEkJUpXwPbK4wwBe5Uk= github.com/swaggo/echo-swagger/v2 v2.0.1 h1:jKR3QiK+ciGjxE0+7qZ/azjtlx/pTVls7pJFJqdJoJI=
github.com/swaggo/echo-swagger v1.5.2/go.mod h1:nt3Z+SlyzXNIQ4odFNlPzRdcNOFvkPJHf+t4sMLhNu4= github.com/swaggo/echo-swagger/v2 v2.0.1/go.mod h1:BbgiO9XKX6yYU5Rq4ejqVlQI0mVRv6ziFKd0XgdztnQ=
github.com/swaggo/files/v2 v2.0.0 h1:hmAt8Dkynw7Ssz46F6pn8ok6YmGZqHSVLZ+HQM7i0kw= github.com/swaggo/files/v2 v2.0.2 h1:Bq4tgS/yxLB/3nwOMcul5oLEUKa877Ykgz3CJMVbQKU=
github.com/swaggo/files/v2 v2.0.0/go.mod h1:24kk2Y9NYEJ5lHuCra6iVwkMjIekMCaFq/0JQj66kyM= github.com/swaggo/files/v2 v2.0.2/go.mod h1:TVqetIzZsO9OhHX1Am9sRf9LdrFZqoK49N37KON/jr0=
github.com/swaggo/swag v1.16.6 h1:qBNcx53ZaX+M5dxVyTrgQ0PJ/ACK+NzhwcbieTt+9yI= github.com/swaggo/swag v1.16.6 h1:qBNcx53ZaX+M5dxVyTrgQ0PJ/ACK+NzhwcbieTt+9yI=
github.com/swaggo/swag v1.16.6/go.mod h1:ngP2etMK5a0P3QBizic5MEwpRmluJZPHjXcMoj4Xesg= github.com/swaggo/swag v1.16.6/go.mod h1:ngP2etMK5a0P3QBizic5MEwpRmluJZPHjXcMoj4Xesg=
github.com/swaggo/swag/v2 v2.0.0-rc4 h1:SZ8cK68gcV6cslwrJMIOqPkJELRwq4gmjvk77MrvHvY= github.com/swaggo/swag/v2 v2.0.0-rc5 h1:fK7d6ET9rrEsdB8IyuwXREWMcyQN3N7gawGFbbrjgHk=
github.com/swaggo/swag/v2 v2.0.0-rc4/go.mod h1:Ow7Y8gF16BTCDn8YxZbyKn8FkMLRUHekv1kROJZpbvE= github.com/swaggo/swag/v2 v2.0.0-rc5/go.mod h1:kCL8Fu4Zl8d5tB2Bgj96b8wRowwrwk175bZHXfuGVFI=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0 h1:DheMAlT6POBP+gh8RUH19EOTnQIor5QE0uSRPtzCpSw= go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0/go.mod h1:wZcGmeVO9nzP67aYSLDqXNWK87EZWhi7JWj1v7ZXf94= go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/zap v1.28.0 h1:IZzaP1Fv73/T/pBMLk4VutPl36uNC+OSUh3JLG3FIjo=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/zap v1.28.0/go.mod h1:rDLpOi171uODNm/mxFcuYWxDsqWSAVkFdX4XojSKg/Q=
golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI= go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ=
golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q= go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ=
golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA= golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4=
golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs= golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ=
golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w=
golang.org/x/net v0.54.0/go.mod h1:Sj4oj8jK6XmHpBZU/zWHw3BV3abl4Kvi+Ut7cQcY+cQ=
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ=
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg= golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164= golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s= golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8=
golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0= golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0=
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-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/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=
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=
+44
View File
@@ -0,0 +1,44 @@
package logging
import (
"github.com/labstack/echo/v5"
"github.com/labstack/echo/v5/middleware"
"go.uber.org/zap"
)
// RequestLogger is an Echo middleware that logs HTTP requests using Zap
func RequestLogger() echo.MiddlewareFunc {
return middleware.RequestLoggerWithConfig(middleware.RequestLoggerConfig{
LogStatus: true,
LogURI: true,
LogMethod: true,
HandleError: true,
LogValuesFunc: func(c *echo.Context, v middleware.RequestLoggerValues) error {
logger := GetLogger()
fields := []zap.Field{
zap.String("method", v.Method),
zap.String("uri", v.URI),
zap.Int("status", v.Status),
}
if v.Error != nil {
fields = append(fields, zap.String("error", v.Error.Error()))
logger.Error("Request error", fields...)
} else {
logger.Info("Request completed", fields...)
}
return nil
},
})
}
// ErrorHandler is a custom error handler that logs errors
func ErrorHandler(err error, c *echo.Context) {
logger := GetLogger()
logger.Error("Error occurred",
zap.String("method", c.Request().Method),
zap.String("path", c.Request().URL.Path),
zap.String("error", err.Error()),
)
}
+104
View File
@@ -0,0 +1,104 @@
package logging
import (
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
var (
// Logger is the global logger instance
Logger *zap.Logger
// SugaredLogger is the global sugared logger instance
SugaredLogger *zap.SugaredLogger
)
// Init initializes the logger with the specified level and config
func Init(level string, jsonOutput bool) {
var config zap.Config
// Set the log level
logLevel := zap.NewAtomicLevel()
err := logLevel.UnmarshalText([]byte(level))
if err != nil {
logLevel.SetLevel(zap.InfoLevel)
}
if jsonOutput {
// JSON output for Grafana Loki
config = zap.Config{
Level: logLevel,
Development: false,
Sampling: nil,
Encoding: "json",
EncoderConfig: zapcore.EncoderConfig{
MessageKey: "msg",
LevelKey: "level",
TimeKey: "time",
NameKey: "logger",
CallerKey: "caller",
FunctionKey: zapcore.OmitKey,
StacktraceKey: "stacktrace",
SkipLineEnding: false,
LineEnding: zapcore.DefaultLineEnding,
EncodeLevel: zapcore.LowercaseLevelEncoder,
EncodeTime: zapcore.ISO8601TimeEncoder,
EncodeDuration: zapcore.StringDurationEncoder,
EncodeCaller: zapcore.ShortCallerEncoder,
},
OutputPaths: []string{"stdout"},
ErrorOutputPaths: []string{"stderr"},
InitialFields: map[string]interface{}{"service": "music-server"},
}
} else {
// Human-readable output for development
config = zap.Config{
Level: logLevel,
Development: true,
Sampling: nil,
Encoding: "console",
EncoderConfig: zapcore.EncoderConfig{
MessageKey: "msg",
LevelKey: "level",
TimeKey: "time",
NameKey: "logger",
CallerKey: "caller",
FunctionKey: zapcore.OmitKey,
StacktraceKey: "stacktrace",
SkipLineEnding: false,
LineEnding: zapcore.DefaultLineEnding,
EncodeLevel: zapcore.CapitalLevelEncoder,
EncodeTime: zapcore.ISO8601TimeEncoder,
EncodeDuration: zapcore.StringDurationEncoder,
EncodeCaller: zapcore.ShortCallerEncoder,
},
OutputPaths: []string{"stdout"},
ErrorOutputPaths: []string{"stderr"},
InitialFields: map[string]interface{}{"service": "music-server"},
}
}
logger, err := config.Build()
if err != nil {
panic(err)
}
Logger = logger
SugaredLogger = logger.Sugar()
}
// GetLogger returns the global logger
func GetLogger() *zap.Logger {
if Logger == nil {
Init("info", false)
}
return Logger
}
// GetSugaredLogger returns the global sugared logger
func GetSugaredLogger() *zap.SugaredLogger {
if SugaredLogger == nil {
Init("info", false)
}
return SugaredLogger
}
+10 -10
View File
@@ -1,9 +1,9 @@
package server package server
import ( import (
"github.com/labstack/echo/v4" "github.com/labstack/echo/v5"
"log"
"music-server/internal/backend" "music-server/internal/backend"
"music-server/internal/logging"
"net/http" "net/http"
) )
@@ -22,8 +22,8 @@ func NewDownloadHandler() *DownloadHandler {
// @Produce json // @Produce json
// @Success 200 {string} string // @Success 200 {string} string
// @Router /download [get] // @Router /download [get]
func (d *DownloadHandler) checkLatest(ctx echo.Context) error { func (d *DownloadHandler) checkLatest(ctx *echo.Context) error {
log.Println("Checking latest version") logging.GetLogger().Info("Checking latest version")
latest := backend.CheckLatest() latest := backend.CheckLatest()
return ctx.JSON(http.StatusOK, latest) return ctx.JSON(http.StatusOK, latest)
} }
@@ -36,8 +36,8 @@ func (d *DownloadHandler) checkLatest(ctx echo.Context) error {
// @Produce json // @Produce json
// @Success 200 {array} string // @Success 200 {array} string
// @Router /download/list [get] // @Router /download/list [get]
func (d *DownloadHandler) listAssetsOfLatest(ctx echo.Context) error { func (d *DownloadHandler) listAssetsOfLatest(ctx *echo.Context) error {
log.Println("Listing assets") logging.GetLogger().Info("Listing assets")
assets := backend.ListAssetsOfLatest() assets := backend.ListAssetsOfLatest()
return ctx.JSON(http.StatusOK, assets) return ctx.JSON(http.StatusOK, assets)
} }
@@ -49,8 +49,8 @@ func (d *DownloadHandler) listAssetsOfLatest(ctx echo.Context) error {
// @Produce octet-stream // @Produce octet-stream
// @Success 302 {string} string // @Success 302 {string} string
// @Router /download/windows [get] // @Router /download/windows [get]
func (d *DownloadHandler) downloadLatestWindows(ctx echo.Context) error { func (d *DownloadHandler) downloadLatestWindows(ctx *echo.Context) error {
log.Println("Downloading latest windows") logging.GetLogger().Info("Downloading latest windows")
asset := backend.DownloadLatestWindows() asset := backend.DownloadLatestWindows()
ctx.Response().Header().Set("Content-Type", "application/octet-stream") ctx.Response().Header().Set("Content-Type", "application/octet-stream")
return ctx.Redirect(http.StatusFound, asset) return ctx.Redirect(http.StatusFound, asset)
@@ -63,8 +63,8 @@ func (d *DownloadHandler) downloadLatestWindows(ctx echo.Context) error {
// @Produce octet-stream // @Produce octet-stream
// @Success 302 {string} string // @Success 302 {string} string
// @Router /download/linux [get] // @Router /download/linux [get]
func (d *DownloadHandler) downloadLatestLinux(ctx echo.Context) error { func (d *DownloadHandler) downloadLatestLinux(ctx *echo.Context) error {
log.Println("Downloading latest linux") logging.GetLogger().Info("Downloading latest linux")
asset := backend.DownloadLatestLinux() asset := backend.DownloadLatestLinux()
ctx.Response().Header().Set("Content-Type", "application/octet-stream") ctx.Response().Header().Set("Content-Type", "application/octet-stream")
return ctx.Redirect(http.StatusFound, asset) return ctx.Redirect(http.StatusFound, asset)
+6 -6
View File
@@ -5,7 +5,7 @@ import (
"music-server/internal/db" "music-server/internal/db"
"net/http" "net/http"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v5"
) )
type IndexHandler struct { type IndexHandler struct {
@@ -25,7 +25,7 @@ func NewIndexHandler() *IndexHandler {
// @Success 200 {object} backend.VersionData // @Success 200 {object} backend.VersionData
// @Failure 404 {object} string // @Failure 404 {object} string
// @Router /version [get] // @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 == "" {
return ctx.JSON(http.StatusNotFound, "version not found") return ctx.JSON(http.StatusNotFound, "version not found")
@@ -41,7 +41,7 @@ func (i *IndexHandler) GetVersion(ctx echo.Context) error {
// @Produce json // @Produce json
// @Success 200 {string} string "TestedDB" // @Success 200 {string} string "TestedDB"
// @Router /dbtest [get] // @Router /dbtest [get]
func (i *IndexHandler) GetDBTest(ctx echo.Context) error { func (i *IndexHandler) GetDBTest(ctx *echo.Context) error {
backend.TestDB() backend.TestDB()
return ctx.JSON(http.StatusOK, "TestedDB") return ctx.JSON(http.StatusOK, "TestedDB")
} }
@@ -54,7 +54,7 @@ func (i *IndexHandler) GetDBTest(ctx echo.Context) error {
// @Produce json // @Produce json
// @Success 200 {string} string "OK" // @Success 200 {string} string "OK"
// @Router /health [get] // @Router /health [get]
func (i *IndexHandler) HealthCheck(ctx echo.Context) error { func (i *IndexHandler) HealthCheck(ctx *echo.Context) error {
return ctx.JSON(http.StatusOK, db.Health()) return ctx.JSON(http.StatusOK, db.Health())
} }
@@ -66,7 +66,7 @@ func (i *IndexHandler) HealthCheck(ctx echo.Context) error {
// @Produce json // @Produce json
// @Success 200 {array} string // @Success 200 {array} string
// @Router /characters [get] // @Router /characters [get]
func (i *IndexHandler) GetCharacterList(ctx echo.Context) error { func (i *IndexHandler) GetCharacterList(ctx *echo.Context) error {
characters := backend.GetCharacterList() characters := backend.GetCharacterList()
return ctx.JSON(http.StatusOK, characters) return ctx.JSON(http.StatusOK, characters)
} }
@@ -80,7 +80,7 @@ func (i *IndexHandler) GetCharacterList(ctx echo.Context) error {
// @Param name query string true "Character name" // @Param name query string true "Character name"
// @Success 200 {file} file // @Success 200 {file} file
// @Router /character [get] // @Router /character [get]
func (i *IndexHandler) GetCharacter(ctx echo.Context) error { func (i *IndexHandler) GetCharacter(ctx *echo.Context) error {
character := ctx.QueryParam("name") character := ctx.QueryParam("name")
return ctx.File(backend.GetCharacter(character)) return ctx.File(backend.GetCharacter(character))
} }
+40 -39
View File
@@ -1,13 +1,14 @@
package server package server
import ( import (
"log"
"music-server/internal/backend" "music-server/internal/backend"
"music-server/internal/logging"
"net/http" "net/http"
"os" "os"
"strconv" "strconv"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v5"
"go.uber.org/zap"
) )
type MusicHandler struct { type MusicHandler struct {
@@ -29,9 +30,9 @@ func NewMusicHandler() *MusicHandler {
// @Failure 404 {string} string "Not Found" // @Failure 404 {string} string "Not Found"
// @Failure 423 {string} string "Syncing is in progress" // @Failure 423 {string} string "Syncing is in progress"
// @Router /music [get] // @Router /music [get]
func (m *MusicHandler) GetSong(ctx echo.Context) error { func (m *MusicHandler) GetSong(ctx *echo.Context) error {
if backend.Syncing { if backend.Syncing {
log.Println("Syncing is in progress") logging.GetLogger().Info("Syncing is in progress")
return ctx.JSON(http.StatusLocked, "Syncing is in progress") return ctx.JSON(http.StatusLocked, "Syncing is in progress")
} }
song := ctx.QueryParam("song") song := ctx.QueryParam("song")
@@ -41,7 +42,7 @@ func (m *MusicHandler) GetSong(ctx echo.Context) error {
songPath := backend.GetSong(song) songPath := backend.GetSong(song)
file, err := os.Open(songPath) file, err := os.Open(songPath)
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusNotFound, err) return echo.NewHTTPError(http.StatusNotFound, err.Error())
} }
defer file.Close() defer file.Close()
return ctx.Stream(http.StatusOK, "audio/mpeg", file) return ctx.Stream(http.StatusOK, "audio/mpeg", file)
@@ -56,15 +57,15 @@ func (m *MusicHandler) GetSong(ctx echo.Context) error {
// @Failure 404 {string} string "Not Found" // @Failure 404 {string} string "Not Found"
// @Failure 423 {string} string "Syncing is in progress" // @Failure 423 {string} string "Syncing is in progress"
// @Router /music/soundTest [get] // @Router /music/soundTest [get]
func (m *MusicHandler) GetSoundCheckSong(ctx echo.Context) error { func (m *MusicHandler) GetSoundCheckSong(ctx *echo.Context) error {
if backend.Syncing { if backend.Syncing {
log.Println("Syncing is in progress") logging.GetLogger().Info("Syncing is in progress")
return ctx.JSON(http.StatusLocked, "Syncing is in progress") return ctx.JSON(http.StatusLocked, "Syncing is in progress")
} }
songPath := backend.GetSoundCheckSong() songPath := backend.GetSoundCheckSong()
file, err := os.Open(songPath) file, err := os.Open(songPath)
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusNotFound, err) return echo.NewHTTPError(http.StatusNotFound, err.Error())
} }
defer file.Close() defer file.Close()
return ctx.Stream(http.StatusOK, "audio/mpeg", file) return ctx.Stream(http.StatusOK, "audio/mpeg", file)
@@ -78,9 +79,9 @@ func (m *MusicHandler) GetSoundCheckSong(ctx echo.Context) error {
// @Success 204 // @Success 204
// @Failure 423 {string} string "Syncing is in progress" // @Failure 423 {string} string "Syncing is in progress"
// @Router /music/reset [get] // @Router /music/reset [get]
func (m *MusicHandler) ResetMusic(ctx echo.Context) error { func (m *MusicHandler) ResetMusic(ctx *echo.Context) error {
if backend.Syncing { if backend.Syncing {
log.Println("Syncing is in progress") logging.GetLogger().Info("Syncing is in progress")
return ctx.JSON(http.StatusLocked, "Syncing is in progress") return ctx.JSON(http.StatusLocked, "Syncing is in progress")
} }
backend.Reset() backend.Reset()
@@ -96,15 +97,15 @@ func (m *MusicHandler) ResetMusic(ctx echo.Context) error {
// @Failure 404 {string} string "Not Found" // @Failure 404 {string} string "Not Found"
// @Failure 423 {string} string "Syncing is in progress" // @Failure 423 {string} string "Syncing is in progress"
// @Router /music/rand [get] // @Router /music/rand [get]
func (m *MusicHandler) GetRandomSong(ctx echo.Context) error { func (m *MusicHandler) GetRandomSong(ctx *echo.Context) error {
if backend.Syncing { if backend.Syncing {
log.Println("Syncing is in progress") logging.GetLogger().Info("Syncing is in progress")
return ctx.JSON(http.StatusLocked, "Syncing is in progress") return ctx.JSON(http.StatusLocked, "Syncing is in progress")
} }
songPath := backend.GetRandomSong() songPath := backend.GetRandomSong()
file, err := os.Open(songPath) file, err := os.Open(songPath)
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusNotFound, err) return echo.NewHTTPError(http.StatusNotFound, err.Error())
} }
defer file.Close() defer file.Close()
return ctx.Stream(http.StatusOK, "audio/mpeg", file) return ctx.Stream(http.StatusOK, "audio/mpeg", file)
@@ -119,15 +120,15 @@ func (m *MusicHandler) GetRandomSong(ctx echo.Context) error {
// @Failure 404 {string} string "Not Found" // @Failure 404 {string} string "Not Found"
// @Failure 423 {string} string "Syncing is in progress" // @Failure 423 {string} string "Syncing is in progress"
// @Router /music/rand/low [get] // @Router /music/rand/low [get]
func (m *MusicHandler) GetRandomSongLowChance(ctx echo.Context) error { func (m *MusicHandler) GetRandomSongLowChance(ctx *echo.Context) error {
if backend.Syncing { if backend.Syncing {
log.Println("Syncing is in progress") logging.GetLogger().Info("Syncing is in progress")
return ctx.JSON(http.StatusLocked, "Syncing is in progress") return ctx.JSON(http.StatusLocked, "Syncing is in progress")
} }
songPath := backend.GetRandomSongLowChance() songPath := backend.GetRandomSongLowChance()
file, err := os.Open(songPath) file, err := os.Open(songPath)
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusNotFound, err) return echo.NewHTTPError(http.StatusNotFound, err.Error())
} }
defer file.Close() defer file.Close()
return ctx.Stream(http.StatusOK, "audio/mpeg", file) return ctx.Stream(http.StatusOK, "audio/mpeg", file)
@@ -142,15 +143,15 @@ func (m *MusicHandler) GetRandomSongLowChance(ctx echo.Context) error {
// @Failure 404 {string} string "Not Found" // @Failure 404 {string} string "Not Found"
// @Failure 423 {string} string "Syncing is in progress" // @Failure 423 {string} string "Syncing is in progress"
// @Router /music/rand/classic [get] // @Router /music/rand/classic [get]
func (m *MusicHandler) GetRandomSongClassic(ctx echo.Context) error { func (m *MusicHandler) GetRandomSongClassic(ctx *echo.Context) error {
if backend.Syncing { if backend.Syncing {
log.Println("Syncing is in progress") logging.GetLogger().Info("Syncing is in progress")
return ctx.JSON(http.StatusLocked, "Syncing is in progress") return ctx.JSON(http.StatusLocked, "Syncing is in progress")
} }
songPath := backend.GetRandomSongClassic() songPath := backend.GetRandomSongClassic()
file, err := os.Open(songPath) file, err := os.Open(songPath)
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusNotFound, err) return echo.NewHTTPError(http.StatusNotFound, err.Error())
} }
defer file.Close() defer file.Close()
return ctx.Stream(http.StatusOK, "audio/mpeg", file) return ctx.Stream(http.StatusOK, "audio/mpeg", file)
@@ -164,7 +165,7 @@ func (m *MusicHandler) GetRandomSongClassic(ctx echo.Context) error {
// @Produce json // @Produce json
// @Success 200 {object} map[string]interface{} // @Success 200 {object} map[string]interface{}
// @Router /music/info [get] // @Router /music/info [get]
func (m *MusicHandler) GetSongInfo(ctx echo.Context) error { func (m *MusicHandler) GetSongInfo(ctx *echo.Context) error {
song := backend.GetSongInfo() song := backend.GetSongInfo()
return ctx.JSON(http.StatusOK, song) return ctx.JSON(http.StatusOK, song)
} }
@@ -177,7 +178,7 @@ func (m *MusicHandler) GetSongInfo(ctx echo.Context) error {
// @Produce json // @Produce json
// @Success 200 {array} map[string]interface{} // @Success 200 {array} map[string]interface{}
// @Router /music/list [get] // @Router /music/list [get]
func (m *MusicHandler) GetPlayedSongs(ctx echo.Context) error { func (m *MusicHandler) GetPlayedSongs(ctx *echo.Context) error {
songList := backend.GetPlayedSongs() songList := backend.GetPlayedSongs()
return ctx.JSON(http.StatusOK, songList) return ctx.JSON(http.StatusOK, songList)
} }
@@ -191,15 +192,15 @@ func (m *MusicHandler) GetPlayedSongs(ctx echo.Context) error {
// @Failure 404 {string} string "Not Found" // @Failure 404 {string} string "Not Found"
// @Failure 423 {string} string "Syncing is in progress" // @Failure 423 {string} string "Syncing is in progress"
// @Router /music/next [get] // @Router /music/next [get]
func (m *MusicHandler) GetNextSong(ctx echo.Context) error { func (m *MusicHandler) GetNextSong(ctx *echo.Context) error {
if backend.Syncing { if backend.Syncing {
log.Println("Syncing is in progress") logging.GetLogger().Info("Syncing is in progress")
return ctx.JSON(http.StatusLocked, "Syncing is in progress") return ctx.JSON(http.StatusLocked, "Syncing is in progress")
} }
songPath := backend.GetNextSong() songPath := backend.GetNextSong()
file, err := os.Open(songPath) file, err := os.Open(songPath)
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusNotFound, err) return echo.NewHTTPError(http.StatusNotFound, err.Error())
} }
defer file.Close() defer file.Close()
return ctx.Stream(http.StatusOK, "audio/mpeg", file) return ctx.Stream(http.StatusOK, "audio/mpeg", file)
@@ -214,15 +215,15 @@ func (m *MusicHandler) GetNextSong(ctx echo.Context) error {
// @Failure 404 {string} string "Not Found" // @Failure 404 {string} string "Not Found"
// @Failure 423 {string} string "Syncing is in progress" // @Failure 423 {string} string "Syncing is in progress"
// @Router /music/previous [get] // @Router /music/previous [get]
func (m *MusicHandler) GetPreviousSong(ctx echo.Context) error { func (m *MusicHandler) GetPreviousSong(ctx *echo.Context) error {
if backend.Syncing { if backend.Syncing {
log.Println("Syncing is in progress") logging.GetLogger().Info("Syncing is in progress")
return ctx.JSON(http.StatusLocked, "Syncing is in progress") return ctx.JSON(http.StatusLocked, "Syncing is in progress")
} }
songPath := backend.GetPreviousSong() songPath := backend.GetPreviousSong()
file, err := os.Open(songPath) file, err := os.Open(songPath)
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusNotFound, err) return echo.NewHTTPError(http.StatusNotFound, err.Error())
} }
defer file.Close() defer file.Close()
return ctx.Stream(http.StatusOK, "audio/mpeg", file) return ctx.Stream(http.StatusOK, "audio/mpeg", file)
@@ -237,9 +238,9 @@ func (m *MusicHandler) GetPreviousSong(ctx echo.Context) error {
// @Success 200 {array} map[string]interface{} // @Success 200 {array} map[string]interface{}
// @Failure 423 {string} string "Syncing is in progress" // @Failure 423 {string} string "Syncing is in progress"
// @Router /music/all/order [get] // @Router /music/all/order [get]
func (m *MusicHandler) GetAllGames(ctx echo.Context) error { func (m *MusicHandler) GetAllGames(ctx *echo.Context) error {
if backend.Syncing { if backend.Syncing {
log.Println("Syncing is in progress") logging.GetLogger().Info("Syncing is in progress")
return ctx.JSON(http.StatusLocked, "Syncing is in progress") return ctx.JSON(http.StatusLocked, "Syncing is in progress")
} }
gameList := backend.GetAllGames() gameList := backend.GetAllGames()
@@ -255,9 +256,9 @@ func (m *MusicHandler) GetAllGames(ctx echo.Context) error {
// @Success 200 {array} map[string]interface{} // @Success 200 {array} map[string]interface{}
// @Failure 423 {string} string "Syncing is in progress" // @Failure 423 {string} string "Syncing is in progress"
// @Router /music/all/random [get] // @Router /music/all/random [get]
func (m *MusicHandler) GetAllGamesRandom(ctx echo.Context) error { func (m *MusicHandler) GetAllGamesRandom(ctx *echo.Context) error {
if backend.Syncing { if backend.Syncing {
log.Println("Syncing is in progress") logging.GetLogger().Info("Syncing is in progress")
return ctx.JSON(http.StatusLocked, "Syncing is in progress") return ctx.JSON(http.StatusLocked, "Syncing is in progress")
} }
gameList := backend.GetAllGamesRandom() gameList := backend.GetAllGamesRandom()
@@ -275,16 +276,16 @@ func (m *MusicHandler) GetAllGamesRandom(ctx echo.Context) error {
// @Failure 400 {string} string "Bad Request" // @Failure 400 {string} string "Bad Request"
// @Failure 423 {string} string "Syncing is in progress" // @Failure 423 {string} string "Syncing is in progress"
// @Router /music/played [put] // @Router /music/played [put]
func (m *MusicHandler) PutPlayed(ctx echo.Context) error { func (m *MusicHandler) PutPlayed(ctx *echo.Context) error {
if backend.Syncing { if backend.Syncing {
log.Println("Syncing is in progress") logging.GetLogger().Info("Syncing is in progress")
return ctx.JSON(http.StatusLocked, "Syncing is in progress") return ctx.JSON(http.StatusLocked, "Syncing is in progress")
} }
song, err := strconv.Atoi(ctx.QueryParam("song")) song, err := strconv.Atoi(ctx.QueryParam("song"))
if err != nil { if err != nil {
return ctx.JSON(http.StatusBadRequest, err) return ctx.JSON(http.StatusBadRequest, err.Error())
} }
log.Println("song", song) logging.GetLogger().Info("Marking song as played", zap.Int("song_id", song))
backend.SetPlayed(song) backend.SetPlayed(song)
return ctx.NoContent(http.StatusOK) return ctx.NoContent(http.StatusOK)
} }
@@ -297,9 +298,9 @@ func (m *MusicHandler) PutPlayed(ctx echo.Context) error {
// @Success 204 // @Success 204
// @Failure 423 {string} string "Syncing is in progress" // @Failure 423 {string} string "Syncing is in progress"
// @Router /music/addQue [get] // @Router /music/addQue [get]
func (m *MusicHandler) AddLatestToQue(ctx echo.Context) error { func (m *MusicHandler) AddLatestToQue(ctx *echo.Context) error {
if backend.Syncing { if backend.Syncing {
log.Println("Syncing is in progress") logging.GetLogger().Info("Syncing is in progress")
return ctx.JSON(http.StatusLocked, "Syncing is in progress") return ctx.JSON(http.StatusLocked, "Syncing is in progress")
} }
backend.AddLatestToQue() backend.AddLatestToQue()
@@ -314,9 +315,9 @@ func (m *MusicHandler) AddLatestToQue(ctx echo.Context) error {
// @Success 204 // @Success 204
// @Failure 423 {string} string "Syncing is in progress" // @Failure 423 {string} string "Syncing is in progress"
// @Router /music/addPlayed [get] // @Router /music/addPlayed [get]
func (m *MusicHandler) AddLatestPlayed(ctx echo.Context) error { func (m *MusicHandler) AddLatestPlayed(ctx *echo.Context) error {
if backend.Syncing { if backend.Syncing {
log.Println("Syncing is in progress") logging.GetLogger().Info("Syncing is in progress")
return ctx.JSON(http.StatusLocked, "Syncing is in progress") return ctx.JSON(http.StatusLocked, "Syncing is in progress")
} }
backend.AddLatestPlayed() backend.AddLatestPlayed()
+7 -6
View File
@@ -8,9 +8,10 @@ import (
"strings" "strings"
"github.com/a-h/templ" "github.com/a-h/templ"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v5"
"github.com/labstack/echo/v4/middleware" "github.com/labstack/echo/v5/middleware"
"github.com/swaggo/echo-swagger" echoSwagger "github.com/swaggo/echo-swagger/v2"
"music-server/internal/logging"
) )
// @Title MusicServer API // @Title MusicServer API
@@ -34,7 +35,7 @@ func (s *Server) RegisterRoutes() http.Handler {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
http.ServeFile(w, r, "cmd/docs/swagger.json") http.ServeFile(w, r, "cmd/docs/swagger.json")
}))) })))
e.Use(middleware.Logger()) e.Use(logging.RequestLogger())
e.Use(middleware.Recover()) e.Use(middleware.Recover())
e.Use(middleware.CORSWithConfig(middleware.CORSConfig{ e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
@@ -98,13 +99,13 @@ func (s *Server) RegisterRoutes() http.Handler {
musicGroup.GET("/addQue", music.AddLatestToQue) musicGroup.GET("/addQue", music.AddLatestToQue)
musicGroup.GET("/addPlayed", music.AddLatestPlayed) musicGroup.GET("/addPlayed", music.AddLatestPlayed)
routes := e.Routes() routes := e.Router().Routes()
sort.Slice(routes, func(i, j int) bool { sort.Slice(routes, func(i, j int) bool {
return routes[i].Path < routes[j].Path return routes[i].Path < routes[j].Path
}) })
for _, r := range routes { for _, r := range routes {
if (r.Method == "GET" || r.Method == "POST" || r.Method == "PUT" || r.Method == "DELETE") && !strings.Contains(r.Name, "github") { 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) fmt.Printf(" %s\t\t%s\n", r.Method, r.Path)
} }
} }
return e return e
+26 -8
View File
@@ -2,12 +2,15 @@ package server
import ( import (
"fmt" "fmt"
"log"
"music-server/internal/db"
"net/http"
"os" "os"
"strconv" "strconv"
"time" "time"
"music-server/internal/db"
"music-server/internal/logging"
"net/http"
"go.uber.org/zap"
) )
type Server struct { type Server struct {
@@ -22,24 +25,39 @@ var (
password = os.Getenv("DB_PASSWORD") password = os.Getenv("DB_PASSWORD")
musicPath = os.Getenv("MUSIC_PATH") musicPath = os.Getenv("MUSIC_PATH")
charactersPath = os.Getenv("CHARACTERS_PATH") charactersPath = os.Getenv("CHARACTERS_PATH")
logLevel = os.Getenv("LOG_LEVEL")
logJSON = os.Getenv("LOG_JSON") == "true"
) )
func NewServer() *http.Server { func NewServer() *http.Server {
// Initialize logger
if logLevel == "" {
logLevel = "info"
}
logging.Init(logLevel, logJSON)
logger := logging.GetLogger()
port, _ := strconv.Atoi(os.Getenv("PORT")) port, _ := strconv.Atoi(os.Getenv("PORT"))
NewServer := &Server{ NewServer := &Server{
port: port, port: port,
} }
fmt.Printf("host: %s, dbPort: %v, username: %s, password: %s, dbName: %s\n", logger.Info("Starting server",
host, dbPort, username, password, dbName) zap.String("host", host),
zap.String("dbPort", dbPort),
zap.String("username", username),
zap.String("dbName", dbName),
)
log.Printf("musicPath: %s\n", musicPath) logger.Info("Paths",
log.Printf("charactersPath: %s\n", charactersPath) zap.String("musicPath", musicPath),
zap.String("charactersPath", charactersPath),
)
//conf.SetupDb() //conf.SetupDb()
if host == "" || dbPort == "" || username == "" || password == "" || dbName == "" || musicPath == "" || charactersPath == "" { if host == "" || dbPort == "" || username == "" || password == "" || dbName == "" || musicPath == "" || charactersPath == "" {
log.Fatal("Invalid settings") logging.GetLogger().Fatal("Invalid settings - missing required environment variables")
} }
db.Migrate_db(host, dbPort, username, password, dbName) db.Migrate_db(host, dbPort, username, password, dbName)
+14 -13
View File
@@ -1,11 +1,11 @@
package server package server
import ( import (
"log"
"music-server/internal/backend" "music-server/internal/backend"
"music-server/internal/logging"
"net/http" "net/http"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v5"
) )
type SyncHandler struct { type SyncHandler struct {
@@ -23,13 +23,13 @@ func NewSyncHandler() *SyncHandler {
// @Produce json // @Produce json
// @Success 200 {object} map[string]interface{} // @Success 200 {object} map[string]interface{}
// @Router /sync/progress [get] // @Router /sync/progress [get]
func (s *SyncHandler) SyncProgress(ctx echo.Context) error { func (s *SyncHandler) SyncProgress(ctx *echo.Context) error {
if backend.Syncing { if backend.Syncing {
log.Println("Getting progress") logging.GetLogger().Info("Getting sync progress")
response := backend.SyncProgress() response := backend.SyncProgress()
return ctx.JSON(http.StatusOK, response) return ctx.JSON(http.StatusOK, response)
} }
log.Println("Getting result") logging.GetLogger().Info("Getting sync result")
response := backend.SyncResult() response := backend.SyncResult()
return ctx.JSON(http.StatusOK, response) return ctx.JSON(http.StatusOK, response)
} }
@@ -43,12 +43,12 @@ func (s *SyncHandler) SyncProgress(ctx echo.Context) error {
// @Success 200 {string} string "Start syncing games" // @Success 200 {string} string "Start syncing games"
// @Failure 423 {string} string "Syncing is in progress" // @Failure 423 {string} string "Syncing is in progress"
// @Router /sync [get] // @Router /sync [get]
func (s *SyncHandler) SyncGamesNewOnlyChanges(ctx echo.Context) error { func (s *SyncHandler) SyncGamesNewOnlyChanges(ctx *echo.Context) error {
if backend.Syncing { if backend.Syncing {
log.Println("Syncing is in progress") logging.GetLogger().Warn("Syncing is already in progress")
return ctx.JSON(http.StatusLocked, "Syncing is in progress") return ctx.JSON(http.StatusLocked, "Syncing is in progress")
} }
log.Println("Start syncing games") logging.GetLogger().Info("Starting sync with only changes")
go backend.SyncGamesNewOnlyChanges() go backend.SyncGamesNewOnlyChanges()
return ctx.JSON(http.StatusOK, "Start syncing games") return ctx.JSON(http.StatusOK, "Start syncing games")
} }
@@ -62,12 +62,12 @@ func (s *SyncHandler) SyncGamesNewOnlyChanges(ctx echo.Context) error {
// @Success 200 {string} string "Start syncing games full" // @Success 200 {string} string "Start syncing games full"
// @Failure 423 {string} string "Syncing is in progress" // @Failure 423 {string} string "Syncing is in progress"
// @Router /sync/full [get] // @Router /sync/full [get]
func (s *SyncHandler) SyncGamesNewFull(ctx echo.Context) error { func (s *SyncHandler) SyncGamesNewFull(ctx *echo.Context) error {
if backend.Syncing { if backend.Syncing {
log.Println("Syncing is in progress") logging.GetLogger().Warn("Syncing is already in progress")
return ctx.JSON(http.StatusLocked, "Syncing is in progress") return ctx.JSON(http.StatusLocked, "Syncing is in progress")
} }
log.Println("Start syncing games full") logging.GetLogger().Info("Starting full sync")
go backend.SyncGamesNewFull() go backend.SyncGamesNewFull()
return ctx.JSON(http.StatusOK, "Start syncing games full") return ctx.JSON(http.StatusOK, "Start syncing games full")
} }
@@ -81,11 +81,12 @@ func (s *SyncHandler) SyncGamesNewFull(ctx echo.Context) error {
// @Success 200 {string} string "Games and songs are deleted from the database" // @Success 200 {string} string "Games and songs are deleted from the database"
// @Failure 423 {string} string "Syncing is in progress" // @Failure 423 {string} string "Syncing is in progress"
// @Router /sync/reset [get] // @Router /sync/reset [get]
func (s *SyncHandler) ResetGames(ctx echo.Context) error { func (s *SyncHandler) ResetGames(ctx *echo.Context) error {
if backend.Syncing { if backend.Syncing {
log.Println("Syncing is in progress") logging.GetLogger().Warn("Cannot reset - syncing is in progress")
return ctx.JSON(http.StatusLocked, "Syncing is in progress") return ctx.JSON(http.StatusLocked, "Syncing is in progress")
} }
logging.GetLogger().Info("Resetting games database")
backend.ResetDB() backend.ResetDB()
return ctx.JSON(http.StatusOK, "Games and songs are deleted from the database") return ctx.JSON(http.StatusOK, "Games and songs are deleted from the database")
} }
+12 -1
View File
@@ -60,8 +60,19 @@ swag-generate: swag-install
@echo "Generating OpenAPI docs..." @echo "Generating OpenAPI docs..."
@swag init -g internal/server/routes.go -o cmd/docs @swag init -g internal/server/routes.go -o cmd/docs
frontend-install:
@if ! command -v npm > /dev/null; then \
echo "npm is not installed on your machine. Please install Node.js first."; \
exit 1; \
fi
@cd cmd/frontend && npm install
frontend-build: frontend-install
@echo "Building frontend..."
@cd cmd/frontend && npm run build
[no-cd] [no-cd]
build: sqlc-generate templ-build tailwind-build swag-generate build: sqlc-generate templ-build swag-generate
@echo "Building..." @echo "Building..."
@go build -o main cmd/main.go @go build -o main cmd/main.go