dropped fiber for std http + gorilla websocket
Session serialization will use gob encoding instead of json. Binary size will likely be reduced. General backend code refactoring.
This commit is contained in:
10
.vscode/launch.json
vendored
10
.vscode/launch.json
vendored
@@ -4,13 +4,19 @@
|
|||||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Launch file",
|
||||||
|
"type": "go",
|
||||||
|
"request": "launch",
|
||||||
|
"mode": "debug",
|
||||||
|
"program": "${file}"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "chrome",
|
"type": "chrome",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"name": "Launch Chrome against localhost",
|
"name": "Launch Chrome against localhost",
|
||||||
"url": "http://localhost:1234",
|
"url": "http://localhost:5173",
|
||||||
"webRoot": "${workspaceFolder}",
|
"webRoot": "${workspaceFolder}",
|
||||||
"breakOnLoad": true,
|
|
||||||
"sourceMapPathOverrides": {
|
"sourceMapPathOverrides": {
|
||||||
"/__parcel_source_root/*": "${webRoot}/*"
|
"/__parcel_source_root/*": "${webRoot}/*"
|
||||||
}
|
}
|
||||||
|
|||||||
21
go.mod
21
go.mod
@@ -3,29 +3,12 @@ module github.com/marcopeocchi/yt-dlp-web-ui
|
|||||||
go 1.20
|
go 1.20
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/go-chi/chi/v5 v5.0.10
|
||||||
github.com/goccy/go-json v0.10.2
|
github.com/goccy/go-json v0.10.2
|
||||||
github.com/gofiber/fiber/v2 v2.47.0
|
|
||||||
github.com/gofiber/websocket/v2 v2.2.1
|
|
||||||
github.com/golang-jwt/jwt/v5 v5.0.0
|
github.com/golang-jwt/jwt/v5 v5.0.0
|
||||||
github.com/google/uuid v1.3.0
|
github.com/google/uuid v1.3.0
|
||||||
|
github.com/gorilla/websocket v1.5.0
|
||||||
github.com/marcopeocchi/fazzoletti v0.0.0-20230308161120-c545580f79fa
|
github.com/marcopeocchi/fazzoletti v0.0.0-20230308161120-c545580f79fa
|
||||||
golang.org/x/sys v0.9.0
|
golang.org/x/sys v0.9.0
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
|
||||||
github.com/andybalholm/brotli v1.0.5 // indirect
|
|
||||||
github.com/fasthttp/websocket v1.5.3 // indirect
|
|
||||||
github.com/klauspost/compress v1.16.6 // indirect
|
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
|
||||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
|
||||||
github.com/mattn/go-runewidth v0.0.14 // indirect
|
|
||||||
github.com/philhofer/fwd v1.1.2 // indirect
|
|
||||||
github.com/rivo/uniseg v0.4.4 // indirect
|
|
||||||
github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 // indirect
|
|
||||||
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect
|
|
||||||
github.com/tinylib/msgp v1.1.8 // indirect
|
|
||||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
|
||||||
github.com/valyala/fasthttp v1.48.0 // indirect
|
|
||||||
github.com/valyala/tcplisten v1.0.0 // indirect
|
|
||||||
)
|
|
||||||
|
|||||||
85
go.sum
85
go.sum
@@ -1,94 +1,17 @@
|
|||||||
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk=
|
||||||
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||||
github.com/fasthttp/websocket v1.5.3 h1:TPpQuLwJYfd4LJPXvHDYPMFWbLjsT91n3GpWtCQtdek=
|
|
||||||
github.com/fasthttp/websocket v1.5.3/go.mod h1:46gg/UBmTU1kUaTcwQXpUxtRwG2PvIZYeA8oL6vF3Fs=
|
|
||||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||||
github.com/gofiber/fiber/v2 v2.47.0 h1:EN5lHVCc+Pyqh5OEsk8fzRiifgwpbrP0rulQ4iNf3fs=
|
|
||||||
github.com/gofiber/fiber/v2 v2.47.0/go.mod h1:mbFMVN1lQuzziTkkakgtKKdjfsXSw9BKR5lmcNksUoU=
|
|
||||||
github.com/gofiber/websocket/v2 v2.2.1 h1:C9cjxvloojayOp9AovmpQrk8VqvVnT8Oao3+IUygH7w=
|
|
||||||
github.com/gofiber/websocket/v2 v2.2.1/go.mod h1:Ao/+nyNnX5u/hIFPuHl28a+NIkrqK7PRimyKaj4JxVU=
|
|
||||||
github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE=
|
github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE=
|
||||||
github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/klauspost/compress v1.16.6 h1:91SKEy4K37vkp255cJ8QesJhjyRO0hn9i9G0GoUwLsk=
|
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||||
github.com/klauspost/compress v1.16.6/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/marcopeocchi/fazzoletti v0.0.0-20230308161120-c545580f79fa h1:uaAQLGhN4SesB9inOQ1Q6EH+BwTWHQOvwhR0TIJvnYc=
|
github.com/marcopeocchi/fazzoletti v0.0.0-20230308161120-c545580f79fa h1:uaAQLGhN4SesB9inOQ1Q6EH+BwTWHQOvwhR0TIJvnYc=
|
||||||
github.com/marcopeocchi/fazzoletti v0.0.0-20230308161120-c545580f79fa/go.mod h1:RvfVo/6Sbnfra9kkvIxDW8NYOOaYsHjF0DdtMCs9cdo=
|
github.com/marcopeocchi/fazzoletti v0.0.0-20230308161120-c545580f79fa/go.mod h1:RvfVo/6Sbnfra9kkvIxDW8NYOOaYsHjF0DdtMCs9cdo=
|
||||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
|
||||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
|
||||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
|
||||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
|
||||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
|
||||||
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
|
|
||||||
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
|
||||||
github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
|
|
||||||
github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw=
|
|
||||||
github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0=
|
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
|
||||||
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
|
|
||||||
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
|
||||||
github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 h1:rmMl4fXJhKMNWl+K+r/fq4FbbKI+Ia2m9hYBLm2h4G4=
|
|
||||||
github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94/go.mod h1:90zrgN3D/WJsDd1iXHT96alCoN2KJo6/4x1DZC3wZs8=
|
|
||||||
github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d/go.mod h1:Gy+0tqhJvgGlqnTF8CVGP0AaGRjwBtXs/a5PA0Y3+A4=
|
|
||||||
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk=
|
|
||||||
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g=
|
|
||||||
github.com/tinylib/msgp v1.1.6/go.mod h1:75BAfg2hauQhs3qedfdDZmWAPcFMAvJE5b9rGOMufyw=
|
|
||||||
github.com/tinylib/msgp v1.1.8 h1:FCXC1xanKO4I8plpHGH2P7koL/RzZs12l/+r7vakfm0=
|
|
||||||
github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw=
|
|
||||||
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/fasthttp v1.48.0 h1:oJWvHb9BIZToTQS3MuQ2R3bJZiNSa2KiNdeI8A+79Tc=
|
|
||||||
github.com/valyala/fasthttp v1.48.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA=
|
|
||||||
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
|
|
||||||
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
|
||||||
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
|
||||||
golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/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/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-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.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
|
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
|
||||||
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
|
||||||
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
|
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
|
||||||
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
|
||||||
golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
|
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
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/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
package internal
|
package internal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/gob"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/goccy/go-json"
|
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/marcopeocchi/yt-dlp-web-ui/server/cli"
|
"github.com/marcopeocchi/yt-dlp-web-ui/server/cli"
|
||||||
)
|
)
|
||||||
@@ -93,25 +92,36 @@ func (m *MemoryDB) All() *[]ProcessResponse {
|
|||||||
func (m *MemoryDB) Persist() {
|
func (m *MemoryDB) Persist() {
|
||||||
running := m.All()
|
running := m.All()
|
||||||
|
|
||||||
session, err := json.Marshal(Session{
|
fd, err := os.Create("session.dat")
|
||||||
Processes: *running,
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(cli.Red, "Failed to persist database", cli.Reset)
|
log.Println(cli.Red, "Failed to persist session", cli.Reset)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = os.WriteFile("session.dat", session, 0700)
|
session := Session{
|
||||||
if err != nil {
|
Processes: *running,
|
||||||
log.Println(cli.Red, "Failed to persist database", cli.Reset)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = gob.NewEncoder(fd).Encode(session)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(cli.Red, "Failed to persist session", cli.Reset)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println(cli.BgBlue, "Successfully serialized session", cli.Reset)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WIP: Restore a persisted state
|
// WIP: Restore a persisted state
|
||||||
func (m *MemoryDB) Restore() {
|
func (m *MemoryDB) Restore() {
|
||||||
feed, _ := os.ReadFile("session.dat")
|
fd, err := os.Open("session.dat")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
session := Session{}
|
session := Session{}
|
||||||
json.Unmarshal(feed, &session)
|
|
||||||
|
err = gob.NewDecoder(fd).Decode(&session)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
for _, proc := range session.Processes {
|
for _, proc := range session.Processes {
|
||||||
m.table.Store(proc.Id, &Process{
|
m.table.Store(proc.Id, &Process{
|
||||||
@@ -122,4 +132,6 @@ func (m *MemoryDB) Restore() {
|
|||||||
DB: m,
|
DB: m,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Println(cli.BgGreen, "Successfully restored session", cli.Reset)
|
||||||
}
|
}
|
||||||
|
|||||||
15
server/middleware/cors.go
Normal file
15
server/middleware/cors.go
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package middlewares
|
||||||
|
|
||||||
|
import "net/http"
|
||||||
|
|
||||||
|
// Middleware for applying CORS policy for ALL hosts and for
|
||||||
|
// allowing ALL request headers.
|
||||||
|
func CORS(next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||||
|
w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
|
||||||
|
w.Header().Set("Access-Control-Allow-Headers", "*")
|
||||||
|
w.Header().Set("Access-Control-Allow-Credentials", "true")
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -2,10 +2,10 @@ package middlewares
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
|
||||||
"github.com/golang-jwt/jwt/v5"
|
"github.com/golang-jwt/jwt/v5"
|
||||||
"github.com/marcopeocchi/yt-dlp-web-ui/server/config"
|
"github.com/marcopeocchi/yt-dlp-web-ui/server/config"
|
||||||
)
|
)
|
||||||
@@ -14,37 +14,49 @@ const (
|
|||||||
TOKEN_COOKIE_NAME = "jwt"
|
TOKEN_COOKIE_NAME = "jwt"
|
||||||
)
|
)
|
||||||
|
|
||||||
var Authenticated = func(c *fiber.Ctx) error {
|
func Authenticated(next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
if !config.Instance().GetConfig().RequireAuth {
|
if !config.Instance().GetConfig().RequireAuth {
|
||||||
return c.Next()
|
next.ServeHTTP(w, r)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cookie := c.Cookies(TOKEN_COOKIE_NAME)
|
cookie, err := r.Cookie(TOKEN_COOKIE_NAME)
|
||||||
|
|
||||||
if cookie == "" {
|
if err != nil {
|
||||||
return c.Status(fiber.StatusUnauthorized).SendString("invalid token")
|
http.Error(w, "invalid token", http.StatusBadRequest)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
token, _ := jwt.Parse(cookie, func(t *jwt.Token) (interface{}, error) {
|
if cookie == nil {
|
||||||
|
http.Error(w, "invalid token", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
token, _ := jwt.Parse(cookie.Value, func(t *jwt.Token) (interface{}, error) {
|
||||||
if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
|
if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||||
return nil, fmt.Errorf("unexpected signing method: %v", t.Header["alg"])
|
return nil, fmt.Errorf("unexpected signing method: %v", t.Header["alg"])
|
||||||
}
|
}
|
||||||
return []byte(os.Getenv("JWT_SECRET")), nil
|
return []byte(os.Getenv("JWTSECRET")), nil
|
||||||
})
|
})
|
||||||
|
|
||||||
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
|
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
|
||||||
expiresAt, err := time.Parse(time.RFC3339, claims["expiresAt"].(string))
|
expiresAt, err := time.Parse(time.RFC3339, claims["expiresAt"].(string))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.SendStatus(fiber.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if time.Now().After(expiresAt) {
|
if time.Now().After(expiresAt) {
|
||||||
return c.Status(fiber.StatusBadRequest).SendString("expired token")
|
http.Error(w, "token expired", http.StatusBadRequest)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return c.Status(fiber.StatusUnauthorized).SendString("invalid token")
|
http.Error(w, "invalid token", http.StatusBadRequest)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.Next()
|
next.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
93
server/middleware/spa_handler.go
Normal file
93
server/middleware/spa_handler.go
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
package middlewares
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/fs"
|
||||||
|
"mime"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SpaHandler struct {
|
||||||
|
Entrypoint string
|
||||||
|
Filesystem fs.FS
|
||||||
|
routes []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSpaHandler(index string, fs fs.FS) *SpaHandler {
|
||||||
|
return &SpaHandler{
|
||||||
|
Entrypoint: index,
|
||||||
|
Filesystem: fs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SpaHandler) AddClientRoute(route string) *SpaHandler {
|
||||||
|
s.routes = append(s.routes, route)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handler for serving a compiled react frontend
|
||||||
|
// each client-side routes must be provided
|
||||||
|
func (s *SpaHandler) Handler() http.HandlerFunc {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != http.MethodGet {
|
||||||
|
http.Error(
|
||||||
|
w,
|
||||||
|
http.StatusText(http.StatusMethodNotAllowed),
|
||||||
|
http.StatusMethodNotAllowed,
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
path := filepath.Clean(r.URL.Path)
|
||||||
|
|
||||||
|
// basically all frontend routes are needed :/
|
||||||
|
hasRoute := false
|
||||||
|
for _, route := range s.routes {
|
||||||
|
hasRoute = strings.HasPrefix(path, route)
|
||||||
|
if hasRoute {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if path == "/" || hasRoute {
|
||||||
|
path = s.Entrypoint
|
||||||
|
}
|
||||||
|
|
||||||
|
path = strings.TrimPrefix(path, "/")
|
||||||
|
|
||||||
|
file, err := s.Filesystem.Open(path)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
http.NotFound(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
http.Error(
|
||||||
|
w,
|
||||||
|
http.StatusText(http.StatusInternalServerError),
|
||||||
|
http.StatusInternalServerError,
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
contentType := mime.TypeByExtension(filepath.Ext(path))
|
||||||
|
w.Header().Set("Content-Type", contentType)
|
||||||
|
|
||||||
|
if strings.HasPrefix(path, "assets/") {
|
||||||
|
w.Header().Set("Cache-Control", "public, max-age=2592000")
|
||||||
|
}
|
||||||
|
|
||||||
|
stat, err := file.Stat()
|
||||||
|
if err == nil && stat.Size() > 0 {
|
||||||
|
w.Header().Set("Content-Length", fmt.Sprintf("%d", stat.Size()))
|
||||||
|
}
|
||||||
|
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
|
||||||
|
io.Copy(w, file)
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@ package rest
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/go-chi/chi/v5"
|
||||||
"github.com/golang-jwt/jwt/v5"
|
"github.com/golang-jwt/jwt/v5"
|
||||||
"github.com/marcopeocchi/yt-dlp-web-ui/server/config"
|
"github.com/marcopeocchi/yt-dlp-web-ui/server/config"
|
||||||
"github.com/marcopeocchi/yt-dlp-web-ui/server/utils"
|
"github.com/marcopeocchi/yt-dlp-web-ui/server/utils"
|
||||||
@@ -69,18 +69,20 @@ type ListRequest struct {
|
|||||||
OrderBy string `json:"orderBy"`
|
OrderBy string `json:"orderBy"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func ListDownloaded(ctx *fiber.Ctx) error {
|
func ListDownloaded(w http.ResponseWriter, r *http.Request) {
|
||||||
root := config.Instance().GetConfig().DownloadPath
|
root := config.Instance().GetConfig().DownloadPath
|
||||||
req := new(ListRequest)
|
req := new(ListRequest)
|
||||||
|
|
||||||
err := ctx.BodyParser(req)
|
err := json.NewDecoder(r.Body).Decode(&req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
files, err := walkDir(filepath.Join(root, req.SubDir))
|
files, err := walkDir(filepath.Join(root, req.SubDir))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.OrderBy == "modtime" {
|
if req.OrderBy == "modtime" {
|
||||||
@@ -89,45 +91,55 @@ func ListDownloaded(ctx *fiber.Ctx) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Status(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
return ctx.JSON(files)
|
err = json.NewEncoder(w).Encode(files)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type DeleteRequest = DirectoryEntry
|
type DeleteRequest = DirectoryEntry
|
||||||
|
|
||||||
func DeleteFile(ctx *fiber.Ctx) error {
|
func DeleteFile(w http.ResponseWriter, r *http.Request) {
|
||||||
req := new(DeleteRequest)
|
req := new(DeleteRequest)
|
||||||
|
|
||||||
err := ctx.BodyParser(req)
|
err := json.NewDecoder(r.Body).Decode(&req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
sum := utils.ShaSumString(req.Path)
|
sum := utils.ShaSumString(req.Path)
|
||||||
if sum != req.SHASum {
|
if sum != req.SHASum {
|
||||||
return errors.New("shasum mismatch")
|
http.Error(w, "shasum mismatch", http.StatusBadRequest)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = os.Remove(req.Path)
|
err = os.Remove(req.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
http.Error(w, "shasum mismatch", http.StatusBadRequest)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Status(fiber.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
return ctx.JSON("ok")
|
json.NewEncoder(w).Encode("ok")
|
||||||
}
|
}
|
||||||
|
|
||||||
func SendFile(ctx *fiber.Ctx) error {
|
func SendFile(w http.ResponseWriter, r *http.Request) {
|
||||||
path := ctx.Params("id")
|
path := chi.URLParam(r, "id")
|
||||||
|
|
||||||
if path == "" {
|
if path == "" {
|
||||||
return errors.New("inexistent path")
|
http.Error(w, "inexistent path", http.StatusBadRequest)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
decoded, err := hex.DecodeString(path)
|
decoded, err := hex.DecodeString(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
decodedStr := string(decoded)
|
decodedStr := string(decoded)
|
||||||
|
|
||||||
root := config.Instance().GetConfig().DownloadPath
|
root := config.Instance().GetConfig().DownloadPath
|
||||||
@@ -138,26 +150,28 @@ func SendFile(ctx *fiber.Ctx) error {
|
|||||||
// "Content-Disposition",
|
// "Content-Disposition",
|
||||||
// "inline; filename="+filepath.Base(decodedStr),
|
// "inline; filename="+filepath.Base(decodedStr),
|
||||||
// )
|
// )
|
||||||
ctx.SendStatus(fiber.StatusOK)
|
|
||||||
return ctx.SendFile(decodedStr)
|
http.ServeFile(w, r, decodedStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ctx.SendStatus(fiber.StatusUnauthorized)
|
w.WriteHeader(http.StatusUnauthorized)
|
||||||
}
|
}
|
||||||
|
|
||||||
type LoginRequest struct {
|
type LoginRequest struct {
|
||||||
Secret string `json:"secret"`
|
Secret string `json:"secret"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func Login(ctx *fiber.Ctx) error {
|
func Login(w http.ResponseWriter, r *http.Request) {
|
||||||
req := new(LoginRequest)
|
req := new(LoginRequest)
|
||||||
err := ctx.BodyParser(req)
|
err := json.NewDecoder(r.Body).Decode(&req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx.SendStatus(fiber.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.Instance().GetConfig().RPCSecret != req.Secret {
|
if config.Instance().GetConfig().RPCSecret != req.Secret {
|
||||||
return ctx.SendStatus(fiber.StatusBadRequest)
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
expiresAt := time.Now().Add(time.Hour * 24 * 30)
|
expiresAt := time.Now().Add(time.Hour * 24 * 30)
|
||||||
@@ -168,30 +182,31 @@ func Login(ctx *fiber.Ctx) error {
|
|||||||
|
|
||||||
tokenString, err := token.SignedString([]byte(os.Getenv("JWT_SECRET")))
|
tokenString, err := token.SignedString([]byte(os.Getenv("JWT_SECRET")))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx.SendStatus(fiber.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Cookie(&fiber.Cookie{
|
cookie := &http.Cookie{
|
||||||
Name: TOKEN_COOKIE_NAME,
|
Name: TOKEN_COOKIE_NAME,
|
||||||
HTTPOnly: true,
|
HttpOnly: true,
|
||||||
Secure: false,
|
Secure: false,
|
||||||
Expires: expiresAt, // 30 days
|
Expires: expiresAt, // 30 days
|
||||||
Value: tokenString,
|
Value: tokenString,
|
||||||
Path: "/",
|
Path: "/",
|
||||||
})
|
}
|
||||||
|
|
||||||
return ctx.SendStatus(fiber.StatusOK)
|
http.SetCookie(w, cookie)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Logout(ctx *fiber.Ctx) error {
|
func Logout(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx.Cookie(&fiber.Cookie{
|
cookie := &http.Cookie{
|
||||||
Name: TOKEN_COOKIE_NAME,
|
Name: TOKEN_COOKIE_NAME,
|
||||||
HTTPOnly: true,
|
HttpOnly: true,
|
||||||
Secure: false,
|
Secure: false,
|
||||||
Expires: time.Now(),
|
Expires: time.Now(),
|
||||||
Value: "",
|
Value: "",
|
||||||
Path: "/",
|
Path: "/",
|
||||||
})
|
}
|
||||||
|
|
||||||
return ctx.SendStatus(fiber.StatusOK)
|
http.SetCookie(w, cookie)
|
||||||
}
|
}
|
||||||
|
|||||||
53
server/rpc/handlers.go
Normal file
53
server/rpc/handlers.go
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
package rpc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
|
)
|
||||||
|
|
||||||
|
var upgrader websocket.Upgrader
|
||||||
|
|
||||||
|
func WebSocket(w http.ResponseWriter, r *http.Request) {
|
||||||
|
c, err := upgrader.Upgrade(w, r, nil)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
// notify client that conn is open and ok
|
||||||
|
c.WriteJSON(struct{ Status string }{Status: "connected"})
|
||||||
|
|
||||||
|
for {
|
||||||
|
mtype, reader, err := c.NextReader()
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
res := newRequest(reader).Call()
|
||||||
|
|
||||||
|
writer, err := c.NextWriter(mtype)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
io.Copy(writer, res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Post(w http.ResponseWriter, r *http.Request) {
|
||||||
|
defer r.Body.Close()
|
||||||
|
|
||||||
|
res := newRequest(r.Body).Call()
|
||||||
|
_, err := io.Copy(w, res)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package server
|
package rpc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@@ -13,7 +13,7 @@ type rpcRequest struct {
|
|||||||
done chan bool
|
done chan bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRPCRequest(r io.Reader) *rpcRequest {
|
func newRequest(r io.Reader) *rpcRequest {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
done := make(chan bool)
|
done := make(chan bool)
|
||||||
return &rpcRequest{r, &buf, done}
|
return &rpcRequest{r, &buf, done}
|
||||||
134
server/server.go
134
server/server.go
@@ -3,7 +3,6 @@ package server
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -13,16 +12,21 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/go-chi/chi/v5"
|
||||||
"github.com/gofiber/fiber/v2/middleware/cors"
|
"github.com/go-chi/chi/v5/middleware"
|
||||||
"github.com/gofiber/fiber/v2/middleware/filesystem"
|
|
||||||
"github.com/gofiber/websocket/v2"
|
|
||||||
"github.com/marcopeocchi/yt-dlp-web-ui/server/internal"
|
"github.com/marcopeocchi/yt-dlp-web-ui/server/internal"
|
||||||
middlewares "github.com/marcopeocchi/yt-dlp-web-ui/server/middleware"
|
middlewares "github.com/marcopeocchi/yt-dlp-web-ui/server/middleware"
|
||||||
"github.com/marcopeocchi/yt-dlp-web-ui/server/rest"
|
"github.com/marcopeocchi/yt-dlp-web-ui/server/rest"
|
||||||
ytdlpRPC "github.com/marcopeocchi/yt-dlp-web-ui/server/rpc"
|
ytdlpRPC "github.com/marcopeocchi/yt-dlp-web-ui/server/rpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type serverConfig struct {
|
||||||
|
frontend fs.FS
|
||||||
|
port int
|
||||||
|
db *internal.MemoryDB
|
||||||
|
mq *internal.MessageQueue
|
||||||
|
}
|
||||||
|
|
||||||
func RunBlocking(port int, frontend fs.FS) {
|
func RunBlocking(port int, frontend fs.FS) {
|
||||||
var db internal.MemoryDB
|
var db internal.MemoryDB
|
||||||
db.Restore()
|
db.Restore()
|
||||||
@@ -30,80 +34,64 @@ func RunBlocking(port int, frontend fs.FS) {
|
|||||||
mq := internal.NewMessageQueue()
|
mq := internal.NewMessageQueue()
|
||||||
go mq.Subscriber()
|
go mq.Subscriber()
|
||||||
|
|
||||||
service := ytdlpRPC.Container(&db, mq)
|
srv := newServer(serverConfig{
|
||||||
rpc.Register(service)
|
frontend: frontend,
|
||||||
|
port: port,
|
||||||
app := fiber.New()
|
db: &db,
|
||||||
|
mq: mq,
|
||||||
app.Use(cors.New())
|
|
||||||
app.Use("/", filesystem.New(filesystem.Config{
|
|
||||||
Root: http.FS(frontend),
|
|
||||||
}))
|
|
||||||
|
|
||||||
// Client side routes
|
|
||||||
app.Get("/settings", func(c *fiber.Ctx) error {
|
|
||||||
return c.Redirect("/")
|
|
||||||
})
|
|
||||||
app.Get("/archive", func(c *fiber.Ctx) error {
|
|
||||||
return c.Redirect("/")
|
|
||||||
})
|
|
||||||
app.Get("/login", func(c *fiber.Ctx) error {
|
|
||||||
return c.Redirect("/")
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// Archive routes
|
|
||||||
archive := app.Group("archive", middlewares.Authenticated)
|
|
||||||
archive.Post("/downloaded", rest.ListDownloaded)
|
|
||||||
archive.Post("/delete", rest.DeleteFile)
|
|
||||||
archive.Get("/d/:id", rest.SendFile)
|
|
||||||
|
|
||||||
// Authentication routes
|
|
||||||
app.Post("/auth/login", rest.Login)
|
|
||||||
app.Get("/auth/logout", rest.Logout)
|
|
||||||
|
|
||||||
// RPC handlers
|
|
||||||
// websocket
|
|
||||||
rpc := app.Group("/rpc", middlewares.Authenticated)
|
|
||||||
|
|
||||||
rpc.Get("/ws", websocket.New(func(c *websocket.Conn) {
|
|
||||||
c.WriteMessage(websocket.TextMessage, []byte(`{
|
|
||||||
"status": "connected"
|
|
||||||
}`))
|
|
||||||
|
|
||||||
for {
|
|
||||||
mtype, reader, err := c.NextReader()
|
|
||||||
if err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
res := NewRPCRequest(reader).Call()
|
|
||||||
|
|
||||||
writer, err := c.NextWriter(mtype)
|
|
||||||
if err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
io.Copy(writer, res)
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
// http-post
|
// http-post
|
||||||
rpc.Post("/http", func(c *fiber.Ctx) error {
|
go gracefulShutdown(srv, &db)
|
||||||
reader := c.Context().RequestBodyStream()
|
|
||||||
writer := c.Response().BodyWriter()
|
|
||||||
|
|
||||||
res := NewRPCRequest(reader).Call()
|
|
||||||
io.Copy(writer, res)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
app.Server().StreamRequestBody = true
|
|
||||||
|
|
||||||
go gracefulShutdown(app, &db)
|
|
||||||
go autoPersist(time.Minute*5, &db)
|
go autoPersist(time.Minute*5, &db)
|
||||||
|
|
||||||
log.Fatal(app.Listen(fmt.Sprintf(":%d", port)))
|
log.Fatal(srv.ListenAndServe())
|
||||||
}
|
}
|
||||||
|
|
||||||
func gracefulShutdown(app *fiber.App, db *internal.MemoryDB) {
|
func newServer(c serverConfig) *http.Server {
|
||||||
|
service := ytdlpRPC.Container(c.db, c.mq)
|
||||||
|
rpc.Register(service)
|
||||||
|
|
||||||
|
r := chi.NewRouter()
|
||||||
|
|
||||||
|
r.Use(middlewares.CORS)
|
||||||
|
r.Use(middleware.Logger)
|
||||||
|
|
||||||
|
sh := middlewares.NewSpaHandler("index.html", c.frontend)
|
||||||
|
sh.AddClientRoute("/settings")
|
||||||
|
sh.AddClientRoute("/archive")
|
||||||
|
sh.AddClientRoute("/login")
|
||||||
|
|
||||||
|
r.Get("/*", sh.Handler())
|
||||||
|
|
||||||
|
// Archive routes
|
||||||
|
r.Route("/archive", func(r chi.Router) {
|
||||||
|
r.Use(middlewares.Authenticated)
|
||||||
|
r.Post("/downloaded", rest.ListDownloaded)
|
||||||
|
r.Post("/delete", rest.DeleteFile)
|
||||||
|
r.Get("/d/{id}", rest.SendFile)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Authentication routes
|
||||||
|
r.Route("/auth", func(r chi.Router) {
|
||||||
|
r.Post("/login", rest.Login)
|
||||||
|
r.Get("/logout", rest.Logout)
|
||||||
|
})
|
||||||
|
|
||||||
|
// RPC handlers
|
||||||
|
r.Route("/rpc", func(r chi.Router) {
|
||||||
|
r.Use(middlewares.Authenticated)
|
||||||
|
r.Get("/ws", ytdlpRPC.WebSocket)
|
||||||
|
r.Post("/http", ytdlpRPC.Post)
|
||||||
|
})
|
||||||
|
|
||||||
|
return &http.Server{
|
||||||
|
Addr: fmt.Sprintf(":%d", c.port),
|
||||||
|
Handler: r,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func gracefulShutdown(srv *http.Server, db *internal.MemoryDB) {
|
||||||
ctx, stop := signal.NotifyContext(context.Background(),
|
ctx, stop := signal.NotifyContext(context.Background(),
|
||||||
os.Interrupt,
|
os.Interrupt,
|
||||||
syscall.SIGTERM,
|
syscall.SIGTERM,
|
||||||
@@ -117,7 +105,7 @@ func gracefulShutdown(app *fiber.App, db *internal.MemoryDB) {
|
|||||||
defer func() {
|
defer func() {
|
||||||
db.Persist()
|
db.Persist()
|
||||||
stop()
|
stop()
|
||||||
app.ShutdownWithTimeout(time.Second * 5)
|
srv.Shutdown(context.TODO())
|
||||||
}()
|
}()
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user