Merge branch 'master' into 230-torrents-category

This commit is contained in:
cocool97
2024-03-24 14:28:31 +01:00
committed by GitHub
64 changed files with 1437 additions and 508 deletions

View File

@@ -7,6 +7,7 @@ import (
"os"
"path/filepath"
"runtime"
"strconv"
"strings"
"time"
@@ -25,12 +26,12 @@ import (
)
type args struct {
Port string `arg:"-p" help:"web server port, default 8090"`
Port string `arg:"-p" help:"web server port (default 8090)"`
Ssl bool `help:"enables https"`
SslPort string `help:"web server ssl port, If not set, will be set to default 8091 or taken from db(if stored previously). Accepted if --ssl enabled."`
SslCert string `help:"path to ssl cert file. If not set, will be taken from db(if stored previously) or default self-signed certificate/key will be generated. Accepted if --ssl enabled."`
SslKey string `help:"path to ssl key file. If not set, will be taken from db(if stored previously) or default self-signed certificate/key will be generated. Accepted if --ssl enabled."`
Path string `arg:"-d" help:"database dir path"`
Path string `arg:"-d" help:"database and config dir path"`
LogPath string `arg:"-l" help:"server log file path"`
WebLogPath string `arg:"-w" help:"web access log file path"`
RDB bool `arg:"-r" help:"start in read-only DB mode"`
@@ -38,10 +39,11 @@ type args struct {
DontKill bool `arg:"-k" help:"don't kill server on signal"`
UI bool `arg:"-u" help:"open torrserver page in browser"`
TorrentsDir string `arg:"-t" help:"autoload torrents from dir"`
TorrentAddr string `help:"Torrent client address, default :32000"`
TorrentAddr string `help:"Torrent client address, like 127.0.0.1:1337 (default :PeersListenPort)"`
PubIPv4 string `arg:"-4" help:"set public IPv4 addr"`
PubIPv6 string `arg:"-6" help:"set public IPv6 addr"`
SearchWA bool `arg:"-s" help:"search without auth"`
MaxSize string `arg:"-m" help:"max allowed stream size (in Bytes)"`
}
func (args) Version() string {
@@ -104,6 +106,13 @@ func main() {
go watchTDir(params.TorrentsDir)
}
if params.MaxSize != "" {
maxSize, err := strconv.ParseInt(params.MaxSize, 10, 64)
if err == nil {
settings.MaxSize = maxSize
}
}
server.Start(params.Port, params.SslPort, params.SslCert, params.SslKey, params.Ssl, params.RDB, params.SearchWA)
log.TLogln(server.WaitServer())
log.Close()

View File

@@ -65,7 +65,7 @@ func Start() {
FriendlyName: getDefaultFriendlyName(),
NoTranscode: true,
NoProbe: true,
StallEventSubscribe: true,
StallEventSubscribe: false,
Icons: []dms.Icon{
{
Width: 48,

View File

@@ -62,7 +62,7 @@ const docTemplate = `{
"parameters": [
{
"type": "string",
"description": "Test file size",
"description": "Test file size (in MB)",
"name": "size",
"in": "path",
"required": true
@@ -98,7 +98,7 @@ const docTemplate = `{
}
}
},
"/ffp": {
"/ffp/{hash}/{id}": {
"get": {
"description": "Gather informations using ffprobe.",
"produces": [
@@ -113,14 +113,14 @@ const docTemplate = `{
"type": "string",
"description": "Torrent hash",
"name": "hash",
"in": "query",
"in": "path",
"required": true
},
{
"type": "string",
"description": "File index in torrent",
"name": "id",
"in": "query",
"in": "path",
"required": true
}
],
@@ -148,32 +148,6 @@ const docTemplate = `{
}
}
},
"/msx": {
"get": {
"description": "Multi usage endpoint.",
"produces": [
"application/json"
],
"tags": [
"MSX"
],
"summary": "Multi usage endpoint",
"parameters": [
{
"type": "string",
"description": "Magnet/hash/link to torrent",
"name": "link",
"in": "query",
"required": true
}
],
"responses": {
"200": {
"description": "Data returned according to query"
}
}
}
},
"/msx/imdb": {
"get": {
"description": "Get MSX IMDB informations.",
@@ -191,7 +165,7 @@ const docTemplate = `{
}
}
},
"/msx/imdb/:id": {
"/msx/imdb/{id}": {
"get": {
"description": "Get MSX IMDB informations.",
"produces": [
@@ -217,7 +191,33 @@ const docTemplate = `{
}
}
},
"/play": {
"/msx/{pth}": {
"get": {
"description": "Multi usage endpoint.",
"produces": [
"application/json"
],
"tags": [
"MSX"
],
"summary": "Multi usage endpoint",
"parameters": [
{
"type": "string",
"description": "Route MSX pages",
"name": "link",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "Data returned according to path"
}
}
}
},
"/play/{hash}/{id}": {
"get": {
"description": "Play given torrent referenced by hash.",
"produces": [
@@ -232,21 +232,15 @@ const docTemplate = `{
"type": "string",
"description": "Torrent hash",
"name": "hash",
"in": "query",
"in": "path",
"required": true
},
{
"type": "string",
"description": "File index in torrent",
"name": "id",
"in": "query",
"in": "path",
"required": true
},
{
"type": "boolean",
"description": "Not authenticated",
"name": "not_auth",
"in": "query"
}
],
"responses": {
@@ -458,7 +452,7 @@ const docTemplate = `{
},
{
"type": "string",
"description": "Get m3u from last play",
"description": "Get M3U from last played file",
"name": "fromlast",
"in": "query"
},
@@ -475,17 +469,10 @@ const docTemplate = `{
"in": "query",
"required": true
},
{
"type": "string",
"description": "File index in torrent",
"name": "poster",
"in": "query",
"required": true
},
{
"type": "string",
"description": "Set poster link of torrent",
"name": "not_auth",
"name": "poster",
"in": "query",
"required": true
}

View File

@@ -55,7 +55,7 @@
"parameters": [
{
"type": "string",
"description": "Test file size",
"description": "Test file size (in MB)",
"name": "size",
"in": "path",
"required": true
@@ -91,7 +91,7 @@
}
}
},
"/ffp": {
"/ffp/{hash}/{id}": {
"get": {
"description": "Gather informations using ffprobe.",
"produces": [
@@ -106,14 +106,14 @@
"type": "string",
"description": "Torrent hash",
"name": "hash",
"in": "query",
"in": "path",
"required": true
},
{
"type": "string",
"description": "File index in torrent",
"name": "id",
"in": "query",
"in": "path",
"required": true
}
],
@@ -141,32 +141,6 @@
}
}
},
"/msx": {
"get": {
"description": "Multi usage endpoint.",
"produces": [
"application/json"
],
"tags": [
"MSX"
],
"summary": "Multi usage endpoint",
"parameters": [
{
"type": "string",
"description": "Magnet/hash/link to torrent",
"name": "link",
"in": "query",
"required": true
}
],
"responses": {
"200": {
"description": "Data returned according to query"
}
}
}
},
"/msx/imdb": {
"get": {
"description": "Get MSX IMDB informations.",
@@ -184,7 +158,7 @@
}
}
},
"/msx/imdb/:id": {
"/msx/imdb/{id}": {
"get": {
"description": "Get MSX IMDB informations.",
"produces": [
@@ -210,7 +184,33 @@
}
}
},
"/play": {
"/msx/{pth}": {
"get": {
"description": "Multi usage endpoint.",
"produces": [
"application/json"
],
"tags": [
"MSX"
],
"summary": "Multi usage endpoint",
"parameters": [
{
"type": "string",
"description": "Route MSX pages",
"name": "link",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "Data returned according to path"
}
}
}
},
"/play/{hash}/{id}": {
"get": {
"description": "Play given torrent referenced by hash.",
"produces": [
@@ -225,21 +225,15 @@
"type": "string",
"description": "Torrent hash",
"name": "hash",
"in": "query",
"in": "path",
"required": true
},
{
"type": "string",
"description": "File index in torrent",
"name": "id",
"in": "query",
"in": "path",
"required": true
},
{
"type": "boolean",
"description": "Not authenticated",
"name": "not_auth",
"in": "query"
}
],
"responses": {
@@ -451,7 +445,7 @@
},
{
"type": "string",
"description": "Get m3u from last play",
"description": "Get M3U from last played file",
"name": "fromlast",
"in": "query"
},
@@ -468,17 +462,10 @@
"in": "query",
"required": true
},
{
"type": "string",
"description": "File index in torrent",
"name": "poster",
"in": "query",
"required": true
},
{
"type": "string",
"description": "Set poster link of torrent",
"name": "not_auth",
"name": "poster",
"in": "query",
"required": true
}

View File

@@ -332,7 +332,7 @@ paths:
get:
description: Download the test file of given size (for speed testing purpose).
parameters:
- description: Test file size
- description: Test file size (in MB)
in: path
name: size
required: true
@@ -360,17 +360,17 @@ paths:
summary: Tests server status
tags:
- API
/ffp:
/ffp/{hash}/{id}:
get:
description: Gather informations using ffprobe.
parameters:
- description: Torrent hash
in: query
in: path
name: hash
required: true
type: string
- description: File index in torrent
in: query
in: path
name: id
required: true
type: string
@@ -393,12 +393,12 @@ paths:
summary: Get HTML of magnet links
tags:
- Pages
/msx:
/msx/{pth}:
get:
description: Multi usage endpoint.
parameters:
- description: Magnet/hash/link to torrent
in: query
- description: Route MSX pages
in: path
name: link
required: true
type: string
@@ -406,7 +406,7 @@ paths:
- application/json
responses:
"200":
description: Data returned according to query
description: Data returned according to path
summary: Multi usage endpoint
tags:
- MSX
@@ -421,7 +421,7 @@ paths:
summary: Get MSX IMDB informations
tags:
- MSX
/msx/imdb/:id:
/msx/imdb/{id}:
get:
description: Get MSX IMDB informations.
parameters:
@@ -438,24 +438,20 @@ paths:
summary: Get MSX IMDB informations
tags:
- MSX
/play:
/play/{hash}/{id}:
get:
description: Play given torrent referenced by hash.
parameters:
- description: Torrent hash
in: query
in: path
name: hash
required: true
type: string
- description: File index in torrent
in: query
in: path
name: id
required: true
type: string
- description: Not authenticated
in: query
name: not_auth
type: boolean
produces:
- application/octet-stream
responses:
@@ -592,7 +588,7 @@ paths:
in: query
name: m3u
type: string
- description: Get m3u from last play
- description: Get M3U from last played file
in: query
name: fromlast
type: string
@@ -605,14 +601,9 @@ paths:
name: title
required: true
type: string
- description: File index in torrent
in: query
name: poster
required: true
type: string
- description: Set poster link of torrent
in: query
name: not_auth
name: poster
required: true
type: string
produces:

View File

@@ -2,51 +2,52 @@ module server
go 1.20
replace github.com/anacrolix/torrent v1.53.1 => github.com/tsynik/torrent v1.2.11
replace github.com/anacrolix/torrent v1.54.1 => github.com/tsynik/torrent v1.2.16
require (
github.com/agnivade/levenshtein v1.1.1
github.com/alexflint/go-arg v1.4.3
github.com/anacrolix/dms v1.6.0
github.com/anacrolix/log v0.14.5
github.com/anacrolix/missinggo v1.3.0
github.com/anacrolix/log v0.15.0
github.com/anacrolix/missinggo/v2 v2.7.3
github.com/anacrolix/publicip v0.3.0
github.com/anacrolix/torrent v1.53.1
github.com/gin-contrib/cors v1.4.0
github.com/anacrolix/torrent v1.54.1
github.com/gin-contrib/cors v1.5.0
github.com/gin-contrib/location v0.0.2
github.com/gin-gonic/gin v1.9.1
github.com/kljensen/snowball v0.8.0
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8
github.com/kljensen/snowball v0.9.0
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c
github.com/pkg/errors v0.9.1
github.com/swaggo/files v1.0.1
github.com/swaggo/gin-swagger v1.6.0
github.com/swaggo/swag v1.16.2
go.etcd.io/bbolt v1.3.8
golang.org/x/image v0.14.0
golang.org/x/time v0.4.0
github.com/swaggo/swag v1.16.3
go.etcd.io/bbolt v1.3.9
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225
golang.org/x/image v0.15.0
golang.org/x/time v0.5.0
gopkg.in/vansante/go-ffprobe.v2 v2.1.1
)
require (
github.com/KyleBanks/depth v1.2.1 // indirect
github.com/RoaringBitmap/roaring v1.6.0 // indirect
github.com/RoaringBitmap/roaring v1.9.0 // indirect
github.com/alecthomas/atomic v0.1.0-alpha2 // indirect
github.com/alexflint/go-scalar v1.2.0 // indirect
github.com/anacrolix/chansync v0.3.0 // indirect
github.com/anacrolix/dht/v2 v2.21.0 // indirect
github.com/anacrolix/chansync v0.4.0 // indirect
github.com/anacrolix/dht/v2 v2.21.1 // indirect
github.com/anacrolix/ffprobe v1.1.0 // indirect
github.com/anacrolix/generics v0.0.0-20230911070922-5dd7545c6b13 // indirect
github.com/anacrolix/generics v0.0.1 // indirect
github.com/anacrolix/missinggo v1.3.0 // indirect
github.com/anacrolix/missinggo/perf v1.0.0 // indirect
github.com/anacrolix/missinggo/v2 v2.7.3 // indirect
github.com/anacrolix/multiless v0.3.1-0.20221221005021-2d12701f83f7 // indirect
github.com/anacrolix/stm v0.5.0 // indirect
github.com/anacrolix/sync v0.5.1 // indirect
github.com/anacrolix/upnp v0.1.3 // indirect
github.com/anacrolix/upnp v0.1.4 // indirect
github.com/anacrolix/utp v0.2.0 // indirect
github.com/benbjohnson/immutable v0.4.3 // indirect
github.com/bits-and-blooms/bitset v1.11.0 // indirect
github.com/bits-and-blooms/bitset v1.13.0 // indirect
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 // indirect
github.com/bytedance/sonic v1.10.2 // indirect
github.com/bytedance/sonic v1.11.1 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
github.com/chenzhuoyu/iasm v0.9.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
@@ -55,38 +56,38 @@ require (
github.com/frankban/quicktest v1.14.6 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-openapi/jsonpointer v0.20.0 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect
github.com/go-openapi/spec v0.20.9 // indirect
github.com/go-openapi/swag v0.22.4 // indirect
github.com/go-openapi/jsonpointer v0.20.2 // indirect
github.com/go-openapi/jsonreference v0.20.4 // indirect
github.com/go-openapi/spec v0.20.14 // indirect
github.com/go-openapi/swag v0.22.9 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.16.0 // indirect
github.com/go-playground/validator/v10 v10.18.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/google/btree v1.1.2 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/huandu/xstrings v1.4.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
github.com/leodido/go-urn v1.2.4 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mschoch/smat v0.2.0 // indirect
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/pelletier/go-toml/v2 v2.1.1 // indirect
github.com/rs/dnscache v0.0.0-20230804202142-fc85eb664529 // indirect
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.11 // indirect
golang.org/x/arch v0.6.0 // indirect
golang.org/x/crypto v0.15.0 // indirect
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect
golang.org/x/net v0.18.0 // indirect
golang.org/x/sync v0.5.0 // indirect
golang.org/x/sys v0.14.0 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
golang.org/x/arch v0.7.0 // indirect
golang.org/x/crypto v0.19.0 // indirect
golang.org/x/net v0.21.0 // indirect
golang.org/x/sync v0.6.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.15.0 // indirect
google.golang.org/protobuf v1.31.0 // indirect
golang.org/x/tools v0.18.0 // indirect
google.golang.org/protobuf v1.32.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

View File

@@ -8,8 +8,8 @@ github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6Xge
github.com/RoaringBitmap/roaring v0.4.7/go.mod h1:8khRDP4HmeXns4xIj9oGrKSz7XTQiJx2zgh7AcNke4w=
github.com/RoaringBitmap/roaring v0.4.17/go.mod h1:D3qVegWTmfCaX4Bl5CrBE9hfrSrrXIr8KVNvRsDi1NI=
github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo=
github.com/RoaringBitmap/roaring v1.6.0 h1:dc7kRiroETgJcHhWX6BerXkZz2b3JgLGg9nTURJL/og=
github.com/RoaringBitmap/roaring v1.6.0/go.mod h1:plvDsJQpxOC5bw8LRteu/MLWHsHez/3y6cubLI4/1yE=
github.com/RoaringBitmap/roaring v1.9.0 h1:lwKhr90/j0jVXJyh5X+vQN1VVn77rQFfYnh6RDRGCcE=
github.com/RoaringBitmap/roaring v1.9.0/go.mod h1:6AXUsoIEzDTFFQCe1RbGA6uFONMhvejWj5rqITANK90=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8=
@@ -25,10 +25,10 @@ github.com/alexflint/go-arg v1.4.3/go.mod h1:3PZ/wp/8HuqRZMUUgu7I+e1qcpUbvmS258m
github.com/alexflint/go-scalar v1.1.0/go.mod h1:LoFvNMqS1CPrMVltza4LvnGKhaSpc3oyLEBUZVhhS2o=
github.com/alexflint/go-scalar v1.2.0 h1:WR7JPKkeNpnYIOfHRa7ivM21aWAdHD0gEWHCx+WQBRw=
github.com/alexflint/go-scalar v1.2.0/go.mod h1:LoFvNMqS1CPrMVltza4LvnGKhaSpc3oyLEBUZVhhS2o=
github.com/anacrolix/chansync v0.3.0 h1:lRu9tbeuw3wl+PhMu/r+JJCRu5ArFXIluOgdF0ao6/U=
github.com/anacrolix/chansync v0.3.0/go.mod h1:DZsatdsdXxD0WiwcGl0nJVwyjCKMDv+knl1q2iBjA2k=
github.com/anacrolix/dht/v2 v2.21.0 h1:8nzI+faaynY9jOKmVgdmBZVrTo8B7ZE/LKEgN3Vl/Bs=
github.com/anacrolix/dht/v2 v2.21.0/go.mod h1:SDGC+sEs1pnO2sJGYuhvIis7T8749dDHNfcjtdH4e3g=
github.com/anacrolix/chansync v0.4.0 h1:Md0HM7zYCAO4KwNwgcIRgxNsMxiRuk7D1Ha0Uo+2y60=
github.com/anacrolix/chansync v0.4.0/go.mod h1:DZsatdsdXxD0WiwcGl0nJVwyjCKMDv+knl1q2iBjA2k=
github.com/anacrolix/dht/v2 v2.21.1 h1:s1rKkfLLcmBHKv4v/mtMkIeHIEptzEFiB6xVu54+5/o=
github.com/anacrolix/dht/v2 v2.21.1/go.mod h1:SDGC+sEs1pnO2sJGYuhvIis7T8749dDHNfcjtdH4e3g=
github.com/anacrolix/dms v1.6.0 h1:v2g1Y+Fc/ICSEc+7M6B92oFcfcqa5LXYPhE4Hcm5tVA=
github.com/anacrolix/dms v1.6.0/go.mod h1:5fAMpBcPFG4WQFh91zhf2E7/KYZ3/WmmRAf/WMoL0Q0=
github.com/anacrolix/envpprof v0.0.0-20180404065416-323002cec2fa/go.mod h1:KgHhUaQMc8cC0+cEflSgCFNFbKwi5h54gqtVn8yhP7c=
@@ -38,14 +38,14 @@ github.com/anacrolix/ffprobe v1.0.0/go.mod h1:BIw+Bjol6CWjm/CRWrVLk2Vy+UYlkgmBZ0
github.com/anacrolix/ffprobe v1.1.0 h1:eKBudnERW9zRJ0+ge6FzkQ0pWLyq142+FJrwRwSRMT4=
github.com/anacrolix/ffprobe v1.1.0/go.mod h1:MXe+zG/RRa5OdIf5+VYYfS/CfsSqOH7RrvGIqJBzqhI=
github.com/anacrolix/generics v0.0.0-20230113004304-d6428d516633/go.mod h1:ff2rHB/joTV03aMSSn/AZNnaIpUw0h3njetGsaXcMy8=
github.com/anacrolix/generics v0.0.0-20230911070922-5dd7545c6b13 h1:qwOprPTDMM3BASJRf84mmZnTXRsPGGJ8xoHKQS7m3so=
github.com/anacrolix/generics v0.0.0-20230911070922-5dd7545c6b13/go.mod h1:ff2rHB/joTV03aMSSn/AZNnaIpUw0h3njetGsaXcMy8=
github.com/anacrolix/generics v0.0.1 h1:4WVhK6iLb3UAAAQP6I3uYlMOHcp9FqJC9j4n81Wv9Ks=
github.com/anacrolix/generics v0.0.1/go.mod h1:ff2rHB/joTV03aMSSn/AZNnaIpUw0h3njetGsaXcMy8=
github.com/anacrolix/log v0.3.0/go.mod h1:lWvLTqzAnCWPJA08T2HCstZi0L1y2Wyvm3FJgwU9jwU=
github.com/anacrolix/log v0.6.0/go.mod h1:lWvLTqzAnCWPJA08T2HCstZi0L1y2Wyvm3FJgwU9jwU=
github.com/anacrolix/log v0.13.1/go.mod h1:D4+CvN8SnruK6zIFS/xPoRJmtvtnxs+CSfDQ+BFxZ68=
github.com/anacrolix/log v0.14.2/go.mod h1:1OmJESOtxQGNMlUO5rcv96Vpp9mfMqXXbe2RdinFLdY=
github.com/anacrolix/log v0.14.5 h1:OkMjBquVSRb742LkecSGDGaGpNoSrw4syRIm0eRdmrg=
github.com/anacrolix/log v0.14.5/go.mod h1:1OmJESOtxQGNMlUO5rcv96Vpp9mfMqXXbe2RdinFLdY=
github.com/anacrolix/log v0.15.0 h1:QIhbW5NDUL6P1Aml+ZfdaXJ+QFAnrO0K1EpFYs/nh9M=
github.com/anacrolix/log v0.15.0/go.mod h1:m0poRtlr41mriZlXBQ9SOVZ8yZBkLjOkDhd5Li5pITA=
github.com/anacrolix/missinggo v1.1.0/go.mod h1:MBJu3Sk/k3ZfGYcS7z18gwfu72Ey/xopPFJJbTi5yIo=
github.com/anacrolix/missinggo v1.1.2-0.20190815015349-b888af804467/go.mod h1:MBJu3Sk/k3ZfGYcS7z18gwfu72Ey/xopPFJJbTi5yIo=
github.com/anacrolix/missinggo v1.2.1/go.mod h1:J5cMhif8jPmFoC3+Uvob3OXXNIhOUikzMt+uUjeM21Y=
@@ -70,8 +70,8 @@ github.com/anacrolix/sync v0.5.1/go.mod h1:BbecHL6jDSExojhNtgTFSBcdGerzNc64tz3DC
github.com/anacrolix/tagflag v0.0.0-20180109131632-2146c8d41bf0/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pmhJXOKKCHw=
github.com/anacrolix/tagflag v1.0.0/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pmhJXOKKCHw=
github.com/anacrolix/tagflag v1.1.0/go.mod h1:Scxs9CV10NQatSmbyjqmqmeQNwGzlNe0CMUMIxqHIG8=
github.com/anacrolix/upnp v0.1.3 h1:NlYEhE75adz2npEJKjbqyqnyW9qU4STookvSNXBJ5ao=
github.com/anacrolix/upnp v0.1.3/go.mod h1:Qyhbqo69gwNWvEk1xNTXsS5j7hMHef9hdr984+9fIic=
github.com/anacrolix/upnp v0.1.4 h1:+2t2KA6QOhm/49zeNyeVwDu1ZYS9dB9wfxyVvh/wk7U=
github.com/anacrolix/upnp v0.1.4/go.mod h1:Qyhbqo69gwNWvEk1xNTXsS5j7hMHef9hdr984+9fIic=
github.com/anacrolix/utp v0.2.0 h1:65Cdmr6q9WSw2KsM+rtJFu7rqDzLl2bdysf4KlNPcFI=
github.com/anacrolix/utp v0.2.0/go.mod h1:HGk4GYQw1O/3T1+yhqT/F6EcBd+AAwlo9dYErNy7mj8=
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
@@ -82,17 +82,17 @@ github.com/benbjohnson/immutable v0.4.3/go.mod h1:qJIKKSmdqz1tVzNtst1DZzvaqOU1on
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
github.com/bits-and-blooms/bitset v1.11.0 h1:RMyy2mBBShArUAhfVRZJ2xyBO58KCBCtZFShw3umo6k=
github.com/bits-and-blooms/bitset v1.11.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/bits-and-blooms/bitset v1.12.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE=
github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/bradfitz/iter v0.0.0-20140124041915-454541ec3da2/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo=
github.com/bradfitz/iter v0.0.0-20190303215204-33e6a9893b0c/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo=
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 h1:GKTyiRCL6zVf5wWaqKnf+7Qs6GbEPfd4iMOitWzXJx8=
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8/go.mod h1:spo1JLcs67NmW1aVLEgtA8Yy1elc+X8y5SRW1sFW4Og=
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=
github.com/bytedance/sonic v1.10.2 h1:GQebETVBxYB7JGWJtLBi07OVzWwt+8dWA00gEVW2ZFE=
github.com/bytedance/sonic v1.10.2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
github.com/bytedance/sonic v1.11.1 h1:JC0+6c9FoWYYxakaoa+c5QTtJeiSZNeByOBhXtAFSn4=
github.com/bytedance/sonic v1.11.1/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
@@ -122,14 +122,14 @@ github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7z
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
github.com/gin-contrib/cors v1.4.0 h1:oJ6gwtUl3lqV0WEIwM/LxPF1QZ5qe2lGWdY2+bz7y0g=
github.com/gin-contrib/cors v1.4.0/go.mod h1:bs9pNM0x/UsmHPBWT2xZz9ROh8xYjYkiURUfmBoMlcs=
github.com/gin-contrib/cors v1.5.0 h1:DgGKV7DDoOn36DFkNtbHrjoRiT5ExCe+PC9/xp7aKvk=
github.com/gin-contrib/cors v1.5.0/go.mod h1:TvU7MAZ3EwrPLI2ztzTt3tqgvBCq+wn8WpZmfADjupI=
github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4=
github.com/gin-contrib/location v0.0.2 h1:QZKh1+K/LLR4KG/61eIO3b7MLuKi8tytQhV6texLgP4=
github.com/gin-contrib/location v0.0.2/go.mod h1:NGoidiRlf0BlA/VKSVp+g3cuSMeTmip/63PhEjRhUAc=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
@@ -142,36 +142,25 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ=
github.com/go-openapi/jsonpointer v0.20.0/go.mod h1:6PGzBjjIIumbLYysB73Klnms1mwnU4G3YHOECG3CedA=
github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo=
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
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/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU=
github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q=
github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs=
github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU=
github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4=
github.com/go-openapi/spec v0.20.14 h1:7CBlRnw+mtjFGlPDRZmAMnq35cRzI91xj03HVyUi/Do=
github.com/go-openapi/spec v0.20.14/go.mod h1:8EOhTpBoFiask8rrgwbLC3zmJfz4zsCUueRuPM6GNkw=
github.com/go-openapi/swag v0.22.9 h1:XX2DssF+mQKM2DHsbgZK74y/zj4mo9I99+89xUmuZCE=
github.com/go-openapi/swag v0.22.9/go.mod h1:3/OXnFfnMAwBD099SwYRk7GD3xOrr1iL7d/XNLXVVwE=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
github.com/go-playground/validator/v10 v10.16.0 h1:x+plE831WK4vaKHO/jpgUGsvLKIqRRkz6M78GuJAfGE=
github.com/go-playground/validator/v10 v10.16.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
github.com/go-playground/validator/v10 v10.18.0 h1:BvolUXjp4zuvkZ5YN5t7ebzbhlUtPsPm2S9NAZ5nl9U=
github.com/go-playground/validator/v10 v10.18.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
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/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
@@ -189,7 +178,6 @@ github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:x
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180124185431-e89373fe6b4a/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
@@ -200,8 +188,9 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
@@ -227,31 +216,25 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc=
github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/kljensen/snowball v0.8.0 h1:WU4cExxK6sNW33AiGdbn4e8RvloHrhkAssu2mVJ11kg=
github.com/kljensen/snowball v0.8.0/go.mod h1:OGo5gFWjaeXqCu4iIrMl5OYip9XUJHGOU5eSkPjVg2A=
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/kljensen/snowball v0.9.0 h1:OpXkQBcic6vcPG+dChOGLIA/GNuVg47tbbIJ2s7Keas=
github.com/kljensen/snowball v0.9.0/go.mod h1:OGo5gFWjaeXqCu4iIrMl5OYip9XUJHGOU5eSkPjVg2A=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
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/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
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/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
@@ -267,18 +250,16 @@ github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM=
github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI=
github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -305,6 +286,7 @@ github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqn
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rs/dnscache v0.0.0-20230804202142-fc85eb664529 h1:18kd+8ZUlt/ARXhljq+14TwAoKa61q6dX8jtwOf6DH8=
github.com/rs/dnscache v0.0.0-20230804202142-fc85eb664529/go.mod h1:qe5TWALJ8/a1Lqznoc5BDHpYX/8HU60Hm2AwRmqzxqA=
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46 h1:GHRpF1pTW19a8tTFrMLUcfWwyC0pnifVo2ClaLq+hP8=
@@ -323,57 +305,53 @@ github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.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.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE=
github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg=
github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M=
github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo=
github.com/swaggo/swag v1.16.2 h1:28Pp+8DkQoV+HLzLx8RGJZXNGKbFqnuvSbAAtoxiY04=
github.com/swaggo/swag v1.16.2/go.mod h1:6YzXnDcpr0767iOejs318CwYkCQqyGer6BizOg03f+E=
github.com/swaggo/swag v1.16.3 h1:PnCYjPCah8FK4I26l2F/KQ4yz3sILcVUN3cTlBFA9Pg=
github.com/swaggo/swag v1.16.3/go.mod h1:DImHIuOFXKpMFAQjcC7FG4m3Dg4+QuUgUzJmKjI/gRk=
github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
github.com/tsynik/torrent v1.2.11 h1:wPJfxhO/ri10T1Xfi4X8DftwOF3A8geZ4cRQWKxnC2s=
github.com/tsynik/torrent v1.2.11/go.mod h1:AjuETm1Xae+Vk31UrvrSrb29bBunwMKGZLXK6T+AgPo=
github.com/tsynik/torrent v1.2.16 h1:jEXIkdPKIOerO+8b/12wTvEoLnjGFcHX7dMitTmrWH0=
github.com/tsynik/torrent v1.2.16/go.mod h1:c/K0Twt8E0qXJj02tl5FmjhGXSl0XzbFYrzkXTGqU+w=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/willf/bitset v1.1.9/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA=
go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI=
go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE=
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.6.0 h1:S0JTfE48HbRj80+4tbvZDYsJ3tGv6BUU3XxyZ7CirAc=
golang.org/x/arch v0.6.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc=
golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
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-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20220428152302-39d4317da171/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ=
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE=
golang.org/x/image v0.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4=
golang.org/x/image v0.14.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ=
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8=
golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -381,6 +359,7 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -397,8 +376,8 @@ golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20220524220425-1d687d428aca/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -409,8 +388,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/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.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -427,17 +406,15 @@ golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/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-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/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.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
@@ -449,8 +426,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY=
golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -460,8 +437,8 @@ golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8=
golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk=
golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -480,16 +457,13 @@ google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
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-20190902080502-41f04d3bba15/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/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
@@ -500,10 +474,7 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
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-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@@ -45,7 +45,7 @@ func Start(port, sslport, sslCert, sslKey string, sslEnabled, roSets, searchWA b
l.Close()
}
if err != nil {
log.TLogln("Port", sslport, "already in use! Please set different port for HTTPS. Abort")
log.TLogln("Port", sslport, "already in use! Please set different ssl port for HTTPS. Abort")
os.Exit(1)
}
}
@@ -59,7 +59,7 @@ func Start(port, sslport, sslCert, sslKey string, sslEnabled, roSets, searchWA b
l.Close()
}
if err != nil {
log.TLogln("Port", port, "already in use! Please set different sslport for HTTP. Abort")
log.TLogln("Port", port, "already in use! Please set different port for HTTP. Abort")
os.Exit(1)
}
// remove old disk caches

View File

@@ -15,7 +15,7 @@ type TDB struct {
db *bolt.DB
}
func NewTDB() *TDB {
func NewTDB() TorrServerDB {
db, err := bolt.Open(filepath.Join(Path, "config.db"), 0o666, &bolt.Options{Timeout: 5 * time.Second})
if err != nil {
log.TLogln(err)
@@ -68,10 +68,6 @@ func (v *TDB) Get(xpath, name string) []byte {
}
func (v *TDB) Set(xpath, name string, value []byte) {
if ReadOnly {
return
}
spath := strings.Split(xpath, "/")
if len(spath) == 0 {
return
@@ -139,10 +135,6 @@ func (v *TDB) List(xpath string) []string {
}
func (v *TDB) Rem(xpath, name string) {
if ReadOnly {
return
}
spath := strings.Split(xpath, "/")
if len(spath) == 0 {
return

View File

@@ -0,0 +1,70 @@
package settings
import "server/log"
type DBReadCache struct {
db TorrServerDB
listCache map[string][]string
dataCache map[[2]string][]byte
}
func NewDBReadCache(db TorrServerDB) TorrServerDB {
cdb := &DBReadCache{
db: db,
listCache: map[string][]string{},
dataCache: map[[2]string][]byte{},
}
return cdb
}
func (v *DBReadCache) CloseDB() {
v.db.CloseDB()
v.db = nil
v.listCache = nil
v.dataCache = nil
}
func (v *DBReadCache) Get(xPath, name string) []byte {
cacheKey := v.makeDataCacheKey(xPath, name)
if data, ok := v.dataCache[cacheKey]; ok {
return data
}
data := v.db.Get(xPath, name)
v.dataCache[cacheKey] = data
return data
}
func (v *DBReadCache) Set(xPath, name string, value []byte) {
if ReadOnly {
log.TLogln("DB.Set: Read-only DB mode!", name)
return
}
cacheKey := v.makeDataCacheKey(xPath, name)
v.dataCache[cacheKey] = value
delete(v.listCache, xPath)
v.db.Set(xPath, name, value)
}
func (v *DBReadCache) List(xPath string) []string {
if names, ok := v.listCache[xPath]; ok {
return names
}
names := v.db.List(xPath)
v.listCache[xPath] = names
return names
}
func (v *DBReadCache) Rem(xPath, name string) {
if ReadOnly {
log.TLogln("DB.Rem: Read-only DB mode!", name)
return
}
cacheKey := v.makeDataCacheKey(xPath, name)
delete(v.dataCache, cacheKey)
delete(v.listCache, xPath)
v.db.Rem(xPath, name)
}
func (v *DBReadCache) makeDataCacheKey(xPath, name string) [2]string {
return [2]string{xPath, name}
}

159
server/settings/jsondb.go Normal file
View File

@@ -0,0 +1,159 @@
package settings
import (
"encoding/json"
"errors"
"fmt"
"io/fs"
"os"
"path/filepath"
"strings"
"sync"
"server/log"
)
type JsonDB struct {
Path string
filenameDelimiter string
filenameExtension string
fileMode fs.FileMode
xPathDelimeter string
}
var jsonDbLocks = make(map[string]*sync.Mutex)
func NewJsonDB() TorrServerDB {
settingsDB := &JsonDB{
Path: Path,
filenameDelimiter: ".",
filenameExtension: ".json",
fileMode: fs.FileMode(0o666),
xPathDelimeter: "/",
}
return settingsDB
}
func (v *JsonDB) CloseDB() {
// Not necessary
}
func (v *JsonDB) Set(xPath, name string, value []byte) {
var err error = nil
jsonObj := map[string]interface{}{}
if err := json.Unmarshal(value, &jsonObj); err == nil {
if filename, err := v.xPathToFilename(xPath); err == nil {
v.lock(filename)
defer v.unlock(filename)
if root, err := v.readJsonFileAsMap(filename); err == nil {
root[name] = jsonObj
if err = v.writeMapAsJsonFile(filename, root); err == nil {
return
}
}
}
}
v.log(fmt.Sprintf("Set: error writing entry %s->%s", xPath, name), err)
}
func (v *JsonDB) Get(xPath, name string) []byte {
var err error = nil
if filename, err := v.xPathToFilename(xPath); err == nil {
v.lock(filename)
defer v.unlock(filename)
if root, err := v.readJsonFileAsMap(filename); err == nil {
if jsonData, ok := root[name]; ok {
if byteData, err := json.Marshal(jsonData); err == nil {
return byteData
}
} else {
// We assume this is not 'error' but 'no entry' which is normal
return nil
}
}
}
v.log(fmt.Sprintf("Get: error reading entry %s->%s", xPath, name), err)
return nil
}
func (v *JsonDB) List(xPath string) []string {
var err error = nil
if filename, err := v.xPathToFilename(xPath); err == nil {
v.lock(filename)
defer v.unlock(filename)
if root, err := v.readJsonFileAsMap(filename); err == nil {
nameList := make([]string, 0, len(root))
for k := range root {
nameList = append(nameList, k)
}
return nameList
}
}
v.log(fmt.Sprintf("List: error reading entries in xPath %s", xPath), err)
return nil
}
func (v *JsonDB) Rem(xPath, name string) {
var err error = nil
if filename, err := v.xPathToFilename(xPath); err == nil {
v.lock(filename)
defer v.unlock(filename)
if root, err := v.readJsonFileAsMap(filename); err == nil {
delete(root, name)
v.writeMapAsJsonFile(filename, root)
return
}
}
v.log(fmt.Sprintf("Rem: error removing entry %s->%s", xPath, name), err)
}
func (v *JsonDB) lock(filename string) {
var mtx sync.Mutex
if mtx, ok := jsonDbLocks[filename]; !ok {
mtx = new(sync.Mutex)
jsonDbLocks[v.Path] = mtx
}
mtx.Lock()
}
func (v *JsonDB) unlock(filename string) {
if mtx, ok := jsonDbLocks[filename]; ok {
mtx.Unlock()
}
}
func (v *JsonDB) xPathToFilename(xPath string) (string, error) {
if pathComponents := strings.Split(xPath, v.xPathDelimeter); len(pathComponents) > 0 {
return strings.ToLower(strings.Join(pathComponents, v.filenameDelimiter) + v.filenameExtension), nil
}
return "", errors.New("xPath has no components")
}
func (v *JsonDB) readJsonFileAsMap(filename string) (map[string]interface{}, error) {
var err error = nil
jsonData := map[string]interface{}{}
path := filepath.Join(v.Path, filename)
if fileData, err := os.ReadFile(path); err == nil {
err = json.Unmarshal(fileData, &jsonData)
}
return jsonData, err
}
func (v *JsonDB) writeMapAsJsonFile(filename string, o map[string]interface{}) error {
var err error = nil
path := filepath.Join(v.Path, filename)
if fileData, err := json.MarshalIndent(o, "", " "); err == nil {
err = os.WriteFile(path, fileData, v.fileMode)
}
return err
}
func (v *JsonDB) log(s string, params ...interface{}) {
if len(params) > 0 {
log.TLogln(fmt.Sprintf("JsonDB: %s: %s", s, fmt.Sprint(params...)))
} else {
log.TLogln(fmt.Sprintf("JsonDB: %s", s))
}
}

View File

@@ -2,13 +2,17 @@ package settings
import (
"encoding/binary"
"encoding/json"
"errors"
"fmt"
"os"
"path/filepath"
"reflect"
bolt "go.etcd.io/bbolt"
"server/log"
"server/web/api/utils"
bolt "go.etcd.io/bbolt"
)
var dbTorrentsName = []byte("Torrents")
@@ -22,7 +26,8 @@ type torrentOldDB struct {
Timestamp int64
}
func Migrate() {
// Migrate from torrserver.db to config.db
func Migrate1() {
if _, err := os.Lstat(filepath.Join(Path, "torrserver.db")); os.IsNotExist(err) {
return
}
@@ -100,3 +105,87 @@ func Migrate() {
func b2i(v []byte) int64 {
return int64(binary.BigEndian.Uint64(v))
}
/*
=== Migrate 2 ===
Migrate 'Settings' and 'Viewed' buckets from BBolt ('config.db')
to separate JSON files ('settings.json' and 'viewed.json')
'Torrents' data continues to remain in the BBolt database ('config.db')
due to the fact that BLOBs are stored there
To make user be able to roll settings back, no data is deleted from 'config.db' file.
*/
func Migrate2(bboltDB, jsonDB TorrServerDB) error {
var err error = nil
const XPATH_SETTINGS = "Settings"
const NAME_BITTORR = "BitTorr"
const XPATH_VIEWED = "Viewed"
if BTsets != nil {
msg := "Migrate0002 MUST be called before initializing BTSets"
log.TLogln(msg)
os.Exit(1)
}
isByteArraysEqualJson := func(a, b []byte) (bool, error) {
var objectA interface{}
var objectB interface{}
var err error = nil
if err = json.Unmarshal(a, &objectA); err == nil {
if err = json.Unmarshal(b, &objectB); err == nil {
return reflect.DeepEqual(objectA, objectB), nil
} else {
err = fmt.Errorf("Error unmashalling B: %s", err.Error())
}
} else {
err = fmt.Errorf("Error unmashalling A: %s", err.Error())
}
return false, err
}
migrateXPath := func(xPath, name string) error {
if jsonDB.Get(xPath, name) == nil {
bboltDBBlob := bboltDB.Get(xPath, name)
if bboltDBBlob != nil {
log.TLogln(fmt.Sprintf("Attempting to migrate %s->%s from TDB to JsonDB", xPath, name))
jsonDB.Set(xPath, name, bboltDBBlob)
jsonDBBlob := jsonDB.Get(xPath, name)
if isEqual, err := isByteArraysEqualJson(bboltDBBlob, jsonDBBlob); err == nil {
if isEqual {
log.TLogln(fmt.Sprintf("Migrated %s->%s successful", xPath, name))
} else {
msg := fmt.Sprintf("Failed to migrate %s->%s TDB to JsonDB: equality check failed", xPath, name)
log.TLogln(msg)
return errors.New(msg)
}
} else {
msg := fmt.Sprintf("Failed to migrate %s->%s TDB to JsonDB: %s", xPath, name, err)
log.TLogln(msg)
return errors.New(msg)
}
}
}
return nil
}
if err = migrateXPath(XPATH_SETTINGS, NAME_BITTORR); err != nil {
return err
}
jsonDBViewedNames := jsonDB.List(XPATH_VIEWED)
if len(jsonDBViewedNames) <= 0 {
bboltDBViewedNames := bboltDB.List(XPATH_VIEWED)
if len(bboltDBViewedNames) > 0 {
for _, name := range bboltDBViewedNames {
err = migrateXPath(XPATH_VIEWED, name)
if err != nil {
break
}
}
}
}
return err
}

View File

@@ -1,6 +1,7 @@
package settings
import (
"fmt"
"os"
"path/filepath"
@@ -8,7 +9,7 @@ import (
)
var (
tdb *TDB
tdb TorrServerDB
Path string
Port string
Ssl bool
@@ -19,18 +20,40 @@ var (
PubIPv4 string
PubIPv6 string
TorAddr string
MaxSize int64
)
func InitSets(readOnly, searchWA bool) {
ReadOnly = readOnly
SearchWA = searchWA
tdb = NewTDB()
if tdb == nil {
log.TLogln("Error open db:", filepath.Join(Path, "config.db"))
bboltDB := NewTDB()
if bboltDB == nil {
log.TLogln("Error open bboltDB:", filepath.Join(Path, "config.db"))
os.Exit(1)
}
jsonDB := NewJsonDB()
if jsonDB == nil {
log.TLogln("Error open jsonDB")
os.Exit(1)
}
dbRouter := NewXPathDBRouter()
// First registered DB becomes default route
dbRouter.RegisterRoute(jsonDB, "Settings")
dbRouter.RegisterRoute(jsonDB, "Viewed")
dbRouter.RegisterRoute(bboltDB, "Torrents")
tdb = NewDBReadCache(dbRouter)
// We migrate settings here, it must be done before loadBTSets()
if err := Migrate2(bboltDB, jsonDB); err != nil {
log.TLogln(fmt.Sprintf("Migrate2 failed"))
os.Exit(1)
}
loadBTSets()
Migrate()
Migrate1()
}
func CloseDB() {

View File

@@ -0,0 +1,9 @@
package settings
type TorrServerDB interface {
CloseDB()
Get(xPath, name string) []byte
Set(xPath, name string, value []byte)
List(xPath string) []string
Rem(xPath, name string)
}

View File

@@ -0,0 +1,119 @@
package settings
import (
"errors"
"fmt"
"reflect"
"sort"
"strings"
"server/log"
"golang.org/x/exp/slices"
)
type XPathDBRouter struct {
dbs []TorrServerDB
routes []string
route2db map[string]TorrServerDB
dbNames map[TorrServerDB]string
}
func NewXPathDBRouter() *XPathDBRouter {
router := &XPathDBRouter{
dbs: []TorrServerDB{},
dbNames: map[TorrServerDB]string{},
routes: []string{},
route2db: map[string]TorrServerDB{},
}
return router
}
func (v *XPathDBRouter) RegisterRoute(db TorrServerDB, xPath string) error {
newRoute := v.xPathToRoute(xPath)
if slices.Contains(v.routes, newRoute) {
return errors.New(fmt.Sprintf("route \"%s\" already in routing table", newRoute))
}
// First DB becomes Default DB with default route
if len(v.dbs) == 0 && len(newRoute) != 0 {
v.RegisterRoute(db, "")
}
if !slices.Contains(v.dbs, db) {
v.dbs = append(v.dbs, db)
v.dbNames[db] = reflect.TypeOf(db).Elem().Name()
v.log(fmt.Sprintf("Registered new DB \"%s\", total %d DBs registered", v.getDBName(db), len(v.dbs)))
}
v.route2db[newRoute] = db
v.routes = append(v.routes, newRoute)
// Sort routes by length descending.
// It is important later to help selecting
// most suitable route in getDBForXPath(xPath)
sort.Slice(v.routes, func(iLeft, iRight int) bool {
return len(v.routes[iLeft]) > len(v.routes[iRight])
})
v.log(fmt.Sprintf("Registered new route \"%s\" for DB \"%s\", total %d routes", newRoute, v.getDBName(db), len(v.routes)))
return nil
}
func (v *XPathDBRouter) xPathToRoute(xPath string) string {
return strings.ToLower(strings.TrimSpace(xPath))
}
func (v *XPathDBRouter) getDBForXPath(xPath string) TorrServerDB {
if len(v.dbs) == 0 {
return nil
}
lookup_route := v.xPathToRoute(xPath)
var db TorrServerDB = nil
// Expected v.routes sorted by length descending
for _, route_prefix := range v.routes {
if strings.HasPrefix(lookup_route, route_prefix) {
db = v.route2db[route_prefix]
break
}
}
return db
}
func (v *XPathDBRouter) Get(xPath, name string) []byte {
return v.getDBForXPath(xPath).Get(xPath, name)
}
func (v *XPathDBRouter) Set(xPath, name string, value []byte) {
v.getDBForXPath(xPath).Set(xPath, name, value)
}
func (v *XPathDBRouter) List(xPath string) []string {
return v.getDBForXPath(xPath).List(xPath)
}
func (v *XPathDBRouter) Rem(xPath, name string) {
v.getDBForXPath(xPath).Rem(xPath, name)
}
func (v *XPathDBRouter) CloseDB() {
for _, db := range v.dbs {
db.CloseDB()
}
v.dbs = nil
v.routes = nil
v.route2db = nil
v.dbNames = nil
}
func (v *XPathDBRouter) getDBName(db TorrServerDB) string {
return v.dbNames[db]
}
func (v *XPathDBRouter) log(s string, params ...interface{}) {
if len(params) > 0 {
log.TLogln(fmt.Sprintf("XPathDBRouter: %s: %s", s, fmt.Sprint(params...)))
} else {
log.TLogln(fmt.Sprintf("XPathDBRouter: %s", s))
}
}

View File

@@ -150,19 +150,24 @@ func SetTorrent(hashHex, title, poster, data string) *Torrent {
}
func RemTorrent(hashHex string) {
if sets.ReadOnly {
log.TLogln("API RemTorrent: Read-only DB mode!", hashHex)
return
}
hash := metainfo.NewHashFromHex(hashHex)
if sets.BTsets.UseDisk && hashHex != "" && hashHex != "/" {
name := filepath.Join(sets.BTsets.TorrentsSavePath, hashHex)
ff, _ := os.ReadDir(name)
for _, f := range ff {
os.Remove(filepath.Join(name, f.Name()))
}
err := os.Remove(name)
if err != nil {
log.TLogln("Error remove cache:", err)
if bts.RemoveTorrent(hash) {
if sets.BTsets.UseDisk && hashHex != "" && hashHex != "/" {
name := filepath.Join(sets.BTsets.TorrentsSavePath, hashHex)
ff, _ := os.ReadDir(name)
for _, f := range ff {
os.Remove(filepath.Join(name, f.Name()))
}
err := os.Remove(name)
if err != nil {
log.TLogln("Error remove cache:", err)
}
}
}
bts.RemoveTorrent(hash)
RemTorrentDB(hash)
}
@@ -199,6 +204,7 @@ func DropTorrent(hashHex string) {
func SetSettings(set *sets.BTSets) {
if sets.ReadOnly {
log.TLogln("API SetSettings: Read-only DB mode!")
return
}
sets.SetBTSets(set)
@@ -215,6 +221,7 @@ func SetSettings(set *sets.BTSets) {
func SetDefSettings() {
if sets.ReadOnly {
log.TLogln("API SetDefSettings: Read-only DB mode!")
return
}
sets.SetDefaultConfig()

View File

@@ -88,14 +88,13 @@ func (bt *BTServer) configure(ctx context.Context) {
upnpID := "TorrServer/" + version.Version
cliVers := userAgent
// bt.config.AlwaysWantConns = true
bt.config.Debug = settings.BTsets.EnableDebug
bt.config.DisableIPv6 = !settings.BTsets.EnableIPv6
bt.config.DisableTCP = settings.BTsets.DisableTCP
bt.config.DisableUTP = settings.BTsets.DisableUTP
// https://github.com/anacrolix/torrent/issues/703
// bt.config.DisableWebtorrent = true // TODO: check memory usage
// bt.config.DisableWebseeds = false
// bt.config.DisableWebtorrent = true // NE
// bt.config.DisableWebseeds = false // NE
bt.config.NoDefaultPortForwarding = settings.BTsets.DisableUPNP
bt.config.NoDHT = settings.BTsets.DisableDHT
bt.config.DisablePEX = settings.BTsets.DisablePEX
@@ -109,13 +108,13 @@ func (bt *BTServer) configure(ctx context.Context) {
bt.config.EstablishedConnsPerTorrent = settings.BTsets.ConnectionsLimit
bt.config.TotalHalfOpenConns = 500
// Encryption/Obfuscation
bt.config.EncryptionPolicy = torrent.EncryptionPolicy{
ForceEncryption: settings.BTsets.ForceEncrypt,
}
// bt.config.HeaderObfuscationPolicy = torrent.HeaderObfuscationPolicy{
// RequirePreferred: settings.BTsets.ForceEncrypt,
// Preferred: true,
// }
bt.config.EncryptionPolicy = torrent.EncryptionPolicy{ // OE
ForceEncryption: settings.BTsets.ForceEncrypt, // OE
} // OE
// bt.config.HeaderObfuscationPolicy = torrent.HeaderObfuscationPolicy{ // NE
// RequirePreferred: settings.BTsets.ForceEncrypt, // NE
// Preferred: true, // NE
// } // NE
if settings.BTsets.DownloadRateLimit > 0 {
bt.config.DownloadRateLimiter = utils.Limit(settings.BTsets.DownloadRateLimit * 1024)
}
@@ -130,21 +129,8 @@ func (bt *BTServer) configure(ctx context.Context) {
log.Println("Set listen port", settings.BTsets.PeersListenPort)
bt.config.ListenPort = settings.BTsets.PeersListenPort
} else {
// lport := 32000
// for {
// log.Println("Check listen port", lport)
// l, err := net.Listen("tcp", ":"+strconv.Itoa(lport))
// if l != nil {
// l.Close()
// }
// if err == nil {
// break
// }
// lport++
// }
// log.Println("Set listen port", lport)
log.Println("Set listen port to random autoselect (0)")
bt.config.ListenPort = 0 // lport
bt.config.ListenPort = 0
}
}
@@ -200,10 +186,11 @@ func (bt *BTServer) ListTorrents() map[metainfo.Hash]*Torrent {
return list
}
func (bt *BTServer) RemoveTorrent(hash torrent.InfoHash) {
func (bt *BTServer) RemoveTorrent(hash torrent.InfoHash) bool {
if torr, ok := bt.torrents[hash]; ok {
torr.Close()
return torr.Close()
}
return false
}
func isPrivateIP(ip net.IP) bool {

View File

@@ -62,7 +62,7 @@ func (t *Torrent) Preload(index int, size int64) {
// Запуск лога в отдельном потоке
go func() {
for t.Stat == state.TorrentPreload {
stat := fmt.Sprint(file.Torrent().InfoHash().HexString(), " ", utils2.Format(float64(t.PreloadedBytes)), "/", utils2.Format(float64(t.PreloadSize)), " Speed:", utils2.Format(t.DownloadSpeed), " Peers:[", t.Torrent.Stats().ConnectedSeeders, "]", t.Torrent.Stats().ActivePeers, "/", t.Torrent.Stats().TotalPeers)
stat := fmt.Sprint(file.Torrent().InfoHash().HexString(), " ", utils2.Format(float64(t.PreloadedBytes)), "/", utils2.Format(float64(t.PreloadSize)), " Speed:", utils2.Format(t.DownloadSpeed), " Peers:", t.Torrent.Stats().ActivePeers, "/", t.Torrent.Stats().TotalPeers, " [Seeds:", t.Torrent.Stats().ConnectedSeeders, "]")
log.TLogln("Preload:", stat)
t.AddExpiredTime(time.Second * time.Duration(settings.BTsets.TorrentDisconnectTimeout))
time.Sleep(time.Second)
@@ -158,7 +158,7 @@ func (t *Torrent) Preload(index int, size int64) {
wg.Wait()
}
log.TLogln("End preload:", file.Torrent().InfoHash().HexString(), "Peers:[", t.Torrent.Stats().ConnectedSeeders, "]", t.Torrent.Stats().ActivePeers, "/", t.Torrent.Stats().TotalPeers)
log.TLogln("End preload:", file.Torrent().InfoHash().HexString(), "Peers:", t.Torrent.Stats().ActivePeers, "/", t.Torrent.Stats().TotalPeers, "[ Seeds:", t.Torrent.Stats().ConnectedSeeders, "]")
}
func (t *Torrent) findFileIndex(index int) *torrent.File {

View File

@@ -314,6 +314,21 @@ func (c *Cache) NewReader(file *torrent.File) *Reader {
return newReader(file, c)
}
func (c *Cache) GetUseReaders() int {
if c == nil {
return 0
}
c.muReaders.Lock()
defer c.muReaders.Unlock()
readers := 0
for reader := range c.readers {
if reader.isUse {
readers++
}
}
return readers
}
func (c *Cache) Readers() int {
if c == nil {
return 0

View File

@@ -25,20 +25,20 @@ func NewStorage(capacity int64) *Storage {
}
func (s *Storage) OpenTorrent(info *metainfo.Info, infoHash metainfo.Hash) (ts.TorrentImpl, error) {
// capFunc := func() (int64, bool) {
// return s.capacity, true
// }
// capFunc := func() (int64, bool) { // NE
// return s.capacity, true // NE
// } // NE
s.mu.Lock()
defer s.mu.Unlock()
ch := NewCache(s.capacity, s)
ch.Init(info, infoHash)
s.caches[infoHash] = ch
return ch, nil
// return ts.TorrentImpl{
// Piece: ch.Piece,
// Close: ch.Close,
// Capacity: &capFunc,
// }, nil
return ch, nil // OE
// return ts.TorrentImpl{ // NE
// Piece: ch.Piece, // NE
// Close: ch.Close, // NE
// Capacity: &capFunc, // NE
// }, nil // NE
}
func (s *Storage) CloseHash(hash metainfo.Hash) {

View File

@@ -10,7 +10,7 @@ import (
"time"
"github.com/anacrolix/dms/dlna"
"github.com/anacrolix/missinggo/httptoo"
"github.com/anacrolix/missinggo/v2/httptoo"
"github.com/anacrolix/torrent"
mt "server/mimetype"
@@ -47,6 +47,10 @@ func (t *Torrent) Stream(fileID int, req *http.Request, resp http.ResponseWriter
if file == nil {
return fmt.Errorf("file with id %v not found", fileID)
}
if int64(sets.MaxSize) > 0 && file.Length() > int64(sets.MaxSize) {
log.Println("file", file.DisplayPath(), "size exceeded max allowed", sets.MaxSize, "bytes")
return fmt.Errorf("file size exceeded max allowed %d bytes", sets.MaxSize)
}
reader := t.NewReader(file)

View File

@@ -6,6 +6,8 @@ import (
"sync"
"time"
utils2 "server/utils"
"github.com/anacrolix/torrent"
"github.com/anacrolix/torrent/metainfo"
@@ -266,7 +268,10 @@ func (t *Torrent) drop() {
}
}
func (t *Torrent) Close() {
func (t *Torrent) Close() bool {
if t.cache != nil && t.cache.GetUseReaders() > 0 {
return false
}
t.Stat = state.TorrentClosed
t.bt.mu.Lock()
@@ -274,6 +279,7 @@ func (t *Torrent) Close() {
t.bt.mu.Unlock()
t.drop()
return true
}
func (t *Torrent) Status() *state.TorrentStatus {
@@ -329,7 +335,7 @@ func (t *Torrent) Status() *state.TorrentStatus {
files := t.Files()
sort.Slice(files, func(i, j int) bool {
return files[i].Path() < files[j].Path()
return utils2.CompareStrings(files[i].Path(), files[j].Path())
})
for i, f := range files {
st.FileStats = append(st.FileStats, &state.TorrentFileStat{

View File

@@ -3,6 +3,8 @@ package utils
import (
"fmt"
"strconv"
"strings"
"unicode"
)
const (
@@ -46,3 +48,52 @@ func Format(b float64) string {
return fmt.Sprintf("%.2f%s", value, multiple)
}
func CommonPrefix(first, second string) string {
var result strings.Builder
minLength := len(first)
if len(second) < minLength {
minLength = len(second)
}
for i := 0; i < minLength; i++ {
if first[i] != second[i] {
break
}
result.WriteByte(first[i])
}
return result.String()
}
func NumberPrefix(str string) (int, error) {
var result strings.Builder
for i := 0; i < len(str); i++ {
if !unicode.IsDigit(rune(str[i])) {
break
}
result.WriteByte(str[i])
}
return strconv.Atoi(result.String())
}
func CompareStrings(first, second string) bool {
commonPrefix := CommonPrefix(first, second)
resultStr1 := strings.TrimPrefix(first, commonPrefix)
resultStr2 := strings.TrimPrefix(second, commonPrefix)
num1, err1 := NumberPrefix(resultStr1)
num2, err2 := NumberPrefix(resultStr2)
if err1 == nil && err2 == nil {
return num1 < num2
}
if err1 == nil {
return true
} else if err2 == nil {
return false
}
return resultStr1 < resultStr2
}

View File

@@ -6,7 +6,7 @@ import (
// "github.com/anacrolix/torrent"
)
const Version = "MatriX.127.2"
const Version = "MatriX.130"
func GetTorrentVersion() string {
bi, ok := debug.ReadBuildInfo()

View File

@@ -47,7 +47,7 @@ func (f *fileReader) Seek(offset int64, whence int) (int64, error) {
//
// @Tags API
//
// @Param size path string true "Test file size"
// @Param size path string true "Test file size (in MB)"
//
// @Produce application/octet-stream
// @Success 200 {file} file

View File

@@ -18,12 +18,12 @@ import (
//
// @Tags API
//
// @Param hash query string true "Torrent hash"
// @Param id query string true "File index in torrent"
// @Param hash path string true "Torrent hash"
// @Param id path string true "File index in torrent"
//
// @Produce json
// @Success 200 "Data returned from ffprobe"
// @Router /ffp [get]
// @Router /ffp/{hash}/{id} [get]
func ffp(c *gin.Context) {
hash := c.Param("hash")
indexStr := c.Param("id")

View File

@@ -11,7 +11,7 @@ import (
"strings"
"time"
"github.com/anacrolix/missinggo/httptoo"
"github.com/anacrolix/missinggo/v2/httptoo"
sets "server/settings"
"server/torr"

View File

@@ -19,17 +19,16 @@ import (
//
// @Tags API
//
// @Param hash query string true "Torrent hash"
// @Param id query string true "File index in torrent"
// @Param not_auth query bool false "Not authenticated"
// @Param hash path string true "Torrent hash"
// @Param id path string true "File index in torrent"
//
// @Produce application/octet-stream
// @Success 200 "Torrent data"
// @Router /play [get]
// @Router /play/{hash}/{id} [get]
func play(c *gin.Context) {
hash := c.Param("hash")
indexStr := c.Param("id")
notAuth := c.GetBool("not_auth")
notAuth := c.GetBool("auth_required") && c.GetString(gin.AuthUserKey) == ""
if hash == "" || indexStr == "" {
c.AbortWithError(http.StatusNotFound, errors.New("link should not be empty"))

View File

@@ -1,6 +1,9 @@
package api
import (
config "server/settings"
"server/web/auth"
"github.com/gin-gonic/gin"
)
@@ -8,15 +11,17 @@ type requestI struct {
Action string `json:"action,omitempty"`
}
func SetupRoute(route *gin.RouterGroup) {
route.GET("/shutdown", shutdown)
func SetupRoute(route gin.IRouter) {
authorized := route.Group("/", auth.CheckAuth())
route.POST("/settings", settings)
authorized.GET("/shutdown", shutdown)
route.POST("/torrents", torrents)
route.POST("/torrent/upload", torrentUpload)
authorized.POST("/settings", settings)
route.POST("/cache", cache)
authorized.POST("/torrents", torrents)
authorized.POST("/torrent/upload", torrentUpload)
authorized.POST("/cache", cache)
route.HEAD("/stream", stream)
route.HEAD("/stream/*fname", stream)
@@ -27,15 +32,19 @@ func SetupRoute(route *gin.RouterGroup) {
route.HEAD("/play/:hash/:id", play)
route.GET("/play/:hash/:id", play)
route.POST("/viewed", viewed)
authorized.POST("/viewed", viewed)
route.GET("/playlistall/all.m3u", allPlayList)
authorized.GET("/playlistall/all.m3u", allPlayList)
route.GET("/playlist", playList)
route.GET("/playlist/*fname", playList) // Is this endpoint still needed ? `fname` is never used in handler
route.GET("/download/:size", download)
authorized.GET("/download/:size", download)
route.GET("/search/*query", rutorSearch)
if config.SearchWA {
route.GET("/search/*query", rutorSearch)
} else {
authorized.GET("/search/*query", rutorSearch)
}
route.GET("/ffp/:hash/:id", ffp)
authorized.GET("/ffp/:hash/:id", ffp)
}

View File

@@ -41,11 +41,10 @@ import (
// @Param stat query string false "Get statistics from torrent"
// @Param save query string false "Should save torrent"
// @Param m3u query string false "Get torrent as M3U playlist"
// @Param fromlast query string false "Get m3u from last play"
// @Param fromlast query string false "Get M3U from last played file"
// @Param play query string false "Start stream torrent"
// @Param title query string true "Set title of torrent"
// @Param poster query string true "File index in torrent"
// @Param not_auth query string true "Set poster link of torrent"
// @Param poster query string true "Set poster link of torrent"
//
// @Produce application/octet-stream
// @Success 200 "Data returned according to query"
@@ -62,7 +61,7 @@ func stream(c *gin.Context) {
title := c.Query("title")
poster := c.Query("poster")
data := ""
notAuth := c.GetBool("not_auth")
notAuth := c.GetBool("auth_required") && c.GetString(gin.AuthUserKey) == ""
if notAuth && (play || m3u) {
streamNoAuth(c)

View File

@@ -73,6 +73,10 @@ func torrents(c *gin.Context) {
{
dropTorrent(req, c)
}
case "wipe":
{
wipeTorrents(req, c)
}
}
}
@@ -188,3 +192,16 @@ func dropTorrent(req torrReqJS, c *gin.Context) {
torr.DropTorrent(req.Hash)
c.Status(200)
}
func wipeTorrents(req torrReqJS, c *gin.Context) {
torrents := torr.ListTorrent()
for _, t := range torrents {
torr.RemTorrent(t.TorrentSpec.InfoHash.HexString())
}
// TODO: remove (copied todo from remTorrent())
if set.BTsets.EnableDLNA {
dlna.Stop()
dlna.Start()
}
c.Status(200)
}

View File

@@ -6,8 +6,6 @@ import (
"net/http"
"os"
"path/filepath"
"reflect"
"strings"
"unsafe"
"github.com/gin-gonic/gin"
@@ -16,15 +14,15 @@ import (
"server/settings"
)
func SetupAuth(engine *gin.Engine) *gin.RouterGroup {
func SetupAuth(engine *gin.Engine) {
if !settings.HttpAuth {
return nil
return
}
accs := getAccounts()
if accs == nil {
return nil
return
}
return engine.Group("/", BasicAuth(accs))
engine.Use(BasicAuth(accs))
}
func getAccounts() gin.Accounts {
@@ -61,21 +59,27 @@ func (a authPairs) searchCredential(authValue string) (string, bool) {
func BasicAuth(accounts gin.Accounts) gin.HandlerFunc {
pairs := processAccounts(accounts)
return func(c *gin.Context) {
c.Set("auth_required", true)
user, found := pairs.searchCredential(c.Request.Header.Get("Authorization"))
if !found { // always accessible
if strings.HasPrefix(c.FullPath(), "/stream") ||
c.FullPath() == "/site.webmanifest" ||
// https://github.com/YouROK/TorrServer/issues/172
(strings.HasPrefix(c.FullPath(), "/play") && c.FullPath() != "/playlistall/all.m3u") ||
(settings.SearchWA && strings.HasPrefix(c.FullPath(), "/search")) {
c.Set("not_auth", true)
return
}
c.Header("WWW-Authenticate", "Basic realm=Authorization Required")
c.AbortWithStatus(http.StatusUnauthorized)
if found {
c.Set(gin.AuthUserKey, user)
}
}
}
func CheckAuth() gin.HandlerFunc {
return func(c *gin.Context) {
if !settings.HttpAuth {
return
}
c.Set(gin.AuthUserKey, user)
if _, ok := c.Get(gin.AuthUserKey); ok {
return
}
c.Header("WWW-Authenticate", "Basic realm=Authorization Required")
c.AbortWithStatus(http.StatusUnauthorized)
}
}
@@ -97,8 +101,5 @@ func authorizationHeader(user, password string) string {
}
func StringToBytes(s string) (b []byte) {
sh := *(*reflect.StringHeader)(unsafe.Pointer(&s))
bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
bh.Data, bh.Len, bh.Cap = sh.Data, sh.Len, sh.Len
return b
return unsafe.Slice(unsafe.StringData(s), len(s))
}

View File

@@ -7,6 +7,7 @@ import (
"sync"
"server/version"
"server/web/auth"
"github.com/gin-gonic/gin"
)
@@ -30,10 +31,12 @@ func asset(c *gin.Context, t string, d []byte) {
c.Data(200, t+"; charset=UTF-8", d)
}
func SetupRoute(r *gin.RouterGroup) {
r.GET("/msx/:pth", msxPTH)
r.GET("/msx/imdb", msxIMDB)
r.GET("/msx/imdb/:id", msxIMDBID)
func SetupRoute(r gin.IRouter) {
authorized := r.Group("/", auth.CheckAuth())
authorized.GET("/msx/:pth", msxPTH)
authorized.GET("/msx/imdb", msxIMDB)
authorized.GET("/msx/imdb/:id", msxIMDBID)
}
// msxPTH godoc
@@ -43,11 +46,11 @@ func SetupRoute(r *gin.RouterGroup) {
//
// @Tags MSX
//
// @Param link query string true "Magnet/hash/link to torrent"
// @Param link path string true "Route MSX pages"
//
// @Produce json
// @Success 200 "Data returned according to query"
// @Router /msx [get]
// @Success 200 "Data returned according to path"
// @Router /msx/{pth} [get]
func msxPTH(c *gin.Context) {
js := []string{"http://msx.benzac.de/js/tvx-plugin.min.js"}
switch p := c.Param("pth"); p {
@@ -114,7 +117,7 @@ func msxIMDB(c *gin.Context) {
//
// @Produce json
// @Success 200 "JSON MSX IMDB informations"
// @Router /msx/imdb/:id [get]
// @Router /msx/imdb/{id} [get]
func msxIMDBID(c *gin.Context) {
idb.Lock()
defer idb.Unlock()

View File

@@ -6,13 +6,27 @@ import (
"server/settings"
"server/torr"
"server/web/auth"
"server/web/pages/template"
"golang.org/x/exp/slices"
)
func SetupRoute(route *gin.RouterGroup) {
template.RouteWebPages(route)
route.GET("/stat", statPage)
route.GET("/magnets", getTorrents)
func SetupRoute(route gin.IRouter) {
authorized := route.Group("/", auth.CheckAuth())
webPagesAuth := route.Group("/", func() gin.HandlerFunc {
return func(c *gin.Context) {
if slices.Contains([]string{"/site.webmanifest"}, c.FullPath()) {
return
}
auth.CheckAuth()(c)
}
}())
template.RouteWebPages(webPagesAuth)
authorized.GET("/stat", statPage)
authorized.GET("/magnets", getTorrents)
}
// stat godoc

View File

@@ -118,20 +118,20 @@ var Mstile150x150png []byte
//go:embed pages/site.webmanifest
var Sitewebmanifest []byte
//go:embed pages/static/js/2.41a752aa.chunk.js
var Staticjs241a752aachunkjs []byte
//go:embed pages/static/js/2.916c2545.chunk.js
var Staticjs2916c2545chunkjs []byte
//go:embed pages/static/js/2.41a752aa.chunk.js.LICENSE.txt
var Staticjs241a752aachunkjsLICENSEtxt []byte
//go:embed pages/static/js/2.916c2545.chunk.js.LICENSE.txt
var Staticjs2916c2545chunkjsLICENSEtxt []byte
//go:embed pages/static/js/2.41a752aa.chunk.js.map
var Staticjs241a752aachunkjsmap []byte
//go:embed pages/static/js/2.916c2545.chunk.js.map
var Staticjs2916c2545chunkjsmap []byte
//go:embed pages/static/js/main.b1d76117.chunk.js
var Staticjsmainb1d76117chunkjs []byte
//go:embed pages/static/js/main.55f380e1.chunk.js
var Staticjsmain55f380e1chunkjs []byte
//go:embed pages/static/js/main.b1d76117.chunk.js.map
var Staticjsmainb1d76117chunkjsmap []byte
//go:embed pages/static/js/main.55f380e1.chunk.js.map
var Staticjsmain55f380e1chunkjsmap []byte
//go:embed pages/static/js/runtime-main.f542387e.js
var Staticjsruntimemainf542387ejs []byte

View File

@@ -1,17 +1,17 @@
{
"files": {
"main.js": "/static/js/main.b1d76117.chunk.js",
"main.js.map": "/static/js/main.b1d76117.chunk.js.map",
"main.js": "/static/js/main.55f380e1.chunk.js",
"main.js.map": "/static/js/main.55f380e1.chunk.js.map",
"runtime-main.js": "/static/js/runtime-main.f542387e.js",
"runtime-main.js.map": "/static/js/runtime-main.f542387e.js.map",
"static/js/2.41a752aa.chunk.js": "/static/js/2.41a752aa.chunk.js",
"static/js/2.41a752aa.chunk.js.map": "/static/js/2.41a752aa.chunk.js.map",
"static/js/2.916c2545.chunk.js": "/static/js/2.916c2545.chunk.js",
"static/js/2.916c2545.chunk.js.map": "/static/js/2.916c2545.chunk.js.map",
"index.html": "/index.html",
"static/js/2.41a752aa.chunk.js.LICENSE.txt": "/static/js/2.41a752aa.chunk.js.LICENSE.txt"
"static/js/2.916c2545.chunk.js.LICENSE.txt": "/static/js/2.916c2545.chunk.js.LICENSE.txt"
},
"entrypoints": [
"static/js/runtime-main.f542387e.js",
"static/js/2.41a752aa.chunk.js",
"static/js/main.b1d76117.chunk.js"
"static/js/2.916c2545.chunk.js",
"static/js/main.55f380e1.chunk.js"
]
}

File diff suppressed because one or more lines are too long

View File

@@ -1,191 +1,331 @@
package template
import (
"crypto/md5"
"fmt"
"github.com/gin-gonic/gin"
)
func RouteWebPages(route *gin.RouterGroup) {
func RouteWebPages(route gin.IRouter) {
route.GET("/", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Indexhtml))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "text/html; charset=utf-8", Indexhtml)
})
route.GET("/apple-splash-1125-2436.jpg", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Applesplash11252436jpg))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "image/jpeg", Applesplash11252436jpg)
})
route.GET("/apple-splash-1136-640.jpg", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Applesplash1136640jpg))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "image/jpeg", Applesplash1136640jpg)
})
route.GET("/apple-splash-1170-2532.jpg", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Applesplash11702532jpg))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "image/jpeg", Applesplash11702532jpg)
})
route.GET("/apple-splash-1242-2208.jpg", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Applesplash12422208jpg))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "image/jpeg", Applesplash12422208jpg)
})
route.GET("/apple-splash-1242-2688.jpg", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Applesplash12422688jpg))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "image/jpeg", Applesplash12422688jpg)
})
route.GET("/apple-splash-1284-2778.jpg", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Applesplash12842778jpg))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "image/jpeg", Applesplash12842778jpg)
})
route.GET("/apple-splash-1334-750.jpg", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Applesplash1334750jpg))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "image/jpeg", Applesplash1334750jpg)
})
route.GET("/apple-splash-1536-2048.jpg", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Applesplash15362048jpg))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "image/jpeg", Applesplash15362048jpg)
})
route.GET("/apple-splash-1620-2160.jpg", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Applesplash16202160jpg))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "image/jpeg", Applesplash16202160jpg)
})
route.GET("/apple-splash-1668-2224.jpg", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Applesplash16682224jpg))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "image/jpeg", Applesplash16682224jpg)
})
route.GET("/apple-splash-1668-2388.jpg", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Applesplash16682388jpg))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "image/jpeg", Applesplash16682388jpg)
})
route.GET("/apple-splash-1792-828.jpg", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Applesplash1792828jpg))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "image/jpeg", Applesplash1792828jpg)
})
route.GET("/apple-splash-2048-1536.jpg", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Applesplash20481536jpg))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "image/jpeg", Applesplash20481536jpg)
})
route.GET("/apple-splash-2048-2732.jpg", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Applesplash20482732jpg))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "image/jpeg", Applesplash20482732jpg)
})
route.GET("/apple-splash-2160-1620.jpg", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Applesplash21601620jpg))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "image/jpeg", Applesplash21601620jpg)
})
route.GET("/apple-splash-2208-1242.jpg", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Applesplash22081242jpg))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "image/jpeg", Applesplash22081242jpg)
})
route.GET("/apple-splash-2224-1668.jpg", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Applesplash22241668jpg))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "image/jpeg", Applesplash22241668jpg)
})
route.GET("/apple-splash-2388-1668.jpg", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Applesplash23881668jpg))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "image/jpeg", Applesplash23881668jpg)
})
route.GET("/apple-splash-2436-1125.jpg", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Applesplash24361125jpg))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "image/jpeg", Applesplash24361125jpg)
})
route.GET("/apple-splash-2532-1170.jpg", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Applesplash25321170jpg))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "image/jpeg", Applesplash25321170jpg)
})
route.GET("/apple-splash-2688-1242.jpg", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Applesplash26881242jpg))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "image/jpeg", Applesplash26881242jpg)
})
route.GET("/apple-splash-2732-2048.jpg", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Applesplash27322048jpg))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "image/jpeg", Applesplash27322048jpg)
})
route.GET("/apple-splash-2778-1284.jpg", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Applesplash27781284jpg))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "image/jpeg", Applesplash27781284jpg)
})
route.GET("/apple-splash-640-1136.jpg", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Applesplash6401136jpg))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "image/jpeg", Applesplash6401136jpg)
})
route.GET("/apple-splash-750-1334.jpg", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Applesplash7501334jpg))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "image/jpeg", Applesplash7501334jpg)
})
route.GET("/apple-splash-828-1792.jpg", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Applesplash8281792jpg))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "image/jpeg", Applesplash8281792jpg)
})
route.GET("/asset-manifest.json", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Assetmanifestjson))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "application/json", Assetmanifestjson)
})
route.GET("/browserconfig.xml", func(c *gin.Context) {
c.Data(200, "text/xml; charset=utf-8", Browserconfigxml)
etag := fmt.Sprintf("%x", md5.Sum(Browserconfigxml))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "application/xml; charset=utf-8", Browserconfigxml)
})
route.GET("/dlnaicon-120.png", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Dlnaicon120png))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "image/png", Dlnaicon120png)
})
route.GET("/dlnaicon-48.png", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Dlnaicon48png))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "image/png", Dlnaicon48png)
})
route.GET("/favicon-16x16.png", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Favicon16x16png))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "image/png", Favicon16x16png)
})
route.GET("/favicon-32x32.png", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Favicon32x32png))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "image/png", Favicon32x32png)
})
route.GET("/favicon.ico", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Faviconico))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "image/vnd.microsoft.icon", Faviconico)
})
route.GET("/icon.png", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Iconpng))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "image/png", Iconpng)
})
route.GET("/index.html", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Indexhtml))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "text/html; charset=utf-8", Indexhtml)
})
route.GET("/logo.png", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Logopng))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "image/png", Logopng)
})
route.GET("/mstile-150x150.png", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Mstile150x150png))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "image/png", Mstile150x150png)
})
route.GET("/site.webmanifest", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Sitewebmanifest))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "application/manifest+json", Sitewebmanifest)
})
route.GET("/static/js/2.41a752aa.chunk.js", func(c *gin.Context) {
c.Data(200, "text/javascript; charset=utf-8", Staticjs241a752aachunkjs)
route.GET("/static/js/2.916c2545.chunk.js", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Staticjs2916c2545chunkjs))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "application/javascript; charset=utf-8", Staticjs2916c2545chunkjs)
})
route.GET("/static/js/2.41a752aa.chunk.js.LICENSE.txt", func(c *gin.Context) {
c.Data(200, "text/plain; charset=utf-8", Staticjs241a752aachunkjsLICENSEtxt)
route.GET("/static/js/2.916c2545.chunk.js.LICENSE.txt", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Staticjs2916c2545chunkjsLICENSEtxt))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "text/plain; charset=utf-8", Staticjs2916c2545chunkjsLICENSEtxt)
})
route.GET("/static/js/2.41a752aa.chunk.js.map", func(c *gin.Context) {
c.Data(200, "application/json", Staticjs241a752aachunkjsmap)
route.GET("/static/js/2.916c2545.chunk.js.map", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Staticjs2916c2545chunkjsmap))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "application/json", Staticjs2916c2545chunkjsmap)
})
route.GET("/static/js/main.b1d76117.chunk.js", func(c *gin.Context) {
c.Data(200, "text/javascript; charset=utf-8", Staticjsmainb1d76117chunkjs)
route.GET("/static/js/main.55f380e1.chunk.js", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Staticjsmain55f380e1chunkjs))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "application/javascript; charset=utf-8", Staticjsmain55f380e1chunkjs)
})
route.GET("/static/js/main.b1d76117.chunk.js.map", func(c *gin.Context) {
c.Data(200, "application/json", Staticjsmainb1d76117chunkjsmap)
route.GET("/static/js/main.55f380e1.chunk.js.map", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Staticjsmain55f380e1chunkjsmap))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "application/json", Staticjsmain55f380e1chunkjsmap)
})
route.GET("/static/js/runtime-main.f542387e.js", func(c *gin.Context) {
c.Data(200, "text/javascript; charset=utf-8", Staticjsruntimemainf542387ejs)
etag := fmt.Sprintf("%x", md5.Sum(Staticjsruntimemainf542387ejs))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "application/javascript; charset=utf-8", Staticjsruntimemainf542387ejs)
})
route.GET("/static/js/runtime-main.f542387e.js.map", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(Staticjsruntimemainf542387ejsmap))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "application/json", Staticjsruntimemainf542387ejsmap)
})
}

View File

@@ -71,19 +71,14 @@ func Start() {
route := gin.New()
route.Use(log.WebLogger(), blocker.Blocker(), gin.Recovery(), cors.New(corsCfg), location.Default())
auth.SetupAuth(route)
route.GET("/echo", echo)
routeAuth := auth.SetupAuth(route)
if routeAuth != nil {
api.SetupRoute(routeAuth)
msx.SetupRoute(routeAuth)
pages.SetupRoute(routeAuth)
} else {
api.SetupRoute(&route.RouterGroup)
msx.SetupRoute(&route.RouterGroup)
pages.SetupRoute(&route.RouterGroup)
}
api.SetupRoute(route)
msx.SetupRoute(route)
pages.SetupRoute(route)
if settings.BTsets.EnableDLNA {
dlna.Start()
}