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

36
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,36 @@
---
name: Bug report
about: Create a report to help us improve
title: "[BUG]"
labels: bug
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. Linux Ubuntu 22.04]
- TorrServer Version [e.g. MatriX.129]
**Smartphone or tvbox on Android (please complete the following information):**
- Device: [e.g. Ugoos am6]
- OS: [e.g. Android 9]
- TorrServer Version [e.g. MatriX.129]
**Additional context**
Add any other context about the problem here.

View File

@@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: "[Feature]"
labels: enhancement
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@@ -62,10 +62,10 @@ curl -s https://raw.githubusercontent.com/YouROK/TorrServer/master/installTorrSe
#### macOS #### macOS
Run in console Run in Terminal.app
```bash ```bash
curl -s https://raw.githubusercontent.com/YouROK/TorrServer/master/installTorrServerMac.sh -o installTorrserverMac.sh && chmod 755 installTorrServerMac.sh && sudo ./installTorrServerMac.sh curl -s https://raw.githubusercontent.com/YouROK/TorrServer/master/installTorrServerMac.sh -o installTorrserverMac.sh && chmod 755 installTorrServerMac.sh && bash ./installTorrServerMac.sh
``` ```
Alternative install script for Intel Macs: <https://github.com/dancheskus/TorrServerMacInstaller> Alternative install script for Intel Macs: <https://github.com/dancheskus/TorrServerMacInstaller>
@@ -81,12 +81,12 @@ On FreeBSD (TrueNAS/FreeNAS) you can use this plugin: <https://github.com/filka9
### Server args ### Server args
- `--port PORT`, `-p PORT` - web server port, default 8090 - `--port PORT`, `-p PORT` - web server port (default 8090)
- `--ssl` - enables https for web server - `--ssl` - enables https for web server
- `--sslport PORT` - web server https port, default 8091. If not set, will be taken from db (if stored previously) or use default. - `--sslport PORT` - web server https port (default 8091). If not set, will be taken from db (if stored previously) or the default will be used.
- `--sslcert PATH` - 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. - `--sslcert PATH` - 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.
- `--sslkey PATH` - 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. - `--sslkey PATH` - 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.
- `--path PATH`, `-d PATH` - database dir path - `--path PATH`, `-d PATH` - database and config dir path
- `--logpath LOGPATH`, `-l LOGPATH` - server log file path - `--logpath LOGPATH`, `-l LOGPATH` - server log file path
- `--weblogpath WEBLOGPATH`, `-w WEBLOGPATH` - web access log file path - `--weblogpath WEBLOGPATH`, `-w WEBLOGPATH` - web access log file path
- `--rdb`, `-r` - start in read-only DB mode - `--rdb`, `-r` - start in read-only DB mode
@@ -171,7 +171,7 @@ Synology NAS packages repo source: https://grigi.lt
#### Server #### Server
- Install [Golang](https://golang.org/doc/install) 1.18+ - Install [Golang](https://golang.org/doc/install) 1.20+
- Go to the TorrServer source directory - Go to the TorrServer source directory
- Run build script under linux or macOS `build-all.sh` - Run build script under linux or macOS `build-all.sh`
@@ -245,23 +245,26 @@ local:127.0.0.1
- [QIWI](https://qiwi.com/n/YOUROK85) - [QIWI](https://qiwi.com/n/YOUROK85)
- [YooMoney](https://yoomoney.ru/to/410013733697114/200) - [YooMoney](https://yoomoney.ru/to/410013733697114/200)
- [PayPal](https://www.paypal.me/yourok)
- SberBank Card: **5484 4000 2285 7839** - SberBank Card: **5484 4000 2285 7839**
- YooMoney Card: **4048 4150 1812 8179**
## Thanks to everyone who tested and helped ## Thanks to everyone who tested and helped
- [anacrolix (Matt Joiner)](https://github.com/anacrolix) - [anacrolix](https://github.com/anacrolix) Matt Joiner
- [tsynik](https://github.com/tsynik) - [tsynik](https://github.com/tsynik)
- [dancheskus](https://github.com/dancheskus) - [dancheskus](https://github.com/dancheskus) for react web GUI and PWA code
- [kolsys](https://github.com/kolsys) - [kolsys](https://github.com/kolsys) for initial Media Station X support
- [vladlenas](https://github.com/vladlenas) - [damiva](https://github.com/damiva) for Media Station X code updates
- [Nemiroff (Tw1cker)](https://github.com/Nemiroff) - [vladlenas](https://github.com/vladlenas) for NAS builds
- [spawnlmg (SpAwN_LMG)](https://github.com/spawnlmg) - [Nemiroff](https://github.com/Nemiroff) Tw1cker
- [TopperBG (Dimitar Maznekov)](https://github.com/TopperBG) - [spawnlmg](https://github.com/spawnlmg) SpAwN_LMG for testing
- [FaintGhost (Zhang Yaowei)](https://github.com/FaintGhost) - [TopperBG](https://github.com/TopperBG) Dimitar Maznekov for Bulgarian web translation
- [Anton111111 (Anton Potekhin)](https://github.com/Anton111111) - [FaintGhost](https://github.com/FaintGhost) Zhang Yaowei for Simplified Chinese web translation
- [lieranderl (Evgeni)](https://github.com/lieranderl) - [Anton111111](https://github.com/Anton111111) Anton Potekhin for sleep on Windows fixes
- [cocool97](https://github.com/cocool97) - [lieranderl](https://github.com/lieranderl) Evgeni for adding SSL support code
- [shadeov](https://github.com/shadeov) - [cocool97](https://github.com/cocool97) for openapi API documentation
- [shadeov](https://github.com/shadeov) for README improvements
- [butaford](https://github.com/butaford) Pavel for make docker file and scripts
- [filimonic](https://github.com/filimonic) Alexey D. Filimonov
- [leporel](https://github.com/leporel) Viacheslav Evseev
- and others - and others

View File

@@ -54,6 +54,12 @@ echo "Build web"
export NODE_OPTIONS=--openssl-legacy-provider export NODE_OPTIONS=--openssl-legacy-provider
$GOBIN run gen_web.go $GOBIN run gen_web.go
#### Update api docs
echo "Build docs"
$GOBIN install github.com/swaggo/swag/cmd/swag@latest
cd "${ROOT}/server" || exit 1
swag init -g web/server.go
#### Build server #### Build server
echo "Build server" echo "Build server"
cd "${ROOT}/server" || exit 1 cd "${ROOT}/server" || exit 1

View File

@@ -1,9 +1,9 @@
#!/bin/sh #!/bin/sh
FLAGS="--path $TS_CONF_PATH --logpath $TS_LOG_PATH --port $TS_PORT --torrentsdir $TS_TORR_DIR" FLAGS="--path $TS_CONF_PATH --logpath $TS_LOG_PATH --port $TS_PORT --torrentsdir $TS_TORR_DIR"
if [[ -n "$TS_HTTPAUTH" ]]; then FLAGS="${FLAGS} --httpauth"; fi if [[ "$TS_HTTPAUTH" -eq 1 ]]; then FLAGS="${FLAGS} --httpauth"; fi
if [[ -n "$TS_RDB" ]]; then FLAGS="${FLAGS} --rdb"; fi if [[ "$TS_RDB" -eq 1 ]]; then FLAGS="${FLAGS} --rdb"; fi
if [[ -n "$TS_DONTKILL" ]]; then FLAGS="${FLAGS} --dontkill"; fi if [[ "$TS_DONTKILL" -eq 1 ]]; then FLAGS="${FLAGS} --dontkill"; fi
if [ ! -d $TS_CONF_PATH ]; then if [ ! -d $TS_CONF_PATH ]; then
mkdir -p $TS_CONF_PATH mkdir -p $TS_CONF_PATH

6
docker/Dockerfile Normal file
View File

@@ -0,0 +1,6 @@
FROM alpine
LABEL maintainer "yourok"
RUN apk add --no-cache wget
COPY start.sh /start.sh
ENTRYPOINT /start.sh

86
docker/README.md Normal file
View File

@@ -0,0 +1,86 @@
## TorrServer
After starting the container, the latest server is downloaded from GitHub.\
If you need update server to latest, repull container
Source code: https://github.com/YouROK/TorrServer
--------
Author of docker file and scripts [butaford (aka Pavel)](https://github.com/butaford)
--------
### Support platforms
* TorrServer-linux-386
* TorrServer-linux-amd64
* TorrServer-linux-arm5
* TorrServer-linux-arm64
* TorrServer-linux-arm7
--------
### Support env
TS_PORT: TS web port\
TS_PATH: config path and other\
TS_LOGPATHDIR: log path\
TS_LOGFILE: log file name\
TS_WEBLOGFILE: web log file name\
TS_RDB: read only config\
TS_HTTPAUTH: auth for server, accs.db should be in the TS_PATH\
TS_DONTKILL: don't kill server by signal\
TS_TORRENTSDIR: torrents listen directory\
TS_TORRENTADDR: torrents peer listen port\
TS_PUBIPV4: the IP addresses as our peers should see them. May differ from the local interfaces due to NAT or other network configurations\
TS_PUBIPV6: the IP addresses as our peers should see them. May differ from the local interfaces due to NAT or other network configurations\
TS_SEARCHWA: disable auth for search torrents if auth is enable
--------
### Docker run example
```
docker run -p 8090:8090 \
-e TS_PORT=8090 \
-e TS_PATH="/opt/torrserver/config" \
-e TS_LOGPATHDIR="/opt/torrserver/log/" \
-e TS_LOGFILE="ts.log" \
-e TS_WEBLOGFILE="tsweb.log" \
-e TS_RDB=true \
-e TS_HTTPAUTH=true \
-e TS_DONTKILL=true \
-e TS_TORRENTSDIR="/opt/torrserver/torrents" \
-e TS_TORRENTADDR=32000 \
-e TS_PUBIPV4=publicIP \
-e TS_PUBIPV6=publicIP \
-e TS_SEARCHWA=true \
yourok/torrserver
```
--------
### Docker compose example
```
version: '3.6'
services:
torrserver:
container_name: torrserver
image: yourok/torrserver
restart: unless-stopped
environment:
- TS_PORT=8090
- TS_PATH=/opt/torrserver/config
- TS_LOGPATHDIR=/opt/torrserver/log
- TS_LOGFILE=ts.log
- TS_WEBLOGFILE=tsweb.log
- TS_RDB=false
- TS_HTTPAUTH=true
- TS_DONTKILL=true
- TS_TORRENTSDIR=/opt/torrserver/torrents
- TS_TORRENTADDR=:32000
- TS_PUBIPV4=publicIP
- TS_PUBIPV6=publicIP
- TS_SEARCHWA=true
ports:
- 8090:8090
volumes:
- ./torrserver/config:/opt/torrserver/config
- ./torrserver/log:/opt/torrserver/log
- ./torrserver/torrents:/opt/torrserver/torrents
```

49
docker/start.sh Normal file
View File

@@ -0,0 +1,49 @@
#!/bin/sh
case $(uname -m) in
i386) architecture="386" ;;
i686) architecture="386" ;;
x86_64) architecture="amd64" ;;
aarch64) architecture="arm64" ;;
armv7|armv7l) architecture="arm7" ;;
armv6|armv6l) architecture="arm5" ;;
# armv5|armv5l) architecture="arm5" ;;
*) echo "Unsupported Arch. Can't continue."; exit 1 ;;
esac
binName="TorrServer-linux-${architecture}"
mkdir -p /opt/torrserver
cd /opt/torrserver
rm -f ${binName}*
wget -O $binName "https://github.com/YouROK/TorrServer/releases/latest/download/$binName"
chmod +x $binName
FLAGS=""
#sets start flags
[ ! -z "$TS_PORT" ] && echo "TS_PORT: $TS_PORT" && FLAGS="${FLAGS} --port ${TS_PORT}"
[ ! -z "$TS_PATH" ] && echo "TS_PATH: $TS_PATH" && FLAGS="${FLAGS} --path ${TS_PATH}"
[ ! -z "$TS_LOGPATHDIR" ] && echo "TS_LOGPATHDIR: $TS_LOGPATHDIR" && FLAGS="${FLAGS}"
[ ! -z "$TS_LOGFILE" ] && echo "TS_LOGFILE: $TS_LOGPATHDIR/$TS_LOGFILE" && FLAGS="${FLAGS} --logpath $TS_LOGPATHDIR/${TS_LOGFILE}"
[ ! -z "$TS_WEBLOGFILE" ] && echo "TS_WEBLOGFILE: $TS_LOGPATHDIR/$TS_WEBLOGFILE" && FLAGS="${FLAGS} --weblogpath $TS_LOGPATHDIR/${TS_WEBLOGFILE}"
[ ! -z "$TS_RDB" ] | [ "$TS_RDB" = "true" ] && echo "TS_RDB: $TS_RDB" && FLAGS="${FLAGS} --rdb"
[ ! -z "$TS_HTTPAUTH" ] && echo "TS_HTTPAUTH: $TS_HTTPAUTH" && FLAGS="${FLAGS} --httpauth"
[ ! -z "$TS_DONTKILL" ] && echo "TS_DONTKILL: $TS_DONTKILL" && FLAGS="${FLAGS} --dontkill"
[ ! -z "$TS_TORRENTSDIR" ] && echo "TS_TORRENTSDIR: $TS_TORRENTSDIR" && FLAGS="${FLAGS} --torrentsdir ${TS_TORRENTSDIR}"
[ ! -z "$TS_TORRENTADDR" ] && echo "TS_TORRENTADDR: $TS_TORRENTADDR" && FLAGS="${FLAGS} --torrentaddr ${TS_TORRENTADDR}"
[ ! -z "$TS_PUBIPV4" ] && echo "TS_PUBIPV4: $TS_PUBIPV4" && FLAGS="${FLAGS} --pubipv4 ${TS_PUBIPV4}"
[ ! -z "$TS_PUBIPV6" ] && echo "TS_PUBIPV6: $TS_PUBIPV6" && FLAGS="${FLAGS} --pubipv6 ${TS_PUBIPV6}"
[ ! -z "$TS_SEARCHWA" ]&& echo "TS_SEARCHWA: $TS_SEARCHWA" && FLAGS="${FLAGS} --searchwa"
#make directories
[ ! -z "$TS_PATH" ] && [ ! -d "$TS_PATH" ] && mkdir -p $TS_PATH
[ ! -z "$TS_LOGPATHDIR" ] && [ ! -d "$TS_LOGPATHDIR" ] && mkdir -p $TS_LOGPATHDIR
[ ! -z "$TS_TORRENTSDIR" ] && [ ! -d "$TS_TORRENTSDIR" ] && mkdir $TS_TORRENTSDIR
echo "Running with: ${FLAGS}"
export GODEBUG=madvdontneed=1
/opt/torrserver/${binName} ${FLAGS}

View File

@@ -82,11 +82,16 @@ func writeRoute(fname string, fmap map[string]string) {
embedStr := `package template embedStr := `package template
import ( import (
"crypto/md5"
"fmt"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
func RouteWebPages(route *gin.RouterGroup) { func RouteWebPages(route gin.IRouter) {
route.GET("/", func(c *gin.Context) { 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) c.Data(200, "text/html; charset=utf-8", Indexhtml)
}) })
` `
@@ -108,6 +113,9 @@ func RouteWebPages(route *gin.RouterGroup) {
} }
embedStr += ` embedStr += `
route.GET("` + link + `", func(c *gin.Context) { route.GET("` + link + `", func(c *gin.Context) {
etag := fmt.Sprintf("%x", md5.Sum(` + fmap[link] + `))
c.Header("Cache-Control", "public, max-age=31536000")
c.Header("ETag", etag)
c.Data(200, "` + fmime + `", ` + fmap[link] + `) c.Data(200, "` + fmime + `", ` + fmap[link] + `)
}) })
` `

View File

@@ -32,10 +32,10 @@ function killRunning() {
} }
function cleanup() { function cleanup() {
sudo rm -f /Library/LaunchAgents/*torrserver* 1>/dev/null 2>&1 sudo rm -f /Library/LaunchAgents/*torrserver*
sudo rm -f /Library/LaunchDaemons/*torrserver* 1>/dev/null 2>&1 sudo rm -f /Library/LaunchDaemons/*torrserver*
sudo rm -f $HOME/Library/LaunchAgents/*torrserver* 1>/dev/null 2>&1 sudo rm -f $HOME/Library/LaunchAgents/*torrserver*
sudo rm -f $HOME/Library/LaunchDaemons/*torrserver* 1>/dev/null 2>&1 sudo rm -f $HOME/Library/LaunchDaemons/*torrserver*
killRunning killRunning
} }
@@ -54,7 +54,6 @@ function uninstall() {
echo "" echo ""
} }
[[ $lang == "en" ]] && read -p ' Are you shure you want to delete TorrServer? (Yes/No) ' answer_del </dev/tty || read -p ' Вы уверены что хотите удалить программу? (Да/Нет) ' answer_del </dev/tty [[ $lang == "en" ]] && read -p ' Are you shure you want to delete TorrServer? (Yes/No) ' answer_del </dev/tty || read -p ' Вы уверены что хотите удалить программу? (Да/Нет) ' answer_del </dev/tty
read answer_del
if [ "$answer_del" != "${answer_del#[YyДд]}" ]; then if [ "$answer_del" != "${answer_del#[YyДд]}" ]; then
cleanup cleanup
sudo rm -rf $dirInstall sudo rm -rf $dirInstall
@@ -80,6 +79,7 @@ function installTorrServer() {
echo " Устанавливаем TorrServer $(getLatestRelease)" echo " Устанавливаем TorrServer $(getLatestRelease)"
echo "" echo ""
} }
user=$(whoami)
binName="TorrServer-darwin-${architecture}" binName="TorrServer-darwin-${architecture}"
[[ ! -d "$dirInstall" ]] && mkdir -p ${dirInstall} && chmod a+rw ${dirInstall} [[ ! -d "$dirInstall" ]] && mkdir -p ${dirInstall} && chmod a+rw ${dirInstall}
urlBin="https://github.com/YouROK/TorrServer/releases/download/$(getLatestRelease)/${binName}" urlBin="https://github.com/YouROK/TorrServer/releases/download/$(getLatestRelease)/${binName}"
@@ -179,6 +179,7 @@ EOF
sysPath="${HOME}/Library/LaunchAgents" sysPath="${HOME}/Library/LaunchAgents"
[[ ! -d "$sysPath" ]] && mkdir -p ${sysPath} [[ ! -d "$sysPath" ]] && mkdir -p ${sysPath}
cp "$dirInstall/$serviceName.plist" $sysPath cp "$dirInstall/$serviceName.plist" $sysPath
sudo chown $user "$sysPath/$serviceName.plist"
chmod 0644 "$sysPath/$serviceName.plist" chmod 0644 "$sysPath/$serviceName.plist"
launchctl load -w "$sysPath/$serviceName.plist" 1>/dev/null 2>&1 launchctl load -w "$sysPath/$serviceName.plist" 1>/dev/null 2>&1
else else
@@ -211,7 +212,7 @@ EOF
[[ $lang == "en" ]] && echo " Use user \"$isAuthUser\" with password \"$isAuthPass\" for web auth" || echo " Для авторизации введите пользователя $isAuthUser с паролем $isAuthPass" [[ $lang == "en" ]] && echo " Use user \"$isAuthUser\" with password \"$isAuthPass\" for web auth" || echo " Для авторизации введите пользователя $isAuthUser с паролем $isAuthPass"
echo "" echo ""
fi fi
sleep 60 sleep 30
} }
while true; do while true; do

View File

@@ -7,6 +7,7 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"runtime" "runtime"
"strconv"
"strings" "strings"
"time" "time"
@@ -25,12 +26,12 @@ import (
) )
type args struct { 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"` 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."` 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."` 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."` 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"` LogPath string `arg:"-l" help:"server log file path"`
WebLogPath string `arg:"-w" help:"web access log file path"` WebLogPath string `arg:"-w" help:"web access log file path"`
RDB bool `arg:"-r" help:"start in read-only DB mode"` 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"` DontKill bool `arg:"-k" help:"don't kill server on signal"`
UI bool `arg:"-u" help:"open torrserver page in browser"` UI bool `arg:"-u" help:"open torrserver page in browser"`
TorrentsDir string `arg:"-t" help:"autoload torrents from dir"` 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"` PubIPv4 string `arg:"-4" help:"set public IPv4 addr"`
PubIPv6 string `arg:"-6" help:"set public IPv6 addr"` PubIPv6 string `arg:"-6" help:"set public IPv6 addr"`
SearchWA bool `arg:"-s" help:"search without auth"` SearchWA bool `arg:"-s" help:"search without auth"`
MaxSize string `arg:"-m" help:"max allowed stream size (in Bytes)"`
} }
func (args) Version() string { func (args) Version() string {
@@ -104,6 +106,13 @@ func main() {
go watchTDir(params.TorrentsDir) 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) server.Start(params.Port, params.SslPort, params.SslCert, params.SslKey, params.Ssl, params.RDB, params.SearchWA)
log.TLogln(server.WaitServer()) log.TLogln(server.WaitServer())
log.Close() log.Close()

View File

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

View File

@@ -62,7 +62,7 @@ const docTemplate = `{
"parameters": [ "parameters": [
{ {
"type": "string", "type": "string",
"description": "Test file size", "description": "Test file size (in MB)",
"name": "size", "name": "size",
"in": "path", "in": "path",
"required": true "required": true
@@ -98,7 +98,7 @@ const docTemplate = `{
} }
} }
}, },
"/ffp": { "/ffp/{hash}/{id}": {
"get": { "get": {
"description": "Gather informations using ffprobe.", "description": "Gather informations using ffprobe.",
"produces": [ "produces": [
@@ -113,14 +113,14 @@ const docTemplate = `{
"type": "string", "type": "string",
"description": "Torrent hash", "description": "Torrent hash",
"name": "hash", "name": "hash",
"in": "query", "in": "path",
"required": true "required": true
}, },
{ {
"type": "string", "type": "string",
"description": "File index in torrent", "description": "File index in torrent",
"name": "id", "name": "id",
"in": "query", "in": "path",
"required": true "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": { "/msx/imdb": {
"get": { "get": {
"description": "Get MSX IMDB informations.", "description": "Get MSX IMDB informations.",
@@ -191,7 +165,7 @@ const docTemplate = `{
} }
} }
}, },
"/msx/imdb/:id": { "/msx/imdb/{id}": {
"get": { "get": {
"description": "Get MSX IMDB informations.", "description": "Get MSX IMDB informations.",
"produces": [ "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": { "get": {
"description": "Play given torrent referenced by hash.", "description": "Play given torrent referenced by hash.",
"produces": [ "produces": [
@@ -232,21 +232,15 @@ const docTemplate = `{
"type": "string", "type": "string",
"description": "Torrent hash", "description": "Torrent hash",
"name": "hash", "name": "hash",
"in": "query", "in": "path",
"required": true "required": true
}, },
{ {
"type": "string", "type": "string",
"description": "File index in torrent", "description": "File index in torrent",
"name": "id", "name": "id",
"in": "query", "in": "path",
"required": true "required": true
},
{
"type": "boolean",
"description": "Not authenticated",
"name": "not_auth",
"in": "query"
} }
], ],
"responses": { "responses": {
@@ -458,7 +452,7 @@ const docTemplate = `{
}, },
{ {
"type": "string", "type": "string",
"description": "Get m3u from last play", "description": "Get M3U from last played file",
"name": "fromlast", "name": "fromlast",
"in": "query" "in": "query"
}, },
@@ -475,17 +469,10 @@ const docTemplate = `{
"in": "query", "in": "query",
"required": true "required": true
}, },
{
"type": "string",
"description": "File index in torrent",
"name": "poster",
"in": "query",
"required": true
},
{ {
"type": "string", "type": "string",
"description": "Set poster link of torrent", "description": "Set poster link of torrent",
"name": "not_auth", "name": "poster",
"in": "query", "in": "query",
"required": true "required": true
} }

View File

@@ -55,7 +55,7 @@
"parameters": [ "parameters": [
{ {
"type": "string", "type": "string",
"description": "Test file size", "description": "Test file size (in MB)",
"name": "size", "name": "size",
"in": "path", "in": "path",
"required": true "required": true
@@ -91,7 +91,7 @@
} }
} }
}, },
"/ffp": { "/ffp/{hash}/{id}": {
"get": { "get": {
"description": "Gather informations using ffprobe.", "description": "Gather informations using ffprobe.",
"produces": [ "produces": [
@@ -106,14 +106,14 @@
"type": "string", "type": "string",
"description": "Torrent hash", "description": "Torrent hash",
"name": "hash", "name": "hash",
"in": "query", "in": "path",
"required": true "required": true
}, },
{ {
"type": "string", "type": "string",
"description": "File index in torrent", "description": "File index in torrent",
"name": "id", "name": "id",
"in": "query", "in": "path",
"required": true "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": { "/msx/imdb": {
"get": { "get": {
"description": "Get MSX IMDB informations.", "description": "Get MSX IMDB informations.",
@@ -184,7 +158,7 @@
} }
} }
}, },
"/msx/imdb/:id": { "/msx/imdb/{id}": {
"get": { "get": {
"description": "Get MSX IMDB informations.", "description": "Get MSX IMDB informations.",
"produces": [ "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": { "get": {
"description": "Play given torrent referenced by hash.", "description": "Play given torrent referenced by hash.",
"produces": [ "produces": [
@@ -225,21 +225,15 @@
"type": "string", "type": "string",
"description": "Torrent hash", "description": "Torrent hash",
"name": "hash", "name": "hash",
"in": "query", "in": "path",
"required": true "required": true
}, },
{ {
"type": "string", "type": "string",
"description": "File index in torrent", "description": "File index in torrent",
"name": "id", "name": "id",
"in": "query", "in": "path",
"required": true "required": true
},
{
"type": "boolean",
"description": "Not authenticated",
"name": "not_auth",
"in": "query"
} }
], ],
"responses": { "responses": {
@@ -451,7 +445,7 @@
}, },
{ {
"type": "string", "type": "string",
"description": "Get m3u from last play", "description": "Get M3U from last played file",
"name": "fromlast", "name": "fromlast",
"in": "query" "in": "query"
}, },
@@ -468,17 +462,10 @@
"in": "query", "in": "query",
"required": true "required": true
}, },
{
"type": "string",
"description": "File index in torrent",
"name": "poster",
"in": "query",
"required": true
},
{ {
"type": "string", "type": "string",
"description": "Set poster link of torrent", "description": "Set poster link of torrent",
"name": "not_auth", "name": "poster",
"in": "query", "in": "query",
"required": true "required": true
} }

View File

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

View File

@@ -2,51 +2,52 @@ module server
go 1.20 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 ( require (
github.com/agnivade/levenshtein v1.1.1 github.com/agnivade/levenshtein v1.1.1
github.com/alexflint/go-arg v1.4.3 github.com/alexflint/go-arg v1.4.3
github.com/anacrolix/dms v1.6.0 github.com/anacrolix/dms v1.6.0
github.com/anacrolix/log v0.14.5 github.com/anacrolix/log v0.15.0
github.com/anacrolix/missinggo v1.3.0 github.com/anacrolix/missinggo/v2 v2.7.3
github.com/anacrolix/publicip v0.3.0 github.com/anacrolix/publicip v0.3.0
github.com/anacrolix/torrent v1.53.1 github.com/anacrolix/torrent v1.54.1
github.com/gin-contrib/cors v1.4.0 github.com/gin-contrib/cors v1.5.0
github.com/gin-contrib/location v0.0.2 github.com/gin-contrib/location v0.0.2
github.com/gin-gonic/gin v1.9.1 github.com/gin-gonic/gin v1.9.1
github.com/kljensen/snowball v0.8.0 github.com/kljensen/snowball v0.9.0
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/swaggo/files v1.0.1 github.com/swaggo/files v1.0.1
github.com/swaggo/gin-swagger v1.6.0 github.com/swaggo/gin-swagger v1.6.0
github.com/swaggo/swag v1.16.2 github.com/swaggo/swag v1.16.3
go.etcd.io/bbolt v1.3.8 go.etcd.io/bbolt v1.3.9
golang.org/x/image v0.14.0 golang.org/x/exp v0.0.0-20240222234643-814bf88cf225
golang.org/x/time v0.4.0 golang.org/x/image v0.15.0
golang.org/x/time v0.5.0
gopkg.in/vansante/go-ffprobe.v2 v2.1.1 gopkg.in/vansante/go-ffprobe.v2 v2.1.1
) )
require ( require (
github.com/KyleBanks/depth v1.2.1 // indirect 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/alecthomas/atomic v0.1.0-alpha2 // indirect
github.com/alexflint/go-scalar v1.2.0 // indirect github.com/alexflint/go-scalar v1.2.0 // indirect
github.com/anacrolix/chansync v0.3.0 // indirect github.com/anacrolix/chansync v0.4.0 // indirect
github.com/anacrolix/dht/v2 v2.21.0 // indirect github.com/anacrolix/dht/v2 v2.21.1 // indirect
github.com/anacrolix/ffprobe v1.1.0 // 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/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/multiless v0.3.1-0.20221221005021-2d12701f83f7 // indirect
github.com/anacrolix/stm v0.5.0 // indirect github.com/anacrolix/stm v0.5.0 // indirect
github.com/anacrolix/sync v0.5.1 // 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/anacrolix/utp v0.2.0 // indirect
github.com/benbjohnson/immutable v0.4.3 // 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/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/base64x v0.0.0-20230717121745-296ad89f973d // indirect
github.com/chenzhuoyu/iasm v0.9.1 // indirect github.com/chenzhuoyu/iasm v0.9.1 // indirect
github.com/davecgh/go-spew v1.1.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/frankban/quicktest v1.14.6 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-openapi/jsonpointer v0.20.0 // indirect github.com/go-openapi/jsonpointer v0.20.2 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/jsonreference v0.20.4 // indirect
github.com/go-openapi/spec v0.20.9 // indirect github.com/go-openapi/spec v0.20.14 // indirect
github.com/go-openapi/swag v0.22.4 // indirect github.com/go-openapi/swag v0.22.9 // indirect
github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.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/goccy/go-json v0.10.2 // indirect
github.com/google/btree v1.1.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/huandu/xstrings v1.4.0 // indirect
github.com/josharian/intern v1.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.6 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/leodido/go-urn v1.2.4 // indirect github.com/leodido/go-urn v1.4.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mschoch/smat v0.2.0 // 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/rs/dnscache v0.0.0-20230804202142-fc85eb664529 // indirect
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46 // indirect github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.11 // indirect github.com/ugorji/go/codec v1.2.12 // indirect
golang.org/x/arch v0.6.0 // indirect golang.org/x/arch v0.7.0 // indirect
golang.org/x/crypto v0.15.0 // indirect golang.org/x/crypto v0.19.0 // indirect
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect golang.org/x/net v0.21.0 // indirect
golang.org/x/net v0.18.0 // indirect golang.org/x/sync v0.6.0 // indirect
golang.org/x/sync v0.5.0 // indirect golang.org/x/sys v0.17.0 // indirect
golang.org/x/sys v0.14.0 // indirect
golang.org/x/text v0.14.0 // indirect golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.15.0 // indirect golang.org/x/tools v0.18.0 // indirect
google.golang.org/protobuf v1.31.0 // indirect google.golang.org/protobuf v1.32.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // 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.7/go.mod h1:8khRDP4HmeXns4xIj9oGrKSz7XTQiJx2zgh7AcNke4w=
github.com/RoaringBitmap/roaring v0.4.17/go.mod h1:D3qVegWTmfCaX4Bl5CrBE9hfrSrrXIr8KVNvRsDi1NI= 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 v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo=
github.com/RoaringBitmap/roaring v1.6.0 h1:dc7kRiroETgJcHhWX6BerXkZz2b3JgLGg9nTURJL/og= github.com/RoaringBitmap/roaring v1.9.0 h1:lwKhr90/j0jVXJyh5X+vQN1VVn77rQFfYnh6RDRGCcE=
github.com/RoaringBitmap/roaring v1.6.0/go.mod h1:plvDsJQpxOC5bw8LRteu/MLWHsHez/3y6cubLI4/1yE= 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/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/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8= 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.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 h1:WR7JPKkeNpnYIOfHRa7ivM21aWAdHD0gEWHCx+WQBRw=
github.com/alexflint/go-scalar v1.2.0/go.mod h1:LoFvNMqS1CPrMVltza4LvnGKhaSpc3oyLEBUZVhhS2o= 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.4.0 h1:Md0HM7zYCAO4KwNwgcIRgxNsMxiRuk7D1Ha0Uo+2y60=
github.com/anacrolix/chansync v0.3.0/go.mod h1:DZsatdsdXxD0WiwcGl0nJVwyjCKMDv+knl1q2iBjA2k= github.com/anacrolix/chansync v0.4.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.1 h1:s1rKkfLLcmBHKv4v/mtMkIeHIEptzEFiB6xVu54+5/o=
github.com/anacrolix/dht/v2 v2.21.0/go.mod h1:SDGC+sEs1pnO2sJGYuhvIis7T8749dDHNfcjtdH4e3g= 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 h1:v2g1Y+Fc/ICSEc+7M6B92oFcfcqa5LXYPhE4Hcm5tVA=
github.com/anacrolix/dms v1.6.0/go.mod h1:5fAMpBcPFG4WQFh91zhf2E7/KYZ3/WmmRAf/WMoL0Q0= 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= 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 h1:eKBudnERW9zRJ0+ge6FzkQ0pWLyq142+FJrwRwSRMT4=
github.com/anacrolix/ffprobe v1.1.0/go.mod h1:MXe+zG/RRa5OdIf5+VYYfS/CfsSqOH7RrvGIqJBzqhI= 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-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.1 h1:4WVhK6iLb3UAAAQP6I3uYlMOHcp9FqJC9j4n81Wv9Ks=
github.com/anacrolix/generics v0.0.0-20230911070922-5dd7545c6b13/go.mod h1:ff2rHB/joTV03aMSSn/AZNnaIpUw0h3njetGsaXcMy8= 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.3.0/go.mod h1:lWvLTqzAnCWPJA08T2HCstZi0L1y2Wyvm3FJgwU9jwU=
github.com/anacrolix/log v0.6.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.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.2/go.mod h1:1OmJESOtxQGNMlUO5rcv96Vpp9mfMqXXbe2RdinFLdY=
github.com/anacrolix/log v0.14.5 h1:OkMjBquVSRb742LkecSGDGaGpNoSrw4syRIm0eRdmrg= github.com/anacrolix/log v0.15.0 h1:QIhbW5NDUL6P1Aml+ZfdaXJ+QFAnrO0K1EpFYs/nh9M=
github.com/anacrolix/log v0.14.5/go.mod h1:1OmJESOtxQGNMlUO5rcv96Vpp9mfMqXXbe2RdinFLdY= 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.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.1.2-0.20190815015349-b888af804467/go.mod h1:MBJu3Sk/k3ZfGYcS7z18gwfu72Ey/xopPFJJbTi5yIo=
github.com/anacrolix/missinggo v1.2.1/go.mod h1:J5cMhif8jPmFoC3+Uvob3OXXNIhOUikzMt+uUjeM21Y= 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 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.0.0/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pmhJXOKKCHw=
github.com/anacrolix/tagflag v1.1.0/go.mod h1:Scxs9CV10NQatSmbyjqmqmeQNwGzlNe0CMUMIxqHIG8= 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.4 h1:+2t2KA6QOhm/49zeNyeVwDu1ZYS9dB9wfxyVvh/wk7U=
github.com/anacrolix/upnp v0.1.3/go.mod h1:Qyhbqo69gwNWvEk1xNTXsS5j7hMHef9hdr984+9fIic= 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 h1:65Cdmr6q9WSw2KsM+rtJFu7rqDzLl2bdysf4KlNPcFI=
github.com/anacrolix/utp v0.2.0/go.mod h1:HGk4GYQw1O/3T1+yhqT/F6EcBd+AAwlo9dYErNy7mj8= 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= 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 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.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= 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.12.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/bits-and-blooms/bitset v1.11.0 h1:RMyy2mBBShArUAhfVRZJ2xyBO58KCBCtZFShw3umo6k= github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE=
github.com/bits-and-blooms/bitset v1.11.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= 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-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-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 h1:GKTyiRCL6zVf5wWaqKnf+7Qs6GbEPfd4iMOitWzXJx8=
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8/go.mod h1:spo1JLcs67NmW1aVLEgtA8Yy1elc+X8y5SRW1sFW4Og= 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.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.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=
github.com/bytedance/sonic v1.10.2 h1:GQebETVBxYB7JGWJtLBi07OVzWwt+8dWA00gEVW2ZFE= github.com/bytedance/sonic v1.11.1 h1:JC0+6c9FoWYYxakaoa+c5QTtJeiSZNeByOBhXtAFSn4=
github.com/bytedance/sonic v1.10.2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= 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/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-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= 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/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 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= 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.5.0 h1:DgGKV7DDoOn36DFkNtbHrjoRiT5ExCe+PC9/xp7aKvk=
github.com/gin-contrib/cors v1.4.0/go.mod h1:bs9pNM0x/UsmHPBWT2xZz9ROh8xYjYkiURUfmBoMlcs= 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 h1:QZKh1+K/LLR4KG/61eIO3b7MLuKi8tytQhV6texLgP4=
github.com/gin-contrib/location v0.0.2/go.mod h1:NGoidiRlf0BlA/VKSVp+g3cuSMeTmip/63PhEjRhUAc= 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 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= 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.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 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= 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= 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-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.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= 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.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs=
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU=
github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ= github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4=
github.com/go-openapi/jsonpointer v0.20.0/go.mod h1:6PGzBjjIIumbLYysB73Klnms1mwnU4G3YHOECG3CedA= github.com/go-openapi/spec v0.20.14 h1:7CBlRnw+mtjFGlPDRZmAMnq35cRzI91xj03HVyUi/Do=
github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= github.com/go-openapi/spec v0.20.14/go.mod h1:8EOhTpBoFiask8rrgwbLC3zmJfz4zsCUueRuPM6GNkw=
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= github.com/go-openapi/swag v0.22.9 h1:XX2DssF+mQKM2DHsbgZK74y/zj4mo9I99+89xUmuZCE=
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= github.com/go-openapi/swag v0.22.9/go.mod h1:3/OXnFfnMAwBD099SwYRk7GD3xOrr1iL7d/XNLXVVwE=
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-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= 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.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 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= 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.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 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= 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.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.18.0 h1:BvolUXjp4zuvkZ5YN5t7ebzbhlUtPsPm2S9NAZ5nl9U=
github.com/go-playground/validator/v10 v10.16.0 h1:x+plE831WK4vaKHO/jpgUGsvLKIqRRkz6M78GuJAfGE= github.com/go-playground/validator/v10 v10.18.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/go-playground/validator/v10 v10.16.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 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 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 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.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-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.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.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.1/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= 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.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.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.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.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/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-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/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/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/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.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.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/kljensen/snowball v0.8.0 h1:WU4cExxK6sNW33AiGdbn4e8RvloHrhkAssu2mVJ11kg= github.com/kljensen/snowball v0.9.0 h1:OpXkQBcic6vcPG+dChOGLIA/GNuVg47tbbIJ2s7Keas=
github.com/kljensen/snowball v0.8.0/go.mod h1:OGo5gFWjaeXqCu4iIrMl5OYip9XUJHGOU5eSkPjVg2A= 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/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.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/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.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.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= 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/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.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= 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.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
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/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= 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.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 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 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/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/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/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.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.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/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/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.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI=
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= 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/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-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= 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/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.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/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.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.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.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 h1:18kd+8ZUlt/ARXhljq+14TwAoKa61q6dX8jtwOf6DH8=
github.com/rs/dnscache v0.0.0-20230804202142-fc85eb664529/go.mod h1:qe5TWALJ8/a1Lqznoc5BDHpYX/8HU60Hm2AwRmqzxqA= 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= 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.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.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.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.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.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.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/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 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE=
github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg= 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 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M=
github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo= 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.3 h1:PnCYjPCah8FK4I26l2F/KQ4yz3sILcVUN3cTlBFA9Pg=
github.com/swaggo/swag v1.16.2/go.mod h1:6YzXnDcpr0767iOejs318CwYkCQqyGer6BizOg03f+E= 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.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.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
github.com/tinylib/msgp v1.1.2/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.16 h1:jEXIkdPKIOerO+8b/12wTvEoLnjGFcHX7dMitTmrWH0=
github.com/tsynik/torrent v1.2.11/go.mod h1:AjuETm1Xae+Vk31UrvrSrb29bBunwMKGZLXK6T+AgPo= 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 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= 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.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.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.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/willf/bitset v1.1.9/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= 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/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.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 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.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI=
go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= 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.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.20.2/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= 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.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.6.0 h1:S0JTfE48HbRj80+4tbvZDYsJ3tGv6BUU3XxyZ7CirAc= golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc=
golang.org/x/arch v0.6.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= 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-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-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-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.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.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= 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-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-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-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ=
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
golang.org/x/image v0.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4= golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8=
golang.org/x/image v0.14.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE= 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-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-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 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.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.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.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-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-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/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-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.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.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= 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-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 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= 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-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-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.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.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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-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-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/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-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-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-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-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-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-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-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.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 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-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.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.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.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 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= 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.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= 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-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-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/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.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.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.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8= golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= 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-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-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/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 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.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.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.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 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 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/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 h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 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= 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.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.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.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-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 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 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() l.Close()
} }
if err != nil { 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) os.Exit(1)
} }
} }
@@ -59,7 +59,7 @@ func Start(port, sslport, sslCert, sslKey string, sslEnabled, roSets, searchWA b
l.Close() l.Close()
} }
if err != nil { 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) os.Exit(1)
} }
// remove old disk caches // remove old disk caches

View File

@@ -15,7 +15,7 @@ type TDB struct {
db *bolt.DB 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}) db, err := bolt.Open(filepath.Join(Path, "config.db"), 0o666, &bolt.Options{Timeout: 5 * time.Second})
if err != nil { if err != nil {
log.TLogln(err) log.TLogln(err)
@@ -68,10 +68,6 @@ func (v *TDB) Get(xpath, name string) []byte {
} }
func (v *TDB) Set(xpath, name string, value []byte) { func (v *TDB) Set(xpath, name string, value []byte) {
if ReadOnly {
return
}
spath := strings.Split(xpath, "/") spath := strings.Split(xpath, "/")
if len(spath) == 0 { if len(spath) == 0 {
return return
@@ -139,10 +135,6 @@ func (v *TDB) List(xpath string) []string {
} }
func (v *TDB) Rem(xpath, name string) { func (v *TDB) Rem(xpath, name string) {
if ReadOnly {
return
}
spath := strings.Split(xpath, "/") spath := strings.Split(xpath, "/")
if len(spath) == 0 { if len(spath) == 0 {
return 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 ( import (
"encoding/binary" "encoding/binary"
"encoding/json"
"errors"
"fmt" "fmt"
"os" "os"
"path/filepath" "path/filepath"
"reflect"
bolt "go.etcd.io/bbolt"
"server/log" "server/log"
"server/web/api/utils" "server/web/api/utils"
bolt "go.etcd.io/bbolt"
) )
var dbTorrentsName = []byte("Torrents") var dbTorrentsName = []byte("Torrents")
@@ -22,7 +26,8 @@ type torrentOldDB struct {
Timestamp int64 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) { if _, err := os.Lstat(filepath.Join(Path, "torrserver.db")); os.IsNotExist(err) {
return return
} }
@@ -100,3 +105,87 @@ func Migrate() {
func b2i(v []byte) int64 { func b2i(v []byte) int64 {
return int64(binary.BigEndian.Uint64(v)) 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 package settings
import ( import (
"fmt"
"os" "os"
"path/filepath" "path/filepath"
@@ -8,7 +9,7 @@ import (
) )
var ( var (
tdb *TDB tdb TorrServerDB
Path string Path string
Port string Port string
Ssl bool Ssl bool
@@ -19,18 +20,40 @@ var (
PubIPv4 string PubIPv4 string
PubIPv6 string PubIPv6 string
TorAddr string TorAddr string
MaxSize int64
) )
func InitSets(readOnly, searchWA bool) { func InitSets(readOnly, searchWA bool) {
ReadOnly = readOnly ReadOnly = readOnly
SearchWA = searchWA SearchWA = searchWA
tdb = NewTDB()
if tdb == nil { bboltDB := NewTDB()
log.TLogln("Error open db:", filepath.Join(Path, "config.db")) 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) os.Exit(1)
} }
loadBTSets() loadBTSets()
Migrate() Migrate1()
} }
func CloseDB() { 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) { func RemTorrent(hashHex string) {
if sets.ReadOnly {
log.TLogln("API RemTorrent: Read-only DB mode!", hashHex)
return
}
hash := metainfo.NewHashFromHex(hashHex) hash := metainfo.NewHashFromHex(hashHex)
if sets.BTsets.UseDisk && hashHex != "" && hashHex != "/" { if bts.RemoveTorrent(hash) {
name := filepath.Join(sets.BTsets.TorrentsSavePath, hashHex) if sets.BTsets.UseDisk && hashHex != "" && hashHex != "/" {
ff, _ := os.ReadDir(name) name := filepath.Join(sets.BTsets.TorrentsSavePath, hashHex)
for _, f := range ff { ff, _ := os.ReadDir(name)
os.Remove(filepath.Join(name, f.Name())) for _, f := range ff {
} os.Remove(filepath.Join(name, f.Name()))
err := os.Remove(name) }
if err != nil { err := os.Remove(name)
log.TLogln("Error remove cache:", err) if err != nil {
log.TLogln("Error remove cache:", err)
}
} }
} }
bts.RemoveTorrent(hash)
RemTorrentDB(hash) RemTorrentDB(hash)
} }
@@ -199,6 +204,7 @@ func DropTorrent(hashHex string) {
func SetSettings(set *sets.BTSets) { func SetSettings(set *sets.BTSets) {
if sets.ReadOnly { if sets.ReadOnly {
log.TLogln("API SetSettings: Read-only DB mode!")
return return
} }
sets.SetBTSets(set) sets.SetBTSets(set)
@@ -215,6 +221,7 @@ func SetSettings(set *sets.BTSets) {
func SetDefSettings() { func SetDefSettings() {
if sets.ReadOnly { if sets.ReadOnly {
log.TLogln("API SetDefSettings: Read-only DB mode!")
return return
} }
sets.SetDefaultConfig() sets.SetDefaultConfig()

View File

@@ -88,14 +88,13 @@ func (bt *BTServer) configure(ctx context.Context) {
upnpID := "TorrServer/" + version.Version upnpID := "TorrServer/" + version.Version
cliVers := userAgent cliVers := userAgent
// bt.config.AlwaysWantConns = true
bt.config.Debug = settings.BTsets.EnableDebug bt.config.Debug = settings.BTsets.EnableDebug
bt.config.DisableIPv6 = !settings.BTsets.EnableIPv6 bt.config.DisableIPv6 = !settings.BTsets.EnableIPv6
bt.config.DisableTCP = settings.BTsets.DisableTCP bt.config.DisableTCP = settings.BTsets.DisableTCP
bt.config.DisableUTP = settings.BTsets.DisableUTP bt.config.DisableUTP = settings.BTsets.DisableUTP
// https://github.com/anacrolix/torrent/issues/703 // https://github.com/anacrolix/torrent/issues/703
// bt.config.DisableWebtorrent = true // TODO: check memory usage // bt.config.DisableWebtorrent = true // NE
// bt.config.DisableWebseeds = false // bt.config.DisableWebseeds = false // NE
bt.config.NoDefaultPortForwarding = settings.BTsets.DisableUPNP bt.config.NoDefaultPortForwarding = settings.BTsets.DisableUPNP
bt.config.NoDHT = settings.BTsets.DisableDHT bt.config.NoDHT = settings.BTsets.DisableDHT
bt.config.DisablePEX = settings.BTsets.DisablePEX 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.EstablishedConnsPerTorrent = settings.BTsets.ConnectionsLimit
bt.config.TotalHalfOpenConns = 500 bt.config.TotalHalfOpenConns = 500
// Encryption/Obfuscation // Encryption/Obfuscation
bt.config.EncryptionPolicy = torrent.EncryptionPolicy{ bt.config.EncryptionPolicy = torrent.EncryptionPolicy{ // OE
ForceEncryption: settings.BTsets.ForceEncrypt, ForceEncryption: settings.BTsets.ForceEncrypt, // OE
} } // OE
// bt.config.HeaderObfuscationPolicy = torrent.HeaderObfuscationPolicy{ // bt.config.HeaderObfuscationPolicy = torrent.HeaderObfuscationPolicy{ // NE
// RequirePreferred: settings.BTsets.ForceEncrypt, // RequirePreferred: settings.BTsets.ForceEncrypt, // NE
// Preferred: true, // Preferred: true, // NE
// } // } // NE
if settings.BTsets.DownloadRateLimit > 0 { if settings.BTsets.DownloadRateLimit > 0 {
bt.config.DownloadRateLimiter = utils.Limit(settings.BTsets.DownloadRateLimit * 1024) 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) log.Println("Set listen port", settings.BTsets.PeersListenPort)
bt.config.ListenPort = settings.BTsets.PeersListenPort bt.config.ListenPort = settings.BTsets.PeersListenPort
} else { } 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)") 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 return list
} }
func (bt *BTServer) RemoveTorrent(hash torrent.InfoHash) { func (bt *BTServer) RemoveTorrent(hash torrent.InfoHash) bool {
if torr, ok := bt.torrents[hash]; ok { if torr, ok := bt.torrents[hash]; ok {
torr.Close() return torr.Close()
} }
return false
} }
func isPrivateIP(ip net.IP) bool { func isPrivateIP(ip net.IP) bool {

View File

@@ -62,7 +62,7 @@ func (t *Torrent) Preload(index int, size int64) {
// Запуск лога в отдельном потоке // Запуск лога в отдельном потоке
go func() { go func() {
for t.Stat == state.TorrentPreload { 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) log.TLogln("Preload:", stat)
t.AddExpiredTime(time.Second * time.Duration(settings.BTsets.TorrentDisconnectTimeout)) t.AddExpiredTime(time.Second * time.Duration(settings.BTsets.TorrentDisconnectTimeout))
time.Sleep(time.Second) time.Sleep(time.Second)
@@ -158,7 +158,7 @@ func (t *Torrent) Preload(index int, size int64) {
wg.Wait() 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 { 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) 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 { func (c *Cache) Readers() int {
if c == nil { if c == nil {
return 0 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) { func (s *Storage) OpenTorrent(info *metainfo.Info, infoHash metainfo.Hash) (ts.TorrentImpl, error) {
// capFunc := func() (int64, bool) { // capFunc := func() (int64, bool) { // NE
// return s.capacity, true // return s.capacity, true // NE
// } // } // NE
s.mu.Lock() s.mu.Lock()
defer s.mu.Unlock() defer s.mu.Unlock()
ch := NewCache(s.capacity, s) ch := NewCache(s.capacity, s)
ch.Init(info, infoHash) ch.Init(info, infoHash)
s.caches[infoHash] = ch s.caches[infoHash] = ch
return ch, nil return ch, nil // OE
// return ts.TorrentImpl{ // return ts.TorrentImpl{ // NE
// Piece: ch.Piece, // Piece: ch.Piece, // NE
// Close: ch.Close, // Close: ch.Close, // NE
// Capacity: &capFunc, // Capacity: &capFunc, // NE
// }, nil // }, nil // NE
} }
func (s *Storage) CloseHash(hash metainfo.Hash) { func (s *Storage) CloseHash(hash metainfo.Hash) {

View File

@@ -10,7 +10,7 @@ import (
"time" "time"
"github.com/anacrolix/dms/dlna" "github.com/anacrolix/dms/dlna"
"github.com/anacrolix/missinggo/httptoo" "github.com/anacrolix/missinggo/v2/httptoo"
"github.com/anacrolix/torrent" "github.com/anacrolix/torrent"
mt "server/mimetype" mt "server/mimetype"
@@ -47,6 +47,10 @@ func (t *Torrent) Stream(fileID int, req *http.Request, resp http.ResponseWriter
if file == nil { if file == nil {
return fmt.Errorf("file with id %v not found", fileID) 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) reader := t.NewReader(file)

View File

@@ -6,6 +6,8 @@ import (
"sync" "sync"
"time" "time"
utils2 "server/utils"
"github.com/anacrolix/torrent" "github.com/anacrolix/torrent"
"github.com/anacrolix/torrent/metainfo" "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.Stat = state.TorrentClosed
t.bt.mu.Lock() t.bt.mu.Lock()
@@ -274,6 +279,7 @@ func (t *Torrent) Close() {
t.bt.mu.Unlock() t.bt.mu.Unlock()
t.drop() t.drop()
return true
} }
func (t *Torrent) Status() *state.TorrentStatus { func (t *Torrent) Status() *state.TorrentStatus {
@@ -329,7 +335,7 @@ func (t *Torrent) Status() *state.TorrentStatus {
files := t.Files() files := t.Files()
sort.Slice(files, func(i, j int) bool { 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 { for i, f := range files {
st.FileStats = append(st.FileStats, &state.TorrentFileStat{ st.FileStats = append(st.FileStats, &state.TorrentFileStat{

View File

@@ -3,6 +3,8 @@ package utils
import ( import (
"fmt" "fmt"
"strconv" "strconv"
"strings"
"unicode"
) )
const ( const (
@@ -46,3 +48,52 @@ func Format(b float64) string {
return fmt.Sprintf("%.2f%s", value, multiple) 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" // "github.com/anacrolix/torrent"
) )
const Version = "MatriX.127.2" const Version = "MatriX.130"
func GetTorrentVersion() string { func GetTorrentVersion() string {
bi, ok := debug.ReadBuildInfo() bi, ok := debug.ReadBuildInfo()

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,9 @@
package api package api
import ( import (
config "server/settings"
"server/web/auth"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
@@ -8,15 +11,17 @@ type requestI struct {
Action string `json:"action,omitempty"` Action string `json:"action,omitempty"`
} }
func SetupRoute(route *gin.RouterGroup) { func SetupRoute(route gin.IRouter) {
route.GET("/shutdown", shutdown) authorized := route.Group("/", auth.CheckAuth())
route.POST("/settings", settings) authorized.GET("/shutdown", shutdown)
route.POST("/torrents", torrents) authorized.POST("/settings", settings)
route.POST("/torrent/upload", torrentUpload)
route.POST("/cache", cache) authorized.POST("/torrents", torrents)
authorized.POST("/torrent/upload", torrentUpload)
authorized.POST("/cache", cache)
route.HEAD("/stream", stream) route.HEAD("/stream", stream)
route.HEAD("/stream/*fname", stream) route.HEAD("/stream/*fname", stream)
@@ -27,15 +32,19 @@ func SetupRoute(route *gin.RouterGroup) {
route.HEAD("/play/:hash/:id", play) route.HEAD("/play/:hash/:id", play)
route.GET("/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", playList)
route.GET("/playlist/*fname", playList) // Is this endpoint still needed ? `fname` is never used in handler 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 stat query string false "Get statistics from torrent"
// @Param save query string false "Should save torrent" // @Param save query string false "Should save torrent"
// @Param m3u query string false "Get torrent as M3U playlist" // @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 play query string false "Start stream torrent"
// @Param title query string true "Set title of torrent" // @Param title query string true "Set title of torrent"
// @Param poster query string true "File index in torrent" // @Param poster query string true "Set poster link of torrent"
// @Param not_auth query string true "Set poster link of torrent"
// //
// @Produce application/octet-stream // @Produce application/octet-stream
// @Success 200 "Data returned according to query" // @Success 200 "Data returned according to query"
@@ -62,7 +61,7 @@ func stream(c *gin.Context) {
title := c.Query("title") title := c.Query("title")
poster := c.Query("poster") poster := c.Query("poster")
data := "" data := ""
notAuth := c.GetBool("not_auth") notAuth := c.GetBool("auth_required") && c.GetString(gin.AuthUserKey) == ""
if notAuth && (play || m3u) { if notAuth && (play || m3u) {
streamNoAuth(c) streamNoAuth(c)

View File

@@ -73,6 +73,10 @@ func torrents(c *gin.Context) {
{ {
dropTorrent(req, c) dropTorrent(req, c)
} }
case "wipe":
{
wipeTorrents(req, c)
}
} }
} }
@@ -188,3 +192,16 @@ func dropTorrent(req torrReqJS, c *gin.Context) {
torr.DropTorrent(req.Hash) torr.DropTorrent(req.Hash)
c.Status(200) 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" "net/http"
"os" "os"
"path/filepath" "path/filepath"
"reflect"
"strings"
"unsafe" "unsafe"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
@@ -16,15 +14,15 @@ import (
"server/settings" "server/settings"
) )
func SetupAuth(engine *gin.Engine) *gin.RouterGroup { func SetupAuth(engine *gin.Engine) {
if !settings.HttpAuth { if !settings.HttpAuth {
return nil return
} }
accs := getAccounts() accs := getAccounts()
if accs == nil { if accs == nil {
return nil return
} }
return engine.Group("/", BasicAuth(accs)) engine.Use(BasicAuth(accs))
} }
func getAccounts() gin.Accounts { func getAccounts() gin.Accounts {
@@ -61,21 +59,27 @@ func (a authPairs) searchCredential(authValue string) (string, bool) {
func BasicAuth(accounts gin.Accounts) gin.HandlerFunc { func BasicAuth(accounts gin.Accounts) gin.HandlerFunc {
pairs := processAccounts(accounts) pairs := processAccounts(accounts)
return func(c *gin.Context) { return func(c *gin.Context) {
c.Set("auth_required", true)
user, found := pairs.searchCredential(c.Request.Header.Get("Authorization")) user, found := pairs.searchCredential(c.Request.Header.Get("Authorization"))
if !found { // always accessible if found {
if strings.HasPrefix(c.FullPath(), "/stream") || c.Set(gin.AuthUserKey, user)
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) func CheckAuth() gin.HandlerFunc {
return return func(c *gin.Context) {
} if !settings.HttpAuth {
c.Header("WWW-Authenticate", "Basic realm=Authorization Required")
c.AbortWithStatus(http.StatusUnauthorized)
return 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) { func StringToBytes(s string) (b []byte) {
sh := *(*reflect.StringHeader)(unsafe.Pointer(&s)) return unsafe.Slice(unsafe.StringData(s), len(s))
bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
bh.Data, bh.Len, bh.Cap = sh.Data, sh.Len, sh.Len
return b
} }

View File

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

View File

@@ -6,13 +6,27 @@ import (
"server/settings" "server/settings"
"server/torr" "server/torr"
"server/web/auth"
"server/web/pages/template" "server/web/pages/template"
"golang.org/x/exp/slices"
) )
func SetupRoute(route *gin.RouterGroup) { func SetupRoute(route gin.IRouter) {
template.RouteWebPages(route) authorized := route.Group("/", auth.CheckAuth())
route.GET("/stat", statPage)
route.GET("/magnets", getTorrents) 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 // stat godoc

View File

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

View File

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

View File

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

View File

@@ -85,13 +85,16 @@ export default function AboutDialog() {
<LinkComponent name='tw1cker' link='https://github.com/Nemiroff' /> <LinkComponent name='tw1cker' link='https://github.com/Nemiroff' />
<LinkComponent name='SpAwN_LMG' link='https://github.com/spawnlmg' /> <LinkComponent name='SpAwN_LMG' link='https://github.com/spawnlmg' />
<LinkComponent name='damiva' link='https://github.com/damiva' /> <LinkComponent name='damiva' link='https://github.com/damiva' />
<LinkComponent name='Vladlenas' link='https://github.com/vladlenas' />
<LinkComponent name='Anton Potekhin' link='https://github.com/Anton111111' /> <LinkComponent name='Anton Potekhin' link='https://github.com/Anton111111' />
<LinkComponent name='FaintGhost' link='https://github.com/FaintGhost' /> <LinkComponent name='FaintGhost' link='https://github.com/FaintGhost' />
<LinkComponent name='TopperBG' link='https://github.com/TopperBG' /> <LinkComponent name='TopperBG' link='https://github.com/TopperBG' />
<LinkComponent name='FaintGhost' link='https://github.com/FaintGhost' /> <LinkComponent name='Evgeni' link='https://github.com/lieranderl' />
<LinkComponent name='lieranderl' link='https://github.com/lieranderl' />
<LinkComponent name='cocool97' link='https://github.com/cocool97' /> <LinkComponent name='cocool97' link='https://github.com/cocool97' />
<LinkComponent name='shadeov' link='https://github.com/shadeov' /> <LinkComponent name='shadeov' link='https://github.com/shadeov' />
<LinkComponent name='Pavel' link='https://github.com/butaford' />
<LinkComponent name='Alexey Filimonov' link='https://github.com/filimonic' />
<LinkComponent name='Viacheslav Evseev' link='https://github.com/leporel' />
</div> </div>
</Section> </Section>
</div> </div>

View File

@@ -39,7 +39,11 @@ export default function LeftSideComponent({
} }
const [isTorrentSourceActive, setIsTorrentSourceActive] = useState(false) const [isTorrentSourceActive, setIsTorrentSourceActive] = useState(false)
const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop: handleCapture, accept: '.torrent' }) const { getRootProps, getInputProps, isDragActive } = useDropzone({
onDrop: handleCapture,
accept: '.torrent',
multiple: false,
})
const handleTorrentSourceChange = ({ target: { value } }) => setTorrentSource(value) const handleTorrentSourceChange = ({ target: { value } }) => setTorrentSource(value)

View File

@@ -1,12 +1,14 @@
import { useState } from 'react' import { useState } from 'react'
import { Button, DialogActions, DialogTitle, ListItemIcon, ListItemText } from '@material-ui/core' import { Button, DialogActions, DialogTitle, ListItemIcon, ListItemText } from '@material-ui/core'
import { StyledDialog, StyledMenuButtonWrapper } from 'style/CustomMaterialUiStyles' import { StyledDialog, StyledMenuButtonWrapper } from 'style/CustomMaterialUiStyles'
import { PowerSettingsNew as PowerSettingsNewIcon } from '@material-ui/icons' import { PowerSettingsNew as PowerSettingsNewIcon, PowerOff as PowerOffIcon } from '@material-ui/icons'
import { shutdownHost } from 'utils/Hosts' import { shutdownHost } from 'utils/Hosts'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { isStandaloneApp } from 'utils/Utils' import { isStandaloneApp } from 'utils/Utils'
import useOnStandaloneAppOutsideClick from 'utils/useOnStandaloneAppOutsideClick' import useOnStandaloneAppOutsideClick from 'utils/useOnStandaloneAppOutsideClick'
import UnsafeButton from './UnsafeButton'
export default function CloseServer({ isOffline, isLoading }) { export default function CloseServer({ isOffline, isLoading }) {
const { t } = useTranslation() const { t } = useTranslation()
const [open, setOpen] = useState(false) const [open, setOpen] = useState(false)
@@ -41,7 +43,9 @@ export default function CloseServer({ isOffline, isLoading }) {
{t('Cancel')} {t('Cancel')}
</Button> </Button>
<Button <UnsafeButton
timeout={5}
startIcon={<PowerOffIcon />}
variant='contained' variant='contained'
onClick={() => { onClick={() => {
fetch(shutdownHost()) fetch(shutdownHost())
@@ -51,7 +55,7 @@ export default function CloseServer({ isOffline, isLoading }) {
autoFocus autoFocus
> >
{t('TurnOff')} {t('TurnOff')}
</Button> </UnsafeButton>
</DialogActions> </DialogActions>
</StyledDialog> </StyledDialog>
</> </>

View File

@@ -12,6 +12,7 @@ const playableExtList = [
'avchd', 'avchd',
'avi', 'avi',
'drc', 'drc',
'dv',
'flv', 'flv',
'iso', 'iso',
'm2v', 'm2v',
@@ -27,9 +28,9 @@ const playableExtList = [
'mpeg', 'mpeg',
'mpg', 'mpg',
'mpv', 'mpv',
'mts',
'mxf', 'mxf',
'nsv', 'nsv',
'ogg',
'ogv', 'ogv',
'ts', 'ts',
'qt', 'qt',
@@ -46,6 +47,9 @@ const playableExtList = [
'aiff', 'aiff',
'ape', 'ape',
'au', 'au',
'dsd',
'dff',
'dsf',
'flac', 'flac',
'gsm', 'gsm',
'it', 'it',
@@ -55,11 +59,15 @@ const playableExtList = [
'mod', 'mod',
'mp3', 'mp3',
'mpa', 'mpa',
'oga',
'ogg',
'opus',
'pls', 'pls',
'ra', 'ra',
's3m', 's3m',
'sid', 'sid',
'wav', 'wav',
'weba',
'wma', 'wma',
'xm', 'xm',
] ]

View File

@@ -52,7 +52,7 @@ export const PeersWidget = ({ data }) => {
return ( return (
<StatisticsField <StatisticsField
title={t('Peers')} title={t('Peers')}
value={getPeerString(data) || '0 · 0 / 0'} value={getPeerString(data) || '0 / 0 · 0'}
iconBg={iconBGColor} iconBg={iconBGColor}
valueBg={valueBGColor} valueBg={valueBGColor}
icon={SwapVerticalCircleIcon} icon={SwapVerticalCircleIcon}

View File

@@ -7,28 +7,17 @@ import { useState } from 'react'
import { torrentsHost } from 'utils/Hosts' import { torrentsHost } from 'utils/Hosts'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import UnsafeButton from './UnsafeButton'
const fnRemoveAll = () => { const fnRemoveAll = () => {
fetch(torrentsHost(), { fetch(torrentsHost(), {
method: 'post', method: 'post',
body: JSON.stringify({ action: 'list' }), body: JSON.stringify({ action: 'wipe' }),
headers: { headers: {
Accept: 'application/json, text/plain, */*', Accept: 'application/json, text/plain, */*',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
}) })
.then(res => res.json())
.then(json => {
json.forEach(torr => {
fetch(torrentsHost(), {
method: 'post',
body: JSON.stringify({ action: 'rem', hash: torr.hash }),
headers: {
Accept: 'application/json, text/plain, */*',
'Content-Type': 'application/json',
},
})
})
})
} }
export default function RemoveAll({ isOffline, isLoading }) { export default function RemoveAll({ isOffline, isLoading }) {
@@ -54,7 +43,9 @@ export default function RemoveAll({ isOffline, isLoading }) {
{t('Cancel')} {t('Cancel')}
</Button> </Button>
<Button <UnsafeButton
timeout={5}
startIcon={<DeleteIcon />}
variant='contained' variant='contained'
onClick={() => { onClick={() => {
fnRemoveAll() fnRemoveAll()
@@ -64,7 +55,7 @@ export default function RemoveAll({ isOffline, isLoading }) {
autoFocus autoFocus
> >
{t('OK')} {t('OK')}
</Button> </UnsafeButton>
</DialogActions> </DialogActions>
</Dialog> </Dialog>
</> </>

View File

@@ -16,10 +16,11 @@ export default function AddFirstTorrent() {
<> <>
<IconWrapper onClick={() => handleClickOpen(true)} isButton> <IconWrapper onClick={() => handleClickOpen(true)} isButton>
<lord-icon <lord-icon
src='https://cdn.lordicon.com/bbnkwdur.json' src='https://cdn.lordicon.com/jkzgajyr.json'
trigger='loop' trigger='loop'
colors={`primary:#121331,secondary:${primary}`} delay='2000'
stroke='26' colors={`primary:#575757,secondary:${primary}`}
stroke='light'
scale='60' scale='60'
/> />
<div className='icon-label'>{t('NoTorrentsAdded')}</div> <div className='icon-label'>{t('NoTorrentsAdded')}</div>

View File

@@ -0,0 +1,29 @@
import { Button } from '@material-ui/core'
import { useEffect, useState } from 'react'
export default function UnsafeButton({ timeout, children, disabled, ...props }) {
const [timeLeft, setTimeLeft] = useState(timeout || 7)
const [buttonDisabled, setButtonDisabled] = useState(disabled || timeLeft > 0)
const handleTimerTick = () => {
const newTimeLeft = timeLeft - 1
setTimeLeft(newTimeLeft)
if (newTimeLeft <= 0) {
setButtonDisabled(disabled)
}
}
const getTimerText = () => (!disabled && timeLeft > 0 ? ` (${timeLeft})` : '')
useEffect(() => {
if (disabled || !timeLeft) {
return
}
const intervalId = setInterval(handleTimerTick, 1000)
return () => clearInterval(intervalId)
// eslint-disable-next-line
}, [timeLeft])
return (
<Button disabled={buttonDisabled} {...props}>
{children} {getTimerText()}
</Button>
)
}

View File

@@ -72,7 +72,7 @@
"Offline": "Извън линия", "Offline": "Извън линия",
"OK": "OK", "OK": "OK",
"OpenLink": "Отвори линк", "OpenLink": "Отвори линк",
"Peers": "Пиъри", "Peers": "Пиъри·Сийдъри",
"PiecesCount": "Брой парчета", "PiecesCount": "Брой парчета",
"PiecesLength": "Дължина на парчетата", "PiecesLength": "Дължина на парчетата",
"Playlist": "Плейлист", "Playlist": "Плейлист",

View File

@@ -72,7 +72,7 @@
"Offline": "Offline", "Offline": "Offline",
"OK": "OK", "OK": "OK",
"OpenLink": "Open link", "OpenLink": "Open link",
"Peers": "Peers", "Peers": "Peers·Seeds",
"PiecesCount": "Pieces count", "PiecesCount": "Pieces count",
"PiecesLength": "Pieces length", "PiecesLength": "Pieces length",
"Playlist": "Playlist", "Playlist": "Playlist",

View File

@@ -72,7 +72,7 @@
"Offline": "Сервер недоступен", "Offline": "Сервер недоступен",
"OK": "OK", "OK": "OK",
"OpenLink": "Открыть", "OpenLink": "Открыть",
"Peers": "Пиры", "Peers": "Пиры·Сиды",
"PiecesCount": "Кол-во блоков", "PiecesCount": "Кол-во блоков",
"PiecesLength": "Размер блока", "PiecesLength": "Размер блока",
"Playlist": "Плейлист", "Playlist": "Плейлист",

View File

@@ -72,7 +72,7 @@
"Offline": "Сервер не доступний", "Offline": "Сервер не доступний",
"OK": "OK", "OK": "OK",
"OpenLink": "Відкрити", "OpenLink": "Відкрити",
"Peers": "Піри", "Peers": "Піри·Сіди",
"PiecesCount": "К-сть блоків", "PiecesCount": "К-сть блоків",
"PiecesLength": "Розмір блоку", "PiecesLength": "Розмір блоку",
"Playlist": "Плейлист", "Playlist": "Плейлист",

View File

@@ -72,7 +72,7 @@
"Offline": "离线", "Offline": "离线",
"OK": "确定", "OK": "确定",
"OpenLink": "打开链接", "OpenLink": "打开链接",
"Peers": "Peers", "Peers": "Peers·Seeds",
"PiecesCount": "块数量", "PiecesCount": "块数量",
"PiecesLength": "块长度", "PiecesLength": "块长度",
"Playlist": "播放列表", "Playlist": "播放列表",

View File

@@ -20,8 +20,9 @@ export function humanizeSpeed(speed) {
} }
export function getPeerString(torrent) { export function getPeerString(torrent) {
if (!torrent || !torrent.connected_seeders) return null if (!torrent || !torrent.active_peers) return null
return `${torrent.connected_seeders} · ${torrent.active_peers} / ${torrent.total_peers}` const seeders = typeof torrent.connected_seeders !== 'undefined' ? torrent.connected_seeders : 0
return `${torrent.active_peers} / ${torrent.total_peers} · ${seeders}`
} }
export const shortenText = (text, sympolAmount) => export const shortenText = (text, sympolAmount) =>

View File

@@ -5230,13 +5230,14 @@ es-to-primitive@^1.2.1:
is-date-object "^1.0.1" is-date-object "^1.0.1"
is-symbol "^1.0.2" is-symbol "^1.0.2"
es5-ext@^0.10.35, es5-ext@^0.10.46, es5-ext@^0.10.50: es5-ext@^0.10.35, es5-ext@^0.10.46, es5-ext@^0.10.50, es5-ext@^0.10.62, es5-ext@~0.10.14:
version "0.10.62" version "0.10.63"
resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.62.tgz#5e6adc19a6da524bf3d1e02bbc8960e5eb49a9a5" resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.63.tgz#9c222a63b6a332ac80b1e373b426af723b895bd6"
integrity sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA== integrity sha512-hUCZd2Byj/mNKjfP9jXrdVZ62B8KuA/VoK7X8nUh5qT+AxDmcbvZz041oDVZdbIN1qW6XY9VDNwzkvKnZvK2TQ==
dependencies: dependencies:
es6-iterator "^2.0.3" es6-iterator "^2.0.3"
es6-symbol "^3.1.3" es6-symbol "^3.1.3"
esniff "^2.0.1"
next-tick "^1.1.0" next-tick "^1.1.0"
es6-iterator@2.0.3, es6-iterator@^2.0.1, es6-iterator@^2.0.3: es6-iterator@2.0.3, es6-iterator@^2.0.1, es6-iterator@^2.0.3:
@@ -5559,6 +5560,16 @@ eslint@^7.11.0, eslint@^7.27.0:
text-table "^0.2.0" text-table "^0.2.0"
v8-compile-cache "^2.0.3" v8-compile-cache "^2.0.3"
esniff@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/esniff/-/esniff-2.0.1.tgz#a4d4b43a5c71c7ec51c51098c1d8a29081f9b308"
integrity sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==
dependencies:
d "^1.0.1"
es5-ext "^0.10.62"
event-emitter "^0.3.5"
type "^2.7.2"
espree@^7.3.0, espree@^7.3.1: espree@^7.3.0, espree@^7.3.1:
version "7.3.1" version "7.3.1"
resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6"
@@ -5622,6 +5633,14 @@ etag@~1.8.1:
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==
event-emitter@^0.3.5:
version "0.3.5"
resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39"
integrity sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==
dependencies:
d "1"
es5-ext "~0.10.14"
eventemitter3@^4.0.0: eventemitter3@^4.0.0:
version "4.0.7" version "4.0.7"
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
@@ -6037,9 +6056,9 @@ flush-write-stream@^1.0.0, flush-write-stream@^1.0.2:
readable-stream "^2.3.6" readable-stream "^2.3.6"
follow-redirects@^1.0.0, follow-redirects@^1.15.0: follow-redirects@^1.0.0, follow-redirects@^1.15.0:
version "1.15.3" version "1.15.4"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.3.tgz#fe2f3ef2690afce7e82ed0b44db08165b207123a" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.4.tgz#cdc7d308bf6493126b17ea2191ea0ccf3e535adf"
integrity sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q== integrity sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==
for-each@^0.3.3: for-each@^0.3.3:
version "0.3.3" version "0.3.3"
@@ -7063,9 +7082,9 @@ ip-regex@^2.1.0:
integrity sha512-58yWmlHpp7VYfcdTwMTvwMmqx/Elfxjd9RXTDyMsbL7lLWmhMylLEqiYVLKuLzOZqVgiWXD9MfR62Vv89VRxkw== integrity sha512-58yWmlHpp7VYfcdTwMTvwMmqx/Elfxjd9RXTDyMsbL7lLWmhMylLEqiYVLKuLzOZqVgiWXD9MfR62Vv89VRxkw==
ip@^1.1.0, ip@^1.1.5: ip@^1.1.0, ip@^1.1.5:
version "1.1.8" version "1.1.9"
resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.8.tgz#ae05948f6b075435ed3307acce04629da8cdbf48" resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.9.tgz#8dfbcc99a754d07f425310b86a99546b1151e396"
integrity sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg== integrity sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ==
ipaddr.js@1.9.1, ipaddr.js@^1.9.0: ipaddr.js@1.9.1, ipaddr.js@^1.9.0:
version "1.9.1" version "1.9.1"