diff --git a/.gitignore b/.gitignore index d5f5981..fcc7b9b 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ tstor-data httpfs_vfsdata.go bin/ coverage.out -bin \ No newline at end of file +bin +build \ No newline at end of file diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..d7760dc --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,52 @@ +linters: + enable: + - revive + - exhaustruct + - nakedret + - gomoddirectives + - importas + - misspell + - promlinter + - prealloc + - predeclared + - stylecheck + - ineffassign + - dupl + - govet + - staticcheck + - unused + - asasalint + - asciicheck + - bidichk + - bodyclose + # - containedctx + - durationcheck + - errcheck + - nakedret + - testifylint + +linters-settings: + revive: + ignore-generated-header: true + severity: warning + rules: + - name: blank-imports + disabled: true + staticcheck: + checks: + - "-SA4006" + gosimple: + checks: + - "-S1002" + exhaustruct: + include: + - ".*Service" + - ".*Server.*" + exclude: + - ".*mutex" + - ".*mutex" + stylecheck: + checks: + - "-ST1003" + dupl: + threshold: 180 diff --git a/.vscode/launch.json b/.vscode/launch.json index b9d624c..4b9ec0e 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -10,7 +10,7 @@ "request": "launch", "mode": "auto", "program": "${workspaceFolder}/cmd/tstor/main.go", - "cwd": "${workspaceFolder}/bin", + "cwd": "${workspaceFolder}/bin" } ] } \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index e40c94c..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "yaml.schemas": { - "https://json.schemastore.org/github-workflow.json": "file:///home/royalcat/projects/distribyted/.github/workflows/mkdocs.yml" - } -} \ No newline at end of file diff --git a/cmd/tstor/main.go b/cmd/tstor/main.go index ca84dab..eddba22 100644 --- a/cmd/tstor/main.go +++ b/cmd/tstor/main.go @@ -1,27 +1,30 @@ package main import ( - "bufio" "fmt" + + "net" + nethttp "net/http" + _ "net/http/pprof" "os" "os/signal" "path/filepath" - "runtime" "syscall" "time" "git.kmsign.ru/royalcat/tstor/src/config" "git.kmsign.ru/royalcat/tstor/src/host" "git.kmsign.ru/royalcat/tstor/src/host/torrent" - "github.com/anacrolix/torrent/storage" - "github.com/gin-gonic/gin" + "git.kmsign.ru/royalcat/tstor/src/host/vfs" "github.com/rs/zerolog/log" "github.com/urfave/cli/v2" + wnfs "github.com/willscott/go-nfs" "git.kmsign.ru/royalcat/tstor/src/http" dlog "git.kmsign.ru/royalcat/tstor/src/log" "git.kmsign.ru/royalcat/tstor/src/mounts/fuse" "git.kmsign.ru/royalcat/tstor/src/mounts/httpfs" + "git.kmsign.ru/royalcat/tstor/src/mounts/nfs" "git.kmsign.ru/royalcat/tstor/src/mounts/webdav" ) @@ -44,16 +47,7 @@ func main() { }, Action: func(c *cli.Context) error { - err := load(c.String(configFlag)) - - // stop program execution on errors to avoid flashing consoles - if err != nil && runtime.GOOS == "windows" { - log.Error().Err(err).Msg("problem starting application") - fmt.Print("Press 'Enter' to continue...") - bufio.NewReader(os.Stdin).ReadBytes('\n') - } - - return err + return run(c.String(configFlag)) }, HideHelpCommand: true, @@ -64,50 +58,8 @@ func main() { } } -func setupStorage(tcfg config.TorrentClient) (storage.ClientImplCloser, storage.PieceCompletion, error) { - pcp := filepath.Join(tcfg.DataFolder, "piece-completion") - if err := os.MkdirAll(pcp, 0744); err != nil { - return nil, nil, fmt.Errorf("error creating piece completion folder: %w", err) - } - pc, err := storage.NewBoltPieceCompletion(pcp) - if err != nil { - return nil, nil, fmt.Errorf("error creating servers piece completion: %w", err) - } +func run(configPath string) error { - // TODO implement cache/storage switching - // cacheDir := filepath.Join(tcfg.DataFolder, "cache") - // if err := os.MkdirAll(cacheDir, 0744); err != nil { - // return nil, nil, fmt.Errorf("error creating piece completion folder: %w", err) - // } - // fc, err := filecache.NewCache(cacheDir) - // if err != nil { - // return nil, nil, fmt.Errorf("error creating cache: %w", err) - // } - // log.Info().Msg(fmt.Sprintf("setting cache size to %d MB", 1024)) - // fc.SetCapacity(1024 * 1024 * 1024) - - // rp := storage.NewResourcePieces(fc.AsResourceProvider()) - // st := &stc{rp} - - filesDir := filepath.Join(tcfg.DataFolder, "files") - if err := os.MkdirAll(pcp, 0744); err != nil { - return nil, nil, fmt.Errorf("error creating piece completion folder: %w", err) - } - - st := storage.NewFileWithCompletion(filesDir, pc) - - return st, pc, nil -} - -type stc struct { - storage.ClientImpl -} - -func (s *stc) Close() error { - return nil -} - -func load(configPath string) error { conf, err := config.Load(configPath) if err != nil { return fmt.Errorf("error loading configuration: %w", err) @@ -115,6 +67,11 @@ func load(configPath string) error { dlog.Load(&conf.Log) + err = syscall.Setpriority(syscall.PRIO_PGRP, 0, 19) + if err != nil { + log.Err(err).Msg("set priority failed") + } + if err := os.MkdirAll(conf.TorrentClient.MetadataFolder, 0744); err != nil { return fmt.Errorf("error creating metadata folder: %w", err) } @@ -123,22 +80,25 @@ func load(configPath string) error { if err != nil { return fmt.Errorf("error starting item store: %w", err) } + defer fis.Close() id, err := torrent.GetOrCreatePeerID(filepath.Join(conf.TorrentClient.MetadataFolder, "ID")) if err != nil { return fmt.Errorf("error creating node ID: %w", err) } - st, _, err := setupStorage(conf.TorrentClient) + st, _, err := torrent.SetupStorage(conf.TorrentClient) if err != nil { return err } + defer st.Close() c, err := torrent.NewClient(st, fis, &conf.TorrentClient, id) if err != nil { return fmt.Errorf("error starting torrent client: %w", err) } c.AddDhtNodes(conf.TorrentClient.DHTNodes) + defer c.Close() ts := torrent.NewService(c, conf.TorrentClient.AddTimeout, conf.TorrentClient.ReadTimeout) @@ -147,46 +107,15 @@ func load(configPath string) error { } cfs := host.NewStorage(conf.DataFolder, ts) - var mh *fuse.Handler if conf.Mounts.Fuse.Enabled { - mh = fuse.NewHandler(conf.Mounts.Fuse.AllowOther, conf.Mounts.Fuse.Path) + mh := fuse.NewHandler(conf.Mounts.Fuse.AllowOther, conf.Mounts.Fuse.Path) + err := mh.Mount(cfs) + if err != nil { + return fmt.Errorf("mount fuse error: %w", err) + } + defer mh.Unmount() } - sigChan := make(chan os.Signal) - signal.Notify(sigChan, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) - - go func() { - - <-sigChan - log.Info().Msg("closing servers...") - // for _, s := range servers { - // if err := s.Close(); err != nil { - // log.Warn().Err(err).Msg("problem closing server") - // } - // } - log.Info().Msg("closing items database...") - fis.Close() - log.Info().Msg("closing torrent client...") - c.Close() - if mh != nil { - log.Info().Msg("unmounting fuse filesystem...") - mh.Unmount() - } - - log.Info().Msg("exiting") - os.Exit(1) - }() - - go func() { - if mh == nil { - return - } - - if err := mh.Mount(cfs); err != nil { - log.Info().Err(err).Msg("error mounting filesystems") - } - }() - if conf.Mounts.WebDAV.Enabled { go func() { if err := webdav.NewWebDAVServer(cfs, conf.Mounts.WebDAV.Port, conf.Mounts.WebDAV.User, conf.Mounts.WebDAV.Pass); err != nil { @@ -199,24 +128,63 @@ func load(configPath string) error { if conf.Mounts.HttpFs.Enabled { go func() { httpfs := httpfs.NewHTTPFS(cfs) - - r := gin.New() - - r.GET("*filepath", func(c *gin.Context) { - path := c.Param("filepath") - c.FileFromFS(path, httpfs) - }) - - log.Info().Str("host", fmt.Sprintf("0.0.0.0:%d", conf.Mounts.HttpFs.Port)).Msg("starting HTTPFS") - if err := r.Run(fmt.Sprintf("0.0.0.0:%d", conf.Mounts.HttpFs.Port)); err != nil { + err = nethttp.ListenAndServe(fmt.Sprintf("0.0.0.0:%d", conf.Mounts.HttpFs.Port), nethttp.FileServer(httpfs)) + if err != nil { log.Error().Err(err).Msg("error starting HTTPFS") } + // r := gin.New() + + // r.GET("*filepath", func(c *gin.Context) { + // path := c.Param("filepath") + // c.FileFromFS(path, httpfs) + // }) + + // log.Info().Str("host", fmt.Sprintf("0.0.0.0:%d", conf.Mounts.HttpFs.Port)).Msg("starting HTTPFS") + // if err := r.Run(fmt.Sprintf("0.0.0.0:%d", conf.Mounts.HttpFs.Port)); err != nil { + // log.Error().Err(err).Msg("error starting HTTPFS") + // } }() } - logFilename := filepath.Join(conf.Log.Path, dlog.FileName) + if conf.Mounts.NFS.Enabled { + go func() { + listener, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%d", conf.Mounts.NFS.Port)) + panicOnErr(err, "starting TCP listener") + log.Info().Str("host", listener.Addr().String()).Msg("starting NFS server") + handler, err := nfs.NewNFSv3Handler(cfs) + panicOnErr(err, "creating NFS handler") + panicOnErr(wnfs.Serve(listener, handler), "serving nfs") + }() + } - err = http.New(nil, nil, ts, logFilename, conf) - log.Error().Err(err).Msg("error initializing HTTP server") - return err + dataFS := vfs.NewOsFs(conf.DataFolder) + + go func() { + if err := webdav.NewWebDAVServer(dataFS, 36912, conf.Mounts.WebDAV.User, conf.Mounts.WebDAV.Pass); err != nil { + log.Error().Err(err).Msg("error starting webDAV") + } + + log.Warn().Msg("webDAV configuration not found!") + }() + + go func() { + logFilename := filepath.Join(conf.Log.Path, dlog.FileName) + + err = http.New(nil, nil, ts, logFilename, conf) + log.Error().Err(err).Msg("error initializing HTTP server") + }() + + sigChan := make(chan os.Signal, 1) + signal.Notify(sigChan, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) + <-sigChan + + return nil +} + +func panicOnErr(err error, desc string) { + if err == nil { + return + } + log.Err(err).Msg(desc) + log.Panic() } diff --git a/go.mod b/go.mod index 421dc8d..a9b95cd 100644 --- a/go.mod +++ b/go.mod @@ -3,14 +3,18 @@ module git.kmsign.ru/royalcat/tstor go 1.21 require ( - github.com/anacrolix/dht/v2 v2.20.0 - github.com/anacrolix/log v0.14.3-0.20230823030427-4b296d71a6b4 - github.com/anacrolix/missinggo/v2 v2.7.2 - github.com/anacrolix/torrent v1.52.6-0.20230929044811-45c91b322ad1 + github.com/anacrolix/dht/v2 v2.21.0 + github.com/anacrolix/log v0.14.5 + github.com/anacrolix/missinggo v1.3.0 + github.com/anacrolix/missinggo/v2 v2.7.3 + github.com/anacrolix/torrent v1.53.2 github.com/billziss-gh/cgofuse v1.5.0 - github.com/bodgit/sevenzip v1.4.3 + github.com/bodgit/sevenzip v1.4.5 github.com/dgraph-io/badger/v4 v4.2.0 + github.com/edsrzf/mmap-go v1.1.0 + github.com/gin-contrib/pprof v1.4.0 github.com/gin-gonic/gin v1.9.1 + github.com/go-git/go-billy/v5 v5.5.0 github.com/knadh/koanf/parsers/yaml v0.1.0 github.com/knadh/koanf/providers/env v0.1.0 github.com/knadh/koanf/providers/file v0.1.0 @@ -21,122 +25,124 @@ require ( github.com/rs/zerolog v1.31.0 github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c github.com/stretchr/testify v1.8.4 - github.com/urfave/cli/v2 v2.25.7 - golang.org/x/net v0.16.0 + github.com/urfave/cli/v2 v2.26.0 + github.com/willscott/go-nfs v0.0.1 + golang.org/x/net v0.19.0 gopkg.in/natefinch/lumberjack.v2 v2.2.1 ) require ( - github.com/RoaringBitmap/roaring v1.2.3 // indirect + github.com/RoaringBitmap/roaring v1.6.0 // indirect github.com/ajwerner/btree v0.0.0-20211221152037-f427b3e689c0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/anacrolix/chansync v0.3.0 // indirect github.com/anacrolix/envpprof v1.3.0 // indirect - github.com/anacrolix/generics v0.0.0-20230816105729-c755655aee45 // indirect + github.com/anacrolix/generics v0.0.0-20230911070922-5dd7545c6b13 // indirect github.com/anacrolix/go-libutp v1.3.1 // indirect - github.com/anacrolix/missinggo v1.3.0 // indirect github.com/anacrolix/missinggo/perf v1.0.0 // indirect github.com/anacrolix/mmsg v1.0.0 // indirect - github.com/anacrolix/multiless v0.3.1-0.20221221005021-2d12701f83f7 // indirect - github.com/anacrolix/stm v0.4.1-0.20221221005312-96d17df0e496 // indirect - github.com/anacrolix/sync v0.4.1-0.20230926072150-b8cd7cfb92d0 // indirect - github.com/anacrolix/upnp v0.1.3-0.20220123035249-922794e51c96 // indirect - github.com/anacrolix/utp v0.1.0 // indirect - github.com/andybalholm/brotli v1.0.5 // indirect + github.com/anacrolix/multiless v0.3.1-0.20230203023154-f3d27407d8f1 // indirect + github.com/anacrolix/stm v0.5.0 // indirect + github.com/anacrolix/sync v0.5.1 // indirect + github.com/anacrolix/upnp v0.1.3 // indirect + github.com/anacrolix/utp v0.2.0 // indirect + github.com/andybalholm/brotli v1.0.6 // indirect github.com/bahlo/generic-list-go v0.2.0 // indirect - github.com/benbjohnson/immutable v0.4.1-0.20221220213129-8932b999621d // indirect - github.com/bits-and-blooms/bitset v1.2.2 // indirect + github.com/benbjohnson/immutable v0.4.3 // indirect + github.com/bits-and-blooms/bitset v1.12.0 // indirect github.com/bodgit/plumbing v1.3.0 // indirect github.com/bodgit/windows v1.0.1 // indirect github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 // indirect - github.com/bytedance/sonic v1.9.1 // indirect + github.com/bytedance/sonic v1.10.2 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect + github.com/chenzhuoyu/iasm v0.9.1 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgraph-io/ristretto v0.1.1 // indirect - github.com/dustin/go-humanize v1.0.0 // indirect - github.com/edsrzf/mmap-go v1.1.0 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect github.com/fatih/structs v1.1.0 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-llsqlite/adapter v0.0.0-20230927005056-7f5ce7f0c916 // indirect github.com/go-llsqlite/crawshaw v0.4.0 // indirect - github.com/go-logr/logr v1.2.3 // indirect + github.com/go-logr/logr v1.3.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.14.0 // indirect + github.com/go-playground/validator/v10 v10.16.0 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/glog v1.0.0 // indirect - github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect - github.com/golang/protobuf v1.5.2 // indirect - github.com/golang/snappy v0.0.3 // indirect + github.com/golang/glog v1.2.0 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/snappy v0.0.4 // indirect github.com/google/btree v1.1.2 // indirect - github.com/google/flatbuffers v1.12.1 // indirect - github.com/google/uuid v1.3.0 // indirect - github.com/gorilla/websocket v1.5.0 // indirect - github.com/hashicorp/errwrap v1.0.0 // indirect + github.com/google/flatbuffers v23.5.26+incompatible // indirect + github.com/google/uuid v1.5.0 // indirect + github.com/gorilla/websocket v1.5.1 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect - github.com/huandu/xstrings v1.3.2 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect + github.com/huandu/xstrings v1.4.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.16.6 // indirect - github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/klauspost/compress v1.17.4 // indirect + github.com/klauspost/cpuid/v2 v2.2.6 // indirect github.com/knadh/koanf/maps v0.1.1 // indirect github.com/leodido/go-urn v1.2.4 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mschoch/smat v0.2.0 // indirect - github.com/pelletier/go-toml/v2 v2.0.8 // indirect - github.com/pierrec/lz4/v4 v4.1.18 // indirect - github.com/pion/datachannel v1.5.2 // indirect - github.com/pion/dtls/v2 v2.2.4 // indirect - github.com/pion/ice/v2 v2.2.6 // indirect - github.com/pion/interceptor v0.1.11 // indirect + github.com/pelletier/go-toml/v2 v2.1.1 // indirect + github.com/pierrec/lz4/v4 v4.1.19 // indirect + github.com/pion/datachannel v1.5.5 // indirect + github.com/pion/dtls/v2 v2.2.8 // indirect + github.com/pion/ice/v2 v2.3.11 // indirect + github.com/pion/interceptor v0.1.25 // indirect github.com/pion/logging v0.2.2 // indirect - github.com/pion/mdns v0.0.5 // indirect + github.com/pion/mdns v0.0.9 // indirect github.com/pion/randutil v0.1.0 // indirect - github.com/pion/rtcp v1.2.9 // indirect - github.com/pion/rtp v1.7.13 // indirect - github.com/pion/sctp v1.8.2 // indirect - github.com/pion/sdp/v3 v3.0.5 // indirect - github.com/pion/srtp/v2 v2.0.9 // indirect - github.com/pion/stun v0.3.5 // indirect - github.com/pion/transport v0.13.1 // indirect - github.com/pion/transport/v2 v2.0.0 // indirect - github.com/pion/turn/v2 v2.0.8 // indirect - github.com/pion/udp v0.1.4 // indirect - github.com/pion/webrtc/v3 v3.1.42 // indirect + github.com/pion/rtcp v1.2.13 // indirect + github.com/pion/rtp v1.8.3 // indirect + github.com/pion/sctp v1.8.9 // indirect + github.com/pion/sdp/v3 v3.0.6 // indirect + github.com/pion/srtp/v2 v2.0.18 // indirect + github.com/pion/stun v0.6.1 // indirect + github.com/pion/transport/v2 v2.2.4 // indirect + github.com/pion/turn/v2 v2.1.4 // indirect + github.com/pion/webrtc/v3 v3.2.24 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rasky/go-xdr v0.0.0-20170124162913-1a41d1a06c93 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect - github.com/rs/dnscache v0.0.0-20211102005908-e0241e321417 // indirect + github.com/rs/dnscache v0.0.0-20230804202142-fc85eb664529 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46 // indirect - github.com/tidwall/btree v1.6.0 // indirect + github.com/tidwall/btree v1.7.0 // 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 github.com/ulikunitz/xz v0.5.11 // indirect - github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect - go.etcd.io/bbolt v1.3.6 // indirect - go.opencensus.io v0.22.5 // indirect - go.opentelemetry.io/otel v1.8.0 // indirect - go.opentelemetry.io/otel/trace v1.8.0 // indirect - go4.org v0.0.0-20200411211856-f5505b9728dd // indirect - golang.org/x/arch v0.3.0 // indirect - golang.org/x/crypto v0.14.0 // indirect - golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect - golang.org/x/sync v0.3.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect - golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect - google.golang.org/protobuf v1.30.0 // indirect + github.com/willscott/go-nfs-client v0.0.0-20200605172546-271fa9065b33 // indirect + github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e // indirect + go.etcd.io/bbolt v1.3.8 // indirect + go.opencensus.io v0.24.0 // indirect + go.opentelemetry.io/otel v1.21.0 // indirect + go.opentelemetry.io/otel/metric v1.21.0 // indirect + go.opentelemetry.io/otel/trace v1.21.0 // indirect + go4.org v0.0.0-20230225012048-214862532bf5 // indirect + golang.org/x/arch v0.6.0 // indirect + golang.org/x/crypto v0.16.0 // indirect + golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611 // indirect + golang.org/x/sync v0.5.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/time v0.5.0 // indirect + google.golang.org/protobuf v1.31.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect modernc.org/libc v1.22.3 // indirect modernc.org/mathutil v1.5.0 // indirect diff --git a/go.sum b/go.sum index 14db9e5..b8ad50d 100644 --- a/go.sum +++ b/go.sum @@ -24,8 +24,8 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym github.com/RoaringBitmap/roaring v0.4.7/go.mod h1:8khRDP4HmeXns4xIj9oGrKSz7XTQiJx2zgh7AcNke4w= github.com/RoaringBitmap/roaring v0.4.17/go.mod h1:D3qVegWTmfCaX4Bl5CrBE9hfrSrrXIr8KVNvRsDi1NI= github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo= -github.com/RoaringBitmap/roaring v1.2.3 h1:yqreLINqIrX22ErkKI0vY47/ivtJr6n+kMhVOVmhWBY= -github.com/RoaringBitmap/roaring v1.2.3/go.mod h1:plvDsJQpxOC5bw8LRteu/MLWHsHez/3y6cubLI4/1yE= +github.com/RoaringBitmap/roaring v1.6.0 h1:dc7kRiroETgJcHhWX6BerXkZz2b3JgLGg9nTURJL/og= +github.com/RoaringBitmap/roaring v1.6.0/go.mod h1:plvDsJQpxOC5bw8LRteu/MLWHsHez/3y6cubLI4/1yE= github.com/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/ajwerner/btree v0.0.0-20211221152037-f427b3e689c0 h1:byYvvbfSo3+9efR4IeReh77gVs4PnNDR3AMOE9NJ7a0= @@ -42,23 +42,24 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/anacrolix/chansync v0.3.0 h1:lRu9tbeuw3wl+PhMu/r+JJCRu5ArFXIluOgdF0ao6/U= github.com/anacrolix/chansync v0.3.0/go.mod h1:DZsatdsdXxD0WiwcGl0nJVwyjCKMDv+knl1q2iBjA2k= -github.com/anacrolix/dht/v2 v2.20.0 h1:eDx9lfE9iCSf5sPK0290GToHURNhEFuUGN8iyvhvJDk= -github.com/anacrolix/dht/v2 v2.20.0/go.mod h1:SDGC+sEs1pnO2sJGYuhvIis7T8749dDHNfcjtdH4e3g= +github.com/anacrolix/dht/v2 v2.21.0 h1:8nzI+faaynY9jOKmVgdmBZVrTo8B7ZE/LKEgN3Vl/Bs= +github.com/anacrolix/dht/v2 v2.21.0/go.mod h1:SDGC+sEs1pnO2sJGYuhvIis7T8749dDHNfcjtdH4e3g= github.com/anacrolix/envpprof v0.0.0-20180404065416-323002cec2fa/go.mod h1:KgHhUaQMc8cC0+cEflSgCFNFbKwi5h54gqtVn8yhP7c= github.com/anacrolix/envpprof v1.0.0/go.mod h1:KgHhUaQMc8cC0+cEflSgCFNFbKwi5h54gqtVn8yhP7c= github.com/anacrolix/envpprof v1.1.0/go.mod h1:My7T5oSqVfEn4MD4Meczkw/f5lSIndGAKu/0SM/rkf4= github.com/anacrolix/envpprof v1.3.0 h1:WJt9bpuT7A/CDCxPOv/eeZqHWlle/Y0keJUvc6tcJDk= github.com/anacrolix/envpprof v1.3.0/go.mod h1:7QIG4CaX1uexQ3tqd5+BRa/9e2D02Wcertl6Yh0jCB0= -github.com/anacrolix/generics v0.0.0-20230816105729-c755655aee45 h1:Kmcl3I9K2+5AdnnR7hvrnVT0TLeFWWMa9bxnm55aVIg= -github.com/anacrolix/generics v0.0.0-20230816105729-c755655aee45/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.0-20230911070922-5dd7545c6b13/go.mod h1:ff2rHB/joTV03aMSSn/AZNnaIpUw0h3njetGsaXcMy8= github.com/anacrolix/go-libutp v1.3.1 h1:idJzreNLl+hNjGC3ZnUOjujEaryeOGgkwHLqSGoige0= github.com/anacrolix/go-libutp v1.3.1/go.mod h1:heF41EC8kN0qCLMokLBVkB8NXiLwx3t8R8810MTNI5o= 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.10.1-0.20220123034749-3920702c17f8/go.mod h1:GmnE2c0nvz8pOIPUSC9Rawgefy1sDXqposC2wgtBZE4= github.com/anacrolix/log v0.13.1/go.mod h1:D4+CvN8SnruK6zIFS/xPoRJmtvtnxs+CSfDQ+BFxZ68= -github.com/anacrolix/log v0.14.3-0.20230823030427-4b296d71a6b4 h1:01OE3pdiBGIZGyQb6cIAu+QfaNhBR9k5MVmLsl+DVbE= -github.com/anacrolix/log v0.14.3-0.20230823030427-4b296d71a6b4/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.14.5/go.mod h1:1OmJESOtxQGNMlUO5rcv96Vpp9mfMqXXbe2RdinFLdY= github.com/anacrolix/lsan v0.0.0-20211126052245-807000409a62 h1:P04VG6Td13FHMgS5ZBcJX23NPC/fiC4cp9bXwYujdYM= github.com/anacrolix/lsan v0.0.0-20211126052245-807000409a62/go.mod h1:66cFKPCO7Sl4vbFnAaSq7e4OXtdMhRSBagJGWgmpJbM= github.com/anacrolix/missinggo v0.0.0-20180725070939-60ef2fbf63df/go.mod h1:kwGiTUTZ0+p4vAz3VbAI5a30t2YbvemcmspjKwrAz5s= @@ -71,50 +72,49 @@ github.com/anacrolix/missinggo/perf v1.0.0 h1:7ZOGYziGEBytW49+KmYGTaNfnwUqP1HBsy github.com/anacrolix/missinggo/perf v1.0.0/go.mod h1:ljAFWkBuzkO12MQclXzZrosP5urunoLS0Cbvb4V0uMQ= github.com/anacrolix/missinggo/v2 v2.2.0/go.mod h1:o0jgJoYOyaoYQ4E2ZMISVa9c88BbUBVQQW4QeRkNCGY= github.com/anacrolix/missinggo/v2 v2.5.1/go.mod h1:WEjqh2rmKECd0t1VhQkLGTdIWXO6f6NLjp5GlMZ+6FA= -github.com/anacrolix/missinggo/v2 v2.5.2/go.mod h1:yNvsLrtZYRYCOI+KRH/JM8TodHjtIE/bjOGhQaLOWIE= -github.com/anacrolix/missinggo/v2 v2.7.2 h1:XGia0kZVC8DDY6XVl15fjtdEyUF39tWkdtsH1VjuAHg= -github.com/anacrolix/missinggo/v2 v2.7.2/go.mod h1:mIEtp9pgaXqt8VQ3NQxFOod/eQ1H0D1XsZzKUQfwtac= +github.com/anacrolix/missinggo/v2 v2.7.3 h1:Ee//CmZBMadeNiYB/hHo9ly2PFOEZ4Fhsbnug3rDAIE= +github.com/anacrolix/missinggo/v2 v2.7.3/go.mod h1:mIEtp9pgaXqt8VQ3NQxFOod/eQ1H0D1XsZzKUQfwtac= github.com/anacrolix/mmsg v0.0.0-20180515031531-a4a3ba1fc8bb/go.mod h1:x2/ErsYUmT77kezS63+wzZp8E3byYB0gzirM/WMBLfw= github.com/anacrolix/mmsg v1.0.0 h1:btC7YLjOn29aTUAExJiVUhQOuf/8rhm+/nWCMAnL3Hg= github.com/anacrolix/mmsg v1.0.0/go.mod h1:x8kRaJY/dCrY9Al0PEcj1mb/uFHwP6GCJ9fLl4thEPc= -github.com/anacrolix/multiless v0.3.1-0.20221221005021-2d12701f83f7 h1:lOtCD+LzoD1g7bowhYJNR++uV+FyY5bTZXKwnPex9S8= -github.com/anacrolix/multiless v0.3.1-0.20221221005021-2d12701f83f7/go.mod h1:zJv1JF9AqdZiHwxqPgjuOZDGWER6nyE48WBCi/OOrMM= +github.com/anacrolix/multiless v0.3.1-0.20230203023154-f3d27407d8f1 h1:1gfWAUiwUurVDZ4Re9e1hhpF0iGLlVBhPL5DY5U5hrI= +github.com/anacrolix/multiless v0.3.1-0.20230203023154-f3d27407d8f1/go.mod h1:zJv1JF9AqdZiHwxqPgjuOZDGWER6nyE48WBCi/OOrMM= github.com/anacrolix/stm v0.2.0/go.mod h1:zoVQRvSiGjGoTmbM0vSLIiaKjWtNPeTvXUSdJQA4hsg= -github.com/anacrolix/stm v0.4.1-0.20221221005312-96d17df0e496 h1:aMiRi2kOOd+nG64suAmFMVnNK2E6GsnLif7ia9tI3cA= -github.com/anacrolix/stm v0.4.1-0.20221221005312-96d17df0e496/go.mod h1:DBm8/1OXm4A4RZ6Xa9u/eOsjeAXCaoRYvd2JzlskXeM= +github.com/anacrolix/stm v0.5.0 h1:9df1KBpttF0TzLgDq51Z+TEabZKMythqgx89f1FQJt8= +github.com/anacrolix/stm v0.5.0/go.mod h1:MOwrSy+jCm8Y7HYfMAwPj7qWVu7XoVvjOiYwJmpeB/M= github.com/anacrolix/sync v0.0.0-20180808010631-44578de4e778/go.mod h1:s735Etp3joe/voe2sdaXLcqDdJSay1O0OPnM0ystjqk= github.com/anacrolix/sync v0.3.0/go.mod h1:BbecHL6jDSExojhNtgTFSBcdGerzNc64tz3DCOj/I0g= -github.com/anacrolix/sync v0.4.1-0.20230926072150-b8cd7cfb92d0 h1:M2HtYrYz6CVwo88TfVrGNlc+mSe59KXCBe3gFuEsEto= -github.com/anacrolix/sync v0.4.1-0.20230926072150-b8cd7cfb92d0/go.mod h1:BbecHL6jDSExojhNtgTFSBcdGerzNc64tz3DCOj/I0g= +github.com/anacrolix/sync v0.5.1 h1:FbGju6GqSjzVoTgcXTUKkF041lnZkG5P0C3T5RL3SGc= +github.com/anacrolix/sync v0.5.1/go.mod h1:BbecHL6jDSExojhNtgTFSBcdGerzNc64tz3DCOj/I0g= github.com/anacrolix/tagflag v0.0.0-20180109131632-2146c8d41bf0/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pmhJXOKKCHw= github.com/anacrolix/tagflag v1.0.0/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pmhJXOKKCHw= github.com/anacrolix/tagflag v1.1.0/go.mod h1:Scxs9CV10NQatSmbyjqmqmeQNwGzlNe0CMUMIxqHIG8= -github.com/anacrolix/torrent v1.52.6-0.20230929044811-45c91b322ad1 h1:KzIKTajeqBXWeLjHv2KHjlwigyR19TkdvU5uLGPGQAI= -github.com/anacrolix/torrent v1.52.6-0.20230929044811-45c91b322ad1/go.mod h1:q4utKicrzW80odcXiy3J8sObJELsGGFI1FxhFt/2qA0= -github.com/anacrolix/upnp v0.1.3-0.20220123035249-922794e51c96 h1:QAVZ3pN/J4/UziniAhJR2OZ9Ox5kOY2053tBbbqUPYA= -github.com/anacrolix/upnp v0.1.3-0.20220123035249-922794e51c96/go.mod h1:Wa6n8cYIdaG35x15aH3Zy6d03f7P728QfdcDeD/IEOs= -github.com/anacrolix/utp v0.1.0 h1:FOpQOmIwYsnENnz7tAGohA+r6iXpRjrq8ssKSre2Cp4= -github.com/anacrolix/utp v0.1.0/go.mod h1:MDwc+vsGEq7RMw6lr2GKOEqjWny5hO5OZXRVNaBJ2Dk= -github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= -github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/anacrolix/torrent v1.53.2 h1:dW+ficSC8sJaGrUvZJizORPBLTP7XR8idl2oGlrUutQ= +github.com/anacrolix/torrent v1.53.2/go.mod h1:d1NANCFAd9/nv9vmHnYUobLdyBSAoFYohojHjGmcAsw= +github.com/anacrolix/upnp v0.1.3 h1:NlYEhE75adz2npEJKjbqyqnyW9qU4STookvSNXBJ5ao= +github.com/anacrolix/upnp v0.1.3/go.mod h1:Qyhbqo69gwNWvEk1xNTXsS5j7hMHef9hdr984+9fIic= +github.com/anacrolix/utp v0.2.0 h1:65Cdmr6q9WSw2KsM+rtJFu7rqDzLl2bdysf4KlNPcFI= +github.com/anacrolix/utp v0.2.0/go.mod h1:HGk4GYQw1O/3T1+yhqT/F6EcBd+AAwlo9dYErNy7mj8= +github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI= +github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/benbjohnson/immutable v0.2.0/go.mod h1:uc6OHo6PN2++n98KHLxW8ef4W42ylHiQSENghE1ezxI= -github.com/benbjohnson/immutable v0.4.1-0.20221220213129-8932b999621d h1:2qVb9bsAMtmAfnxXltm+6eBzrrS7SZ52c3SedsulaMI= -github.com/benbjohnson/immutable v0.4.1-0.20221220213129-8932b999621d/go.mod h1:iAr8OjJGLnLmVUr9MZ/rz4PWUy6Ouc2JLYuMArmvAJM= +github.com/benbjohnson/immutable v0.4.3 h1:GYHcksoJ9K6HyAUpGxwZURrbTkXA0Dh4otXGqbhdrjA= +github.com/benbjohnson/immutable v0.4.3/go.mod h1:qJIKKSmdqz1tVzNtst1DZzvaqOU1onk1rc03IeM3Owk= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/billziss-gh/cgofuse v1.5.0 h1:kH516I/s+Ab4diL/Y/ayFeUjjA8ey+JK12xDfBf4HEs= github.com/billziss-gh/cgofuse v1.5.0/go.mod h1:LJjoaUojlVjgo5GQoEJTcJNqZJeRU0nCR84CyxKt2YM= github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= -github.com/bits-and-blooms/bitset v1.2.2 h1:J5gbX05GpMdBjCvQ9MteIg2KKDExr7DrgK+Yc15FvIk= -github.com/bits-and-blooms/bitset v1.2.2/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= +github.com/bits-and-blooms/bitset v1.12.0 h1:U/q1fAF7xXRhFCrhROzIfffYnu+dlS38vCZtmFVPHmA= +github.com/bits-and-blooms/bitset v1.12.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/bodgit/plumbing v1.3.0 h1:pf9Itz1JOQgn7vEOE7v7nlEfBykYqvUYioC61TwWCFU= github.com/bodgit/plumbing v1.3.0/go.mod h1:JOTb4XiRu5xfnmdnDJo6GmSbSbtSyufrsyZFByMtKEs= -github.com/bodgit/sevenzip v1.4.3 h1:46Rb9vCYdpceC1U+GIR0bS3hP2/Xv8coKFDeLJySV/A= -github.com/bodgit/sevenzip v1.4.3/go.mod h1:F8n3+0CwbdxqmNy3wFeOAtanza02Ur66AGfs/hbYblI= +github.com/bodgit/sevenzip v1.4.5 h1:HFJQ+nbjppfyf2xbQEJBbmVo+o2kTg1FXV4i7YOx87s= +github.com/bodgit/sevenzip v1.4.5/go.mod h1:LAcAg/UQzyjzCQSGBPZFYzoiHMfT6Gk+3tMSjUk3foY= github.com/bodgit/windows v1.0.1 h1:tF7K6KOluPYygXa3Z2594zxlkbKPAOvqr97etrGNIz4= github.com/bodgit/windows v1.0.1/go.mod h1:a6JLwrB4KrTR5hBpp8FI9/9W9jJfeQ2h4XDXU74ZCdM= github.com/bradfitz/iter v0.0.0-20140124041915-454541ec3da2/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo= @@ -122,22 +122,28 @@ github.com/bradfitz/iter v0.0.0-20190303215204-33e6a9893b0c/go.mod h1:PyRFw1Lt2w github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 h1:GKTyiRCL6zVf5wWaqKnf+7Qs6GbEPfd4iMOitWzXJx8= github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8/go.mod h1:spo1JLcs67NmW1aVLEgtA8Yy1elc+X8y5SRW1sFW4Og= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= -github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= -github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= +github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= +github.com/bytedance/sonic v1.10.2 h1:GQebETVBxYB7JGWJtLBi07OVzWwt+8dWA00gEVW2ZFE= +github.com/bytedance/sonic v1.10.2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= +github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= +github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= +github.com/chenzhuoyu/iasm v0.9.1 h1:tUHQJXo3NhBqw6s33wkGn9SP3bvrWLdlVIJ3hQBL7P0= +github.com/chenzhuoyu/iasm v0.9.1/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -150,28 +156,35 @@ github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczC github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v0.0.0-20180421182945-02af3965c54e/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ= github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/frankban/quicktest v1.9.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y= +github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= -github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= +github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= +github.com/gin-contrib/pprof v1.4.0 h1:XxiBSf5jWZ5i16lNOPbMTVdgHBdhfGRD5PZ1LWazzvg= +github.com/gin-contrib/pprof v1.4.0/go.mod h1:RrehPJasUVBPK6yTUwOl8/NP6i0vbUgmxtis+Z5KE90= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= @@ -180,6 +193,8 @@ github.com/glycerine/go-unsnap-stream v0.0.0-20190901134440-81cf024a9e0a/go.mod github.com/glycerine/goconvey v0.0.0-20180728074245-46e3a41ad493/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= github.com/glycerine/goconvey v0.0.0-20190315024820-982ee783a72e/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= +github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= +github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= @@ -191,20 +206,25 @@ github.com/go-llsqlite/crawshaw v0.4.0/go.mod h1:/YJdV7uBQaYDE0fwe4z3wwJIZBJxdYz 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-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= -github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= -github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= +github.com/go-playground/validator/v10 v10.16.0 h1:x+plE831WK4vaKHO/jpgUGsvLKIqRRkz6M78GuJAfGE= +github.com/go-playground/validator/v10 v10.16.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -213,12 +233,13 @@ github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= -github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68= +github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -232,36 +253,44 @@ github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:x github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 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.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/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-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/flatbuffers v1.12.1 h1:MVlul7pQNoDzWRLTw5imwYsl+usrS1TXG2H4jg6ImGw= -github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/flatbuffers v23.5.26+incompatible h1:M9dgRyhJemaM4Sw8+66GHBu8ioaQmyPLg1b8VwK5WJg= +github.com/google/flatbuffers v23.5.26+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/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 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= 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/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= +github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= @@ -270,14 +299,17 @@ github.com/gopherjs/gopherjs v0.0.0-20190309154008-847fc94819f9/go.mod h1:wJfORR github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= +github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= @@ -285,8 +317,8 @@ github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbc github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= github.com/huandu/xstrings v1.3.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= -github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= +github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -299,11 +331,11 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.16.6 h1:91SKEy4K37vkp255cJ8QesJhjyRO0hn9i9G0GoUwLsk= -github.com/klauspost/compress v1.16.6/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= +github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= -github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc= +github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/knadh/koanf/maps v0.1.1 h1:G5TjmUh2D7G2YWf5SQQqSiHRJEjaicvU0KpypqB3NIs= github.com/knadh/koanf/maps v0.1.1/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI= github.com/knadh/koanf/parsers/yaml v0.1.0 h1:ZZ8/iGfRLvKSaMEECEBPM1HQslrZADk8fP1XFUxVI5w= @@ -316,10 +348,12 @@ github.com/knadh/koanf/providers/structs v0.1.0 h1:wJRteCNn1qvLtE5h8KQBvLJovidSd github.com/knadh/koanf/providers/structs v0.1.0/go.mod h1:sw2YZ3txUcqA3Z27gPlmmBzWn1h8Nt9O6EP/91MkcWE= github.com/knadh/koanf/v2 v2.0.1 h1:1dYGITt1I23x8cfx8ZnldtezdyaZtfAuRtIFOiRzK7g= github.com/knadh/koanf/v2 v2.0.1/go.mod h1:ZeiIlIDXTE7w1lMT6UVcNiRAS2/rCeLn/GdLNvY1Dus= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -327,13 +361,16 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= @@ -366,55 +403,60 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= -github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= -github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= +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.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= -github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ= -github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= -github.com/pion/datachannel v1.5.2 h1:piB93s8LGmbECrpO84DnkIVWasRMk3IimbcXkTQLE6E= -github.com/pion/datachannel v1.5.2/go.mod h1:FTGQWaHrdCwIJ1rw6xBIfZVkslikjShim5yr05XFuCQ= -github.com/pion/dtls/v2 v2.1.3/go.mod h1:o6+WvyLDAlXF7YiPB/RlskRoeK+/JtuaZa5emwQcWus= -github.com/pion/dtls/v2 v2.1.5/go.mod h1:BqCE7xPZbPSubGasRoDFJeTsyJtdD1FanJYL0JGheqY= -github.com/pion/dtls/v2 v2.2.4 h1:YSfYwDQgrxMYXLBc/m7PFY5BVtWlNm/DN4qoU2CbcWg= -github.com/pion/dtls/v2 v2.2.4/go.mod h1:WGKfxqhrddne4Kg3p11FUMJrynkOY4lb25zHNO49wuw= -github.com/pion/ice/v2 v2.2.6 h1:R/vaLlI1J2gCx141L5PEwtuGAGcyS6e7E0hDeJFq5Ig= -github.com/pion/ice/v2 v2.2.6/go.mod h1:SWuHiOGP17lGromHTFadUe1EuPgFh/oCU6FCMZHooVE= -github.com/pion/interceptor v0.1.11 h1:00U6OlqxA3FFB50HSg25J/8cWi7P6FbSzw4eFn24Bvs= -github.com/pion/interceptor v0.1.11/go.mod h1:tbtKjZY14awXd7Bq0mmWvgtHB5MDaRN7HV3OZ/uy7s8= +github.com/pierrec/lz4/v4 v4.1.19 h1:tYLzDnjDXh9qIxSTKHwXwOYmm9d887Y7Y1ZkyXYHAN4= +github.com/pierrec/lz4/v4 v4.1.19/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pion/datachannel v1.5.5 h1:10ef4kwdjije+M9d7Xm9im2Y3O6A6ccQb0zcqZcJew8= +github.com/pion/datachannel v1.5.5/go.mod h1:iMz+lECmfdCMqFRhXhcA/219B0SQlbpoR2V118yimL0= +github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= +github.com/pion/dtls/v2 v2.2.8 h1:BUroldfiIbV9jSnC6cKOMnyiORRWrWWpV11JUyEu5OA= +github.com/pion/dtls/v2 v2.2.8/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= +github.com/pion/ice/v2 v2.3.11 h1:rZjVmUwyT55cmN8ySMpL7rsS8KYsJERsrxJLLxpKhdw= +github.com/pion/ice/v2 v2.3.11/go.mod h1:hPcLC3kxMa+JGRzMHqQzjoSj3xtE9F+eoncmXLlCL4E= +github.com/pion/interceptor v0.1.25 h1:pwY9r7P6ToQ3+IF0bajN0xmk/fNw/suTgaTdlwTDmhc= +github.com/pion/interceptor v0.1.25/go.mod h1:wkbPYAak5zKsfpVDYMtEfWEy8D4zL+rpxCxPImLOg3Y= github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= -github.com/pion/mdns v0.0.5 h1:Q2oj/JB3NqfzY9xGZ1fPzZzK7sDSD8rZPOvcIQ10BCw= -github.com/pion/mdns v0.0.5/go.mod h1:UgssrvdD3mxpi8tMxAXbsppL3vJ4Jipw1mTCW+al01g= +github.com/pion/mdns v0.0.8/go.mod h1:hYE72WX8WDveIhg7fmXgMKivD3Puklk0Ymzog0lSyaI= +github.com/pion/mdns v0.0.9 h1:7Ue5KZsqq8EuqStnpPWV33vYYEH0+skdDN5L7EiEsI4= +github.com/pion/mdns v0.0.9/go.mod h1:2JA5exfxwzXiCihmxpTKgFUpiQws2MnipoPK09vecIc= github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= -github.com/pion/rtcp v1.2.9 h1:1ujStwg++IOLIEoOiIQ2s+qBuJ1VN81KW+9pMPsif+U= -github.com/pion/rtcp v1.2.9/go.mod h1:qVPhiCzAm4D/rxb6XzKeyZiQK69yJpbUDJSF7TgrqNo= -github.com/pion/rtp v1.7.13 h1:qcHwlmtiI50t1XivvoawdCGTP4Uiypzfrsap+bijcoA= -github.com/pion/rtp v1.7.13/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko= -github.com/pion/sctp v1.8.0/go.mod h1:xFe9cLMZ5Vj6eOzpyiKjT9SwGM4KpK/8Jbw5//jc+0s= -github.com/pion/sctp v1.8.2 h1:yBBCIrUMJ4yFICL3RIvR4eh/H2BTTvlligmSTy+3kiA= -github.com/pion/sctp v1.8.2/go.mod h1:xFe9cLMZ5Vj6eOzpyiKjT9SwGM4KpK/8Jbw5//jc+0s= -github.com/pion/sdp/v3 v3.0.5 h1:ouvI7IgGl+V4CrqskVtr3AaTrPvPisEOxwgpdktctkU= -github.com/pion/sdp/v3 v3.0.5/go.mod h1:iiFWFpQO8Fy3S5ldclBkpXqmWy02ns78NOKoLLL0YQw= -github.com/pion/srtp/v2 v2.0.9 h1:JJq3jClmDFBPX/F5roEb0U19jSU7eUhyDqR/NZ34EKQ= -github.com/pion/srtp/v2 v2.0.9/go.mod h1:5TtM9yw6lsH0ppNCehB/EjEUli7VkUgKSPJqWVqbhQ4= -github.com/pion/stun v0.3.5 h1:uLUCBCkQby4S1cf6CGuR9QrVOKcvUwFeemaC865QHDg= -github.com/pion/stun v0.3.5/go.mod h1:gDMim+47EeEtfWogA37n6qXZS88L5V6LqFcf+DZA2UA= -github.com/pion/transport v0.12.2/go.mod h1:N3+vZQD9HlDP5GWkZ85LohxNsDcNgofQmyL6ojX5d8Q= -github.com/pion/transport v0.12.3/go.mod h1:OViWW9SP2peE/HbwBvARicmAVnesphkNkCVZIWJ6q9A= -github.com/pion/transport v0.13.0/go.mod h1:yxm9uXpK9bpBBWkITk13cLo1y5/ur5VQpG22ny6EP7g= -github.com/pion/transport v0.13.1 h1:/UH5yLeQtwm2VZIPjxwnNFxjS4DFhyLfS4GlfuKUzfA= -github.com/pion/transport v0.13.1/go.mod h1:EBxbqzyv+ZrmDb82XswEE0BjfQFtuw1Nu6sjnjWCsGg= -github.com/pion/transport/v2 v2.0.0 h1:bsMYyqHCbkvHwj+eNCFBuxtlKndKfyGI2vaQmM3fIE4= -github.com/pion/transport/v2 v2.0.0/go.mod h1:HS2MEBJTwD+1ZI2eSXSvHJx/HnzQqRy2/LXxt6eVMHc= -github.com/pion/turn/v2 v2.0.8 h1:KEstL92OUN3k5k8qxsXHpr7WWfrdp7iJZHx99ud8muw= -github.com/pion/turn/v2 v2.0.8/go.mod h1:+y7xl719J8bAEVpSXBXvTxStjJv3hbz9YFflvkpcGPw= -github.com/pion/udp v0.1.1/go.mod h1:6AFo+CMdKQm7UiA0eUPA8/eVCTx8jBIITLZHc9DWX5M= -github.com/pion/udp v0.1.4 h1:OowsTmu1Od3sD6i3fQUJxJn2fEvJO6L1TidgadtbTI8= -github.com/pion/udp v0.1.4/go.mod h1:G8LDo56HsFwC24LIcnT4YIDU5qcB6NepqqjP0keL2us= -github.com/pion/webrtc/v3 v3.1.42 h1:wJEQFIXVanptnQcHOLTuIo4AtGB2+mG2x4OhIhnITOA= -github.com/pion/webrtc/v3 v3.1.42/go.mod h1:ffD9DulDrPxyWvDPUIPAOSAWx9GUlOExiJPf7cCcMLA= +github.com/pion/rtcp v1.2.10/go.mod h1:ztfEwXZNLGyF1oQDttz/ZKIBaeeg/oWbRYqzBM9TL1I= +github.com/pion/rtcp v1.2.12/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4= +github.com/pion/rtcp v1.2.13 h1:+EQijuisKwm/8VBs8nWllr0bIndR7Lf7cZG200mpbNo= +github.com/pion/rtcp v1.2.13/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4= +github.com/pion/rtp v1.8.2/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= +github.com/pion/rtp v1.8.3 h1:VEHxqzSVQxCkKDSHro5/4IUUG1ea+MFdqR2R3xSpNU8= +github.com/pion/rtp v1.8.3/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= +github.com/pion/sctp v1.8.5/go.mod h1:SUFFfDpViyKejTAdwD1d/HQsCu+V/40cCs2nZIvC3s0= +github.com/pion/sctp v1.8.8/go.mod h1:igF9nZBrjh5AtmKc7U30jXltsFHicFCXSmWA2GWRaWs= +github.com/pion/sctp v1.8.9 h1:TP5ZVxV5J7rz7uZmbyvnUvsn7EJ2x/5q9uhsTtXbI3g= +github.com/pion/sctp v1.8.9/go.mod h1:cMLT45jqw3+jiJCrtHVwfQLnfR0MGZ4rgOJwUOIqLkI= +github.com/pion/sdp/v3 v3.0.6 h1:WuDLhtuFUUVpTfus9ILC4HRyHsW6TdugjEX/QY9OiUw= +github.com/pion/sdp/v3 v3.0.6/go.mod h1:iiFWFpQO8Fy3S5ldclBkpXqmWy02ns78NOKoLLL0YQw= +github.com/pion/srtp/v2 v2.0.18 h1:vKpAXfawO9RtTRKZJbG4y0v1b11NZxQnxRl85kGuUlo= +github.com/pion/srtp/v2 v2.0.18/go.mod h1:0KJQjA99A6/a0DOVTu1PhDSw0CXF2jTkqOoMg3ODqdA= +github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4= +github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8= +github.com/pion/transport v0.14.1 h1:XSM6olwW+o8J4SCmOBb/BpwZypkHeyM0PGFCxNQBr40= +github.com/pion/transport v0.14.1/go.mod h1:4tGmbk00NeYA3rUa9+n+dzCCoKkcy3YlYb99Jn2fNnI= +github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g= +github.com/pion/transport/v2 v2.2.2/go.mod h1:OJg3ojoBJopjEeECq2yJdXH9YVrUJ1uQ++NjXLOUorc= +github.com/pion/transport/v2 v2.2.3/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= +github.com/pion/transport/v2 v2.2.4 h1:41JJK6DZQYSeVLxILA2+F4ZkKb4Xd/tFJZRFZQ9QAlo= +github.com/pion/transport/v2 v2.2.4/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= +github.com/pion/transport/v3 v3.0.1 h1:gDTlPJwROfSfz6QfSi0ZmeCSkFcnWWiiR9ES0ouANiM= +github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0= +github.com/pion/turn/v2 v2.1.3/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= +github.com/pion/turn/v2 v2.1.4 h1:2xn8rduI5W6sCZQkEnIUDAkrBQNl2eYIBCHMZ3QMmP8= +github.com/pion/turn/v2 v2.1.4/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= +github.com/pion/webrtc/v3 v3.2.24 h1:MiFL5DMo2bDaaIFWr0DDpwiV/L4EGbLZb+xoRvfEo1Y= +github.com/pion/webrtc/v3 v3.2.24/go.mod h1:1CaT2fcZzZ6VZA+O1i9yK2DU4EOcXVvSbWG9pr5jefs= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -439,6 +481,8 @@ github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/rasky/go-xdr v0.0.0-20170124162913-1a41d1a06c93 h1:UVArwN/wkKjMVhh2EQGC0tEc1+FqiLlvYXY5mQ2f8Wg= +github.com/rasky/go-xdr v0.0.0-20170124162913-1a41d1a06c93/go.mod h1:Nfe4efndBz4TibWycNE+lqyJZiMX4ycx+QKV8Ta0f/o= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= @@ -446,10 +490,11 @@ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qq github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rs/dnscache v0.0.0-20211102005908-e0241e321417 h1:Lt9DzQALzHoDwMBGJ6v8ObDPR0dzr2a6sXTB1Fq7IHs= -github.com/rs/dnscache v0.0.0-20211102005908-e0241e321417/go.mod h1:qe5TWALJ8/a1Lqznoc5BDHpYX/8HU60Hm2AwRmqzxqA= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +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/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A= github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= @@ -485,58 +530,70 @@ github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 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/tidwall/btree v1.6.0 h1:LDZfKfQIBHGHWSwckhXI0RPSXzlo+KYdjK7FWSqOzzg= -github.com/tidwall/btree v1.6.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY= +github.com/tidwall/btree v1.7.0 h1:L1fkJH/AuEh5zBnnBbmTwQ5Lt+bRJ5A8EWecslvo9iI= +github.com/tidwall/btree v1.7.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY= github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= -github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= -github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= +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.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= -github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= -github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= +github.com/urfave/cli/v2 v2.26.0 h1:3f3AMg3HpThFNT4I++TKOejZO8yU55t3JnnSr4S4QEI= +github.com/urfave/cli/v2 v2.26.0/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= 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/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= -github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= +github.com/willscott/go-nfs v0.0.1 h1:392gV283iuisKFeV9hkKwTdCRfizP+R9FC+gYg2skj0= +github.com/willscott/go-nfs v0.0.1/go.mod h1:hBPyqKNde3v8rzxDVWtloP6MtLnx/7aVz3XxxP89W7k= +github.com/willscott/go-nfs-client v0.0.0-20200605172546-271fa9065b33 h1:Wd8wdpRzPXskyHvZLyw7Wc1fp5oCE2mhBCj7bAiibUs= +github.com/willscott/go-nfs-client v0.0.0-20200605172546-271fa9065b33/go.mod h1:cOUKSNty+RabZqKhm5yTJT5Vq/Fe83ZRWAJ5Kj8nRes= +github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e h1:+SOyEddqYF09QP7vr7CgJ1eti3pY9Fn3LHO1M1r/0sI= +github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= -go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= +github.com/zema1/go-nfs-client v0.0.0-20200604081958-0cf942f0e0fe/go.mod h1:im3CVJ32XM3+E+2RhY0sa5IVJVQehUrX0oE1wX4xOwU= +go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA= +go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= 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.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.5 h1:dntmOdLpSpHlVqbW5Eay97DelsZHe+55D+xC6i0dDS0= -go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opentelemetry.io/otel v1.8.0 h1:zcvBFizPbpa1q7FehvFiHbQwGzmPILebO0tyqIR5Djg= -go.opentelemetry.io/otel v1.8.0/go.mod h1:2pkj+iMj0o03Y+cW6/m8Y4WkRdYN3AvCXCnzRMp9yvM= -go.opentelemetry.io/otel/trace v1.8.0 h1:cSy0DF9eGI5WIfNwZ1q2iUyGj00tGzP24dE1lOlHrfY= -go.opentelemetry.io/otel/trace v1.8.0/go.mod h1:0Bt3PXY8w+3pheS3hQUt+wow8b1ojPaTBoTCh2zIFI4= -go4.org v0.0.0-20200411211856-f5505b9728dd h1:BNJlw5kRTzdmyfh5U8F93HA2OwkP7ZGwA51eJ/0wKOU= -go4.org v0.0.0-20200411211856-f5505b9728dd/go.mod h1:CIiUVy99QCPfoE13bO4EZaz5GZMZXMSBGhxRdsvzbkg= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= +go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= +go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= +go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= +go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= +go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= +go4.org v0.0.0-20230225012048-214862532bf5 h1:nifaUDeh+rPaBCMPMQHZmvJf+QdpLFnuQPwx+LxVmtc= +go4.org v0.0.0-20230225012048-214862532bf5/go.mod h1:F57wTi5Lrj6WLyswp5EYV1ncrEbFGHD4hhz6S1ZYeaU= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= -golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.6.0 h1:S0JTfE48HbRj80+4tbvZDYsJ3tGv6BUU3XxyZ7CirAc= +golang.org/x/arch v0.6.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= golang.org/x/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-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-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-20220131195533-30dcbda58838/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220516162934-403b01795ae8/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= +golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= +golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= +golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -545,8 +602,9 @@ golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME= -golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= +golang.org/x/exp v0.0.0-20220428152302-39d4317da171/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= +golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611 h1:qCEDpW1G+vcj3Y7Fy52pEM1AWm3abj8WimGYejI3SC4= +golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -565,7 +623,10 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -583,26 +644,25 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201201195509-5d6afe98e0b7/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211201190559-0a0e4e1bb54c/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220401154927-543a649e0bdd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220531201128-c960675eff93/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= +golang.org/x/net v0.6.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.16.0 h1:7eBu7KsSvFDtSXUIDbh3aqlK4DPsZ1rByC8PFfBThos= -golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= +golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= 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-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -615,9 +675,11 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/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-20201020160332-67f06af15bc9/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.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -640,36 +702,42 @@ golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/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-20211216021012-1d35b9e2eb4e/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-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220608164250-635b8c9b7f68/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.4.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.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= +golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -678,14 +746,18 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.6.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.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20220609170525-579cf78fd858 h1:Dpdu/EMxGMFgq0CeYMh4fazTD2vtlZRYE7wyynxJb9U= -golang.org/x/time v0.0.0-20220609170525-579cf78fd858/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -714,9 +786,11 @@ golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +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.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM= +golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -748,29 +822,37 @@ google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvx google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/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/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= @@ -783,6 +865,7 @@ gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/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-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -799,6 +882,7 @@ modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds= modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= modernc.org/sqlite v1.21.1 h1:GyDFqNnESLOhwwDRaHGdp2jKLDzpyT/rNLglX3ZkMSU= modernc.org/sqlite v1.21.1/go.mod h1:XwQ0wZPIh1iKb5mkvCJ3szzbhk+tykC8ZWqTRTgYRwI= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= diff --git a/src/config/default.go b/src/config/default.go index 488d633..0d267b3 100644 --- a/src/config/default.go +++ b/src/config/default.go @@ -20,6 +20,10 @@ var defaultConfig = Config{ Fuse: Fuse{ Enabled: false, }, + NFS: NFS{ + Enabled: false, + Port: 8122, + }, }, TorrentClient: TorrentClient{ diff --git a/src/config/load.go b/src/config/load.go index 5ccb1d9..9f7a78e 100644 --- a/src/config/load.go +++ b/src/config/load.go @@ -42,7 +42,10 @@ func Load(path string) (*Config, error) { } conf := Config{} - k.Unmarshal("", &conf) + err = k.Unmarshal("", &conf) + if err != nil { + return nil, err + } return &conf, nil } diff --git a/src/config/model.go b/src/config/model.go index f7c9fd9..d967ae8 100644 --- a/src/config/model.go +++ b/src/config/model.go @@ -61,6 +61,12 @@ type Mounts struct { WebDAV WebDAV `koanf:"webdav"` HttpFs HttpFs `koanf:"httpfs"` Fuse Fuse `koanf:"fuse"` + NFS NFS `koanf:"nfs"` +} + +type NFS struct { + Enabled bool `koanf:"enabled"` + Port int `koanf:"port"` } type HttpFs struct { diff --git a/src/host/storage.go b/src/host/storage.go index 8372068..c080d72 100644 --- a/src/host/storage.go +++ b/src/host/storage.go @@ -5,11 +5,7 @@ import ( "git.kmsign.ru/royalcat/tstor/src/host/vfs" ) -type storage struct { - factories map[string]vfs.FsFactory -} - -func NewStorage(downPath string, tsrv *torrent.Service) vfs.Filesystem { +func NewStorage(dataPath string, tsrv *torrent.Service) vfs.Filesystem { factories := map[string]vfs.FsFactory{ ".torrent": tsrv.NewTorrentFs, } @@ -19,102 +15,5 @@ func NewStorage(downPath string, tsrv *torrent.Service) vfs.Filesystem { factories[k] = v } - return vfs.NewResolveFS(downPath, factories) + return vfs.NewResolveFS(vfs.NewOsFs(dataPath), factories) } - -// func (s *storage) Clear() { -// s.files = make(map[string]vfs.File) -// } - -// func (s *storage) Has(path string) bool { -// path = clean(path) - -// f := s.files[path] -// if f != nil { -// return true -// } - -// if f, _ := s.getFileFromFs(path); f != nil { -// return true -// } - -// return false -// } - -// func (s *storage) createParent(p string, f File) error { -// base, filename := path.Split(p) -// base = clean(base) - -// if err := s.Add(&Dir{}, base); err != nil { -// return err -// } - -// if _, ok := s.children[base]; !ok { -// s.children[base] = make(map[string]File) -// } - -// if filename != "" { -// s.children[base][filename] = f -// } - -// return nil -// } - -// func (s *storage) Children(path string) (map[string]File, error) { -// path = clean(path) - -// files, err := s.getDirFromFs(path) -// if err == nil { -// return files, nil -// } - -// if !os.IsNotExist(err) { -// return nil, err -// } - -// l := make(map[string]File) -// for n, f := range s.children[path] { -// l[n] = f -// } - -// return l, nil -// } - -// func (s *storage) Get(path string) (File, error) { -// path = clean(path) -// if !s.Has(path) { -// return nil, os.ErrNotExist -// } - -// file, ok := s.files[path] -// if ok { -// return file, nil -// } - -// return s.getFileFromFs(path) -// } - -// func (s *storage) getFileFromFs(p string) (File, error) { -// for fsp, fs := range s.filesystems { -// if strings.HasPrefix(p, fsp) { -// return fs.Open(separator + strings.TrimPrefix(p, fsp)) -// } -// } - -// return nil, os.ErrNotExist -// } - -// func (s *storage) getDirFromFs(p string) (map[string]File, error) { -// for fsp, fs := range s.filesystems { -// if strings.HasPrefix(p, fsp) { -// path := strings.TrimPrefix(p, fsp) -// return fs.ReadDir(path) -// } -// } - -// return nil, os.ErrNotExist -// } - -// func clean(p string) string { -// return path.Clean(separator + strings.ReplaceAll(p, "\\", "/")) -// } diff --git a/src/host/torrent/client.go b/src/host/torrent/client.go index f0936d7..d432883 100644 --- a/src/host/torrent/client.go +++ b/src/host/torrent/client.go @@ -17,10 +17,22 @@ import ( func NewClient(st storage.ClientImpl, fis bep44.Store, cfg *config.TorrentClient, id [20]byte) (*torrent.Client, error) { // TODO download and upload limits torrentCfg := torrent.NewDefaultClientConfig() - torrentCfg.Seed = true torrentCfg.PeerID = string(id[:]) torrentCfg.DefaultStorage = st - torrentCfg.DisableIPv6 = cfg.DisableIPv6 + + // torrentCfg.DisableIPv6 = cfg.DisableIPv6 + // torrentCfg.DropDuplicatePeerIds = true + // torrentCfg.TorrentPeersLowWater = 10 + // torrentCfg.TorrentPeersHighWater = 100 + // torrentCfg.DisableWebtorrent = true + // torrentCfg.DisableAggressiveUpload = true + // torrentCfg.DisableWebseeds = true + // torrentCfg.DisableUTP = false + // torrentCfg.NoDefaultPortForwarding = true + // torrentCfg.AlwaysWantConns = false + // torrentCfg.ClientDhtConfig = torrent.ClientDhtConfig{ + // NoDHT: true, + // } l := log.Logger.With().Str("component", "torrent-client").Logger() diff --git a/src/host/torrent/piece-completion.go b/src/host/torrent/piece-completion.go new file mode 100644 index 0000000..4b7eeec --- /dev/null +++ b/src/host/torrent/piece-completion.go @@ -0,0 +1,131 @@ +package torrent + +import ( + "encoding/binary" + "fmt" + "log/slog" + + "github.com/anacrolix/torrent/metainfo" + "github.com/anacrolix/torrent/storage" + "github.com/dgraph-io/badger/v4" +) + +type PieceCompletionState byte + +const ( + PieceNotComplete PieceCompletionState = 0 + PieceComplete PieceCompletionState = 1<<8 - 1 +) + +func pieceCompletionState(i bool) PieceCompletionState { + if i { + return PieceComplete + } else { + return PieceNotComplete + } +} + +type badgerPieceCompletion struct { + db *badger.DB +} + +var _ storage.PieceCompletion = (*badgerPieceCompletion)(nil) + +func NewBadgerPieceCompletion(dir string) (storage.PieceCompletion, error) { + opts := badger. + DefaultOptions(dir). + WithLogger(badgerSlog{slog: slog.With("component", "piece-completion")}) + db, err := badger.Open(opts) + if err != nil { + return nil, err + } + return &badgerPieceCompletion{db}, nil +} + +func pkToBytes(pk metainfo.PieceKey) []byte { + key := make([]byte, len(pk.InfoHash.Bytes())) + copy(key, pk.InfoHash.Bytes()) + binary.BigEndian.AppendUint32(key, uint32(pk.Index)) + return key +} + +func (k *badgerPieceCompletion) Get(pk metainfo.PieceKey) (storage.Completion, error) { + completion := storage.Completion{ + Ok: true, + } + err := k.db.View(func(tx *badger.Txn) error { + item, err := tx.Get(pkToBytes(pk)) + if err != nil { + if err == badger.ErrKeyNotFound { + completion.Ok = false + return nil + } + + return fmt.Errorf("getting value: %w", err) + } + + valCopy, err := item.ValueCopy(nil) + if err != nil { + return fmt.Errorf("copying value: %w", err) + } + compl := PieceCompletionState(valCopy[0]) + + completion.Ok = true + switch compl { + case PieceComplete: + completion.Complete = true + case PieceNotComplete: + completion.Complete = false + } + + return nil + }) + return completion, err +} + +func (me badgerPieceCompletion) Set(pk metainfo.PieceKey, b bool) error { + if c, err := me.Get(pk); err == nil && c.Ok && c.Complete == b { + return nil + } + + return me.db.Update(func(txn *badger.Txn) error { + return txn.Set(pkToBytes(pk), []byte{byte(pieceCompletionState(b))}) + }) +} + +func (k *badgerPieceCompletion) Delete(key string) error { + return k.db.Update( + func(txn *badger.Txn) error { + return txn.Delete([]byte(key)) + }) +} + +func (me *badgerPieceCompletion) Close() error { + return me.db.Close() +} + +type badgerSlog struct { + slog *slog.Logger +} + +// Debugf implements badger.Logger. +func (log badgerSlog) Debugf(f string, a ...interface{}) { + log.slog.Debug(f, a...) +} + +// Errorf implements badger.Logger. +func (log badgerSlog) Errorf(f string, a ...interface{}) { + log.slog.Error(f, a...) +} + +// Infof implements badger.Logger. +func (log badgerSlog) Infof(f string, a ...interface{}) { + log.slog.Info(f, a...) +} + +// Warningf implements badger.Logger. +func (log badgerSlog) Warningf(f string, a ...interface{}) { + log.slog.Warn(f, a...) +} + +var _ badger.Logger = (*badgerSlog)(nil) diff --git a/src/host/torrent/service.go b/src/host/torrent/service.go index b251aff..7a074de 100644 --- a/src/host/torrent/service.go +++ b/src/host/torrent/service.go @@ -1,31 +1,33 @@ package torrent import ( - "sync" + "context" + "fmt" + "log/slog" + "time" "git.kmsign.ru/royalcat/tstor/src/host/vfs" "github.com/anacrolix/torrent" "github.com/anacrolix/torrent/metainfo" - "github.com/rs/zerolog" - "github.com/rs/zerolog/log" + "github.com/anacrolix/torrent/types" ) type Service struct { c *torrent.Client // stats *Stats + DefaultPriority types.PiecePriority - mu sync.Mutex - - log zerolog.Logger + log *slog.Logger addTimeout, readTimeout int } func NewService(c *torrent.Client, addTimeout, readTimeout int) *Service { - l := log.Logger.With().Str("component", "torrent-service").Logger() + l := slog.With("component", "torrent-service") return &Service{ - log: l, - c: c, + log: l, + c: c, + DefaultPriority: types.PiecePriorityNone, // stats: newStats(), // TODO persistent addTimeout: addTimeout, readTimeout: readTimeout, @@ -35,20 +37,30 @@ func NewService(c *torrent.Client, addTimeout, readTimeout int) *Service { var _ vfs.FsFactory = (*Service)(nil).NewTorrentFs func (s *Service) NewTorrentFs(f vfs.File) (vfs.Filesystem, error) { + ctx, cancel := context.WithTimeout(context.TODO(), time.Second*time.Duration(s.addTimeout)) + defer cancel() defer f.Close() mi, err := metainfo.Load(f) if err != nil { return nil, err } - t, err := s.c.AddTorrent(mi) - if err != nil { - return nil, err - } - <-t.GotInfo() - t.AllowDataDownload() - for _, f := range t.Files() { - f.SetPriority(torrent.PiecePriorityReadahead) + + t, ok := s.c.Torrent(mi.HashInfoBytes()) + if !ok { + t, err = s.c.AddTorrent(mi) + if err != nil { + return nil, err + } + select { + case <-ctx.Done(): + return nil, fmt.Errorf("creating torrent fs timed out") + case <-t.GotInfo(): + } + for _, f := range t.Files() { + f.SetPriority(s.DefaultPriority) + } + t.AllowDataDownload() } return vfs.NewTorrentFs(t, s.readTimeout), nil @@ -57,161 +69,3 @@ func (s *Service) NewTorrentFs(f vfs.File) (vfs.Filesystem, error) { func (s *Service) Stats() (*Stats, error) { return &Stats{}, nil } - -// func (s *Service) Load() (map[string]vfs.Filesystem, error) { -// // Load from config -// s.log.Info().Msg("adding torrents from configuration") -// for _, loader := range s.loaders { -// if err := s.load(loader); err != nil { -// return nil, err -// } -// } - -// // Load from DB -// s.log.Info().Msg("adding torrents from database") -// return s.fss, s.load(s.db) -// } - -// func (s *Service) load(l loader.Loader) error { -// list, err := l.ListMagnets() -// if err != nil { -// return err -// } -// for r, ms := range list { -// s.addRoute(r) -// for _, m := range ms { -// if err := s.addMagnet(r, m); err != nil { -// return err -// } -// } -// } - -// list, err = l.ListTorrentPaths() -// if err != nil { -// return err -// } -// for r, ms := range list { -// s.addRoute(r) -// for _, p := range ms { -// if err := s.addTorrentPath(r, p); err != nil { -// return err -// } -// } -// } - -// return nil -// } - -// func (s *Service) AddMagnet(r, m string) error { -// if err := s.addMagnet(r, m); err != nil { -// return err -// } - -// // Add to db -// return s.db.AddMagnet(r, m) -// } - -// func (s *Service) addTorrentPath(r, p string) error { -// // Add to client -// t, err := s.c.AddTorrentFromFile(p) -// if err != nil { -// return err -// } - -// return s.addTorrent(r, t) -// } - -// func (s *Service) addMagnet(r, m string) error { -// // Add to client -// t, err := s.c.AddMagnet(m) -// if err != nil { -// return err -// } - -// return s.addTorrent(r, t) - -// } - -// func (s *Service) addRoute(r string) { -// s.s.AddRoute(r) - -// // Add to filesystems -// folder := path.Join("/", r) -// s.mu.Lock() -// defer s.mu.Unlock() -// _, ok := s.fss[folder] -// if !ok { -// s.fss[folder] = vfs.NewTorrentFs(s.readTimeout) -// } -// } - -// func (s *Service) addTorrent(r string, t *torrent.Torrent) error { -// // only get info if name is not available -// if t.Info() == nil { -// s.log.Info().Str("hash", t.InfoHash().String()).Msg("getting torrent info") -// select { -// case <-time.After(time.Duration(s.addTimeout) * time.Second): -// s.log.Error().Str("hash", t.InfoHash().String()).Msg("timeout getting torrent info") -// return errors.New("timeout getting torrent info") -// case <-t.GotInfo(): -// s.log.Info().Str("hash", t.InfoHash().String()).Msg("obtained torrent info") -// } - -// } - -// // Add to stats -// s.s.Add(r, t) - -// // Add to filesystems -// folder := path.Join("/", r) -// s.mu.Lock() -// defer s.mu.Unlock() - -// tfs, ok := s.fss[folder].(*vfs.TorrentFs) -// if !ok { -// return errors.New("error adding torrent to filesystem") -// } - -// tfs.AddTorrent(t) -// s.log.Info().Str("name", t.Info().Name).Str("route", r).Msg("torrent added") - -// return nil -// } - -// func (s *Service) RemoveFromHash(r, h string) error { -// // Remove from db -// deleted, err := s.db.RemoveFromHash(r, h) -// if err != nil { -// return err -// } - -// if !deleted { -// return fmt.Errorf("element with hash %v on route %v cannot be removed", h, r) -// } - -// // Remove from stats -// s.s.Del(r, h) - -// // Remove from fs -// folder := path.Join("/", r) - -// tfs, ok := s.fss[folder].(*vfs.TorrentFs) -// if !ok { -// return errors.New("error removing torrent from filesystem") -// } - -// tfs.RemoveTorrent(h) - -// // Remove from client -// var mh metainfo.Hash -// if err := mh.FromHexString(h); err != nil { -// return err -// } - -// t, ok := s.c.Torrent(metainfo.NewHashFromHex(h)) -// if ok { -// t.Drop() -// } - -// return nil -// } diff --git a/src/host/torrent/storage.go b/src/host/torrent/storage.go new file mode 100644 index 0000000..24f694a --- /dev/null +++ b/src/host/torrent/storage.go @@ -0,0 +1,306 @@ +package torrent + +import ( + "errors" + "fmt" + "io" + "os" + "path/filepath" + + "git.kmsign.ru/royalcat/tstor/src/config" + "github.com/anacrolix/missinggo" + "github.com/anacrolix/torrent" + "github.com/anacrolix/torrent/metainfo" + "github.com/anacrolix/torrent/mmap_span" + "github.com/anacrolix/torrent/storage" + "github.com/edsrzf/mmap-go" +) + +type Torrent struct { + client *torrent.Client + data storage.ClientImplCloser + pc storage.PieceCompletion +} + +func SetupStorage(cfg config.TorrentClient) (storage.ClientImplCloser, storage.PieceCompletion, error) { + pcp := filepath.Join(cfg.DataFolder, "piece-completion") + if err := os.MkdirAll(pcp, 0744); err != nil { + return nil, nil, fmt.Errorf("error creating piece completion folder: %w", err) + } + pc, err := storage.NewBoltPieceCompletion(pcp) + if err != nil { + return nil, nil, fmt.Errorf("error creating servers piece completion: %w", err) + } + + // pc, err := NewBadgerPieceCompletion(pcp) + // if err != nil { + // return nil, nil, fmt.Errorf("error creating servers piece completion: %w", err) + // } + + // TODO implement cache/storage switching + // cacheDir := filepath.Join(tcfg.DataFolder, "cache") + // if err := os.MkdirAll(cacheDir, 0744); err != nil { + // return nil, nil, fmt.Errorf("error creating piece completion folder: %w", err) + // } + // fc, err := filecache.NewCache(cacheDir) + // if err != nil { + // return nil, nil, fmt.Errorf("error creating cache: %w", err) + // } + // log.Info().Msg(fmt.Sprintf("setting cache size to %d MB", 1024)) + // fc.SetCapacity(1024 * 1024 * 1024) + + // rp := storage.NewResourcePieces(fc.AsResourceProvider()) + // st := &stc{rp} + + filesDir := filepath.Join(cfg.DataFolder, "files") + if err := os.MkdirAll(pcp, 0744); err != nil { + return nil, nil, fmt.Errorf("error creating piece completion folder: %w", err) + } + + // st := storage.NewMMapWithCompletion(filesDir, pc) + st := storage.NewFileOpts(storage.NewFileClientOpts{ + ClientBaseDir: filesDir, + PieceCompletion: pc, + }) + + return st, pc, nil +} + +func (s Torrent) Remove(f *torrent.File) error { + + return nil +} + +// type dupePieces struct { +// } + +// func (s Torrent) dedupe(f1, f2 *os.File) error { +// for _, t := range s.client.Torrents() { +// for i := 0; i < t.NumPieces(); i++ { +// p := t.Piece(i) +// p.Info().Hash() +// } +// } + +// // https://go-review.googlesource.com/c/sys/+/284352/10/unix/syscall_linux_test.go#856 +// // dedupe := unix.FileDedupeRange{ +// // Src_offset: uint64(0), +// // Src_length: uint64(4096), +// // Info: []unix.FileDedupeRangeInfo{ +// // unix.FileDedupeRangeInfo{ +// // Dest_fd: int64(f2.Fd()), +// // Dest_offset: uint64(0), +// // }, +// // unix.FileDedupeRangeInfo{ +// // Dest_fd: int64(f2.Fd()), +// // Dest_offset: uint64(4096), +// // }, +// // }} +// // err := unix.IoctlFileDedupeRange(int(f1.Fd()), &dedupe) +// // if err == unix.EOPNOTSUPP || err == unix.EINVAL { +// // t.Skip("deduplication not supported on this filesystem") +// // } else if err != nil { +// // t.Fatal(err) +// // } + +// return nil +// } + +type mmapClientImpl struct { + baseDir string + pc storage.PieceCompletion +} + +func NewMMapWithCompletion(baseDir string, completion storage.PieceCompletion) *mmapClientImpl { + return &mmapClientImpl{ + baseDir: baseDir, + pc: completion, + } +} + +func (s *mmapClientImpl) OpenTorrent(info *metainfo.Info, infoHash metainfo.Hash) (_ storage.TorrentImpl, err error) { + t, err := newMMapTorrent(info, infoHash, s.baseDir, s.pc) + if err != nil { + return storage.TorrentImpl{}, err + } + return storage.TorrentImpl{Piece: t.Piece, Close: t.Close, Flush: t.Flush}, nil +} + +func (s *mmapClientImpl) Close() error { + return s.pc.Close() +} + +func newMMapTorrent(md *metainfo.Info, infoHash metainfo.Hash, location string, pc storage.PieceCompletionGetSetter) (*mmapTorrent, error) { + span := &mmap_span.MMapSpan{} + basePath, err := storage.ToSafeFilePath(md.Name) + if err != nil { + return nil, err + } + basePath = filepath.Join(location, basePath) + + for _, miFile := range md.UpvertedFiles() { + var safeName string + safeName, err = storage.ToSafeFilePath(miFile.Path...) + if err != nil { + return nil, err + } + fileName := filepath.Join(basePath, safeName) + var mm FileMapping + mm, err = mmapFile(fileName, miFile.Length) + if err != nil { + err = fmt.Errorf("file %q: %s", miFile.DisplayPath(md), err) + return nil, err + } + span.Append(mm) + } + span.InitIndex() + + return &mmapTorrent{ + infoHash: infoHash, + span: span, + pc: pc, + }, nil +} + +type mmapTorrent struct { + infoHash metainfo.Hash + span *mmap_span.MMapSpan + pc storage.PieceCompletionGetSetter +} + +func (ts *mmapTorrent) Piece(p metainfo.Piece) storage.PieceImpl { + return mmapPiece{ + pc: ts.pc, + p: p, + ih: ts.infoHash, + ReaderAt: io.NewSectionReader(ts.span, p.Offset(), p.Length()), + WriterAt: missinggo.NewSectionWriter(ts.span, p.Offset(), p.Length()), + } +} + +func (ts *mmapTorrent) Close() error { + errs := ts.span.Close() + if len(errs) > 0 { + return errs[0] + } + return nil +} + +func (ts *mmapTorrent) Flush() error { + errs := ts.span.Flush() + if len(errs) > 0 { + return errs[0] + } + return nil +} + +type mmapPiece struct { + pc storage.PieceCompletionGetSetter + p metainfo.Piece + ih metainfo.Hash + io.ReaderAt + io.WriterAt +} + +func (me mmapPiece) pieceKey() metainfo.PieceKey { + return metainfo.PieceKey{InfoHash: me.ih, Index: me.p.Index()} +} + +func (sp mmapPiece) Completion() storage.Completion { + c, err := sp.pc.Get(sp.pieceKey()) + if err != nil { + panic(err) + } + return c +} + +func (sp mmapPiece) MarkComplete() error { + return sp.pc.Set(sp.pieceKey(), true) +} + +func (sp mmapPiece) MarkNotComplete() error { + return sp.pc.Set(sp.pieceKey(), false) +} + +func mmapFile(name string, size int64) (_ FileMapping, err error) { + dir := filepath.Dir(name) + err = os.MkdirAll(dir, 0o750) + if err != nil { + return nil, fmt.Errorf("making directory %q: %s", dir, err) + } + var file *os.File + file, err = os.OpenFile(name, os.O_CREATE|os.O_RDWR, 0o666) + if err != nil { + return nil, err + } + defer func() { + if err != nil { + file.Close() + } + }() + var fi os.FileInfo + fi, err = file.Stat() + if err != nil { + return nil, err + } + if fi.Size() < size { + // I think this is necessary on HFS+. Maybe Linux will SIGBUS too if + // you overmap a file but I'm not sure. + err = file.Truncate(size) + if err != nil { + return nil, err + } + } + return func() (ret mmapWithFile, err error) { + ret.f = file + if size == 0 { + // Can't mmap() regions with length 0. + return + } + intLen := int(size) + if int64(intLen) != size { + err = errors.New("size too large for system") + return + } + ret.mmap, err = mmap.MapRegion(file, intLen, mmap.RDWR, 0, 0) + if err != nil { + err = fmt.Errorf("error mapping region: %s", err) + return + } + if int64(len(ret.mmap)) != size { + panic(len(ret.mmap)) + } + return + }() +} + +type FileMapping = mmap_span.Mmap + +// Handles closing the mmap's file handle (needed for Windows). Could be implemented differently by +// OS. +type mmapWithFile struct { + f *os.File + mmap mmap.MMap +} + +func (m mmapWithFile) Flush() error { + return m.mmap.Flush() +} + +func (m mmapWithFile) Unmap() (err error) { + if m.mmap != nil { + err = m.mmap.Unmap() + } + fileErr := m.f.Close() + if err == nil { + err = fileErr + } + return +} + +func (m mmapWithFile) Bytes() []byte { + if m.mmap == nil { + return nil + } + return m.mmap +} diff --git a/src/host/vfs/archive.go b/src/host/vfs/archive.go index 3963689..585f7f9 100644 --- a/src/host/vfs/archive.go +++ b/src/host/vfs/archive.go @@ -3,8 +3,11 @@ package vfs import ( "archive/zip" "io" + "io/fs" "os" + "path" "path/filepath" + "strings" "sync" "git.kmsign.ru/royalcat/tstor/src/iio" @@ -46,6 +49,8 @@ func NewArchive(r iio.Reader, size int64, loader ArchiveLoader) *archive { } } +var _ Filesystem = &archive{} + func (a *archive) Open(filename string) (File, error) { files, err := a.files() if err != nil { @@ -55,28 +60,56 @@ func (a *archive) Open(filename string) (File, error) { return getFile(files, filename) } -func (fs *archive) ReadDir(path string) (map[string]File, error) { +func (fs *archive) ReadDir(path string) ([]fs.DirEntry, error) { files, err := fs.files() if err != nil { return nil, err } - return listFilesInDir(files, path) + return listDirFromFiles(files, path) +} + +// Stat implements Filesystem. +func (afs *archive) Stat(filename string) (fs.FileInfo, error) { + files, err := afs.files() + if err != nil { + return nil, err + } + + if file, ok := files[filename]; ok { + return newFileInfo(path.Base(filename), file.Size()), nil + } + + for p, _ := range files { + if strings.HasPrefix(p, filename) { + return newDirInfo(path.Base(filename)), nil + } + } + + return nil, ErrNotExist + } var _ File = &archiveFile{} -func NewArchiveFile(readerFunc func() (iio.Reader, error), len int64) *archiveFile { +func NewArchiveFile(name string, readerFunc func() (iio.Reader, error), size int64) *archiveFile { return &archiveFile{ + name: name, readerFunc: readerFunc, - len: len, + size: size, } } type archiveFile struct { + name string + readerFunc func() (iio.Reader, error) reader iio.Reader - len int64 + size int64 +} + +func (d *archiveFile) Stat() (fs.FileInfo, error) { + return newFileInfo(d.name, d.size), nil } func (d *archiveFile) load() error { @@ -94,7 +127,7 @@ func (d *archiveFile) load() error { } func (d *archiveFile) Size() int64 { - return d.len + return d.size } func (d *archiveFile) IsDir() bool { @@ -151,7 +184,7 @@ func ZipLoader(reader iio.Reader, size int64) (map[string]*archiveFile, error) { } n := filepath.Join(string(os.PathSeparator), f.Name) - af := NewArchiveFile(rf, f.FileInfo().Size()) + af := NewArchiveFile(f.Name, rf, f.FileInfo().Size()) out[n] = af } @@ -183,7 +216,7 @@ func SevenZipLoader(reader iio.Reader, size int64) (map[string]*archiveFile, err return iio.NewDiskTeeReader(zr) } - af := NewArchiveFile(rf, f.FileInfo().Size()) + af := NewArchiveFile(f.Name, rf, f.FileInfo().Size()) n := filepath.Join(string(os.PathSeparator), f.Name) out[n] = af @@ -216,7 +249,7 @@ func RarLoader(reader iio.Reader, size int64) (map[string]*archiveFile, error) { n := filepath.Join(string(os.PathSeparator), header.Name) - af := NewArchiveFile(rf, header.UnPackedSize) + af := NewArchiveFile(header.Name, rf, header.UnPackedSize) out[n] = af } diff --git a/src/host/vfs/archive_test.go b/src/host/vfs/archive_test.go index 0383b56..a984d92 100644 --- a/src/host/vfs/archive_test.go +++ b/src/host/vfs/archive_test.go @@ -16,18 +16,21 @@ func TestZipFilesystem(t *testing.T) { t.Parallel() require := require.New(t) - zReader, len := createTestZip(require) + zReader, size := createTestZip(require) - zfs := NewArchive(zReader, len, ZipLoader) + zfs := NewArchive(zReader, size, ZipLoader) files, err := zfs.ReadDir("/path/to/test/file") require.NoError(err) require.Len(files, 1) - f := files["1.txt"] - require.NotNil(f) + e := files[0] + require.Equal("1.txt", e.Name()) + require.NotNil(e) out := make([]byte, 11) + f, err := zfs.Open("/path/to/test/file/1.txt") + require.NoError(err) n, err := f.Read(out) require.Equal(io.EOF, err) require.Equal(11, n) diff --git a/src/host/vfs/dir.go b/src/host/vfs/dir.go index 3077321..fc0c1a0 100644 --- a/src/host/vfs/dir.go +++ b/src/host/vfs/dir.go @@ -1,26 +1,43 @@ package vfs -var _ File = &Dir{} +import ( + "io/fs" + "path" +) -type Dir struct { +var _ File = &dir{} + +func NewDir(name string) File { + return &dir{ + name: path.Base(name), + } } -func (d *Dir) Size() int64 { +type dir struct { + name string +} + +// Info implements File. +func (d *dir) Stat() (fs.FileInfo, error) { + return newDirInfo(d.name), nil +} + +func (d *dir) Size() int64 { return 0 } -func (d *Dir) IsDir() bool { +func (d *dir) IsDir() bool { return true } -func (d *Dir) Close() error { +func (d *dir) Close() error { return nil } -func (d *Dir) Read(p []byte) (n int, err error) { +func (d *dir) Read(p []byte) (n int, err error) { return 0, nil } -func (d *Dir) ReadAt(p []byte, off int64) (n int, err error) { +func (d *dir) ReadAt(p []byte, off int64) (n int, err error) { return 0, nil } diff --git a/src/host/vfs/fs.go b/src/host/vfs/fs.go index 8a73aad..3cfc1fc 100644 --- a/src/host/vfs/fs.go +++ b/src/host/vfs/fs.go @@ -1,7 +1,9 @@ package vfs import ( - "os" + "errors" + "io/fs" + "path" "time" "git.kmsign.ru/royalcat/tstor/src/iio" @@ -10,10 +12,13 @@ import ( type File interface { IsDir() bool Size() int64 + Stat() (fs.FileInfo, error) iio.Reader } +var ErrNotImplemented = errors.New("not implemented") + type Filesystem interface { // Open opens the named file for reading. If successful, methods on the // returned file can be used for reading; the associated file descriptor has @@ -22,23 +27,50 @@ type Filesystem interface { // ReadDir reads the directory named by dirname and returns a list of // directory entries. - ReadDir(path string) (map[string]File, error) + ReadDir(path string) ([]fs.DirEntry, error) + + Stat(filename string) (fs.FileInfo, error) } +const defaultMode = fs.FileMode(0555) + type fileInfo struct { name string size int64 isDir bool } -func NewFileInfo(name string, size int64, isDir bool) *fileInfo { +var _ fs.FileInfo = &fileInfo{} +var _ fs.DirEntry = &fileInfo{} + +func newDirInfo(name string) *fileInfo { return &fileInfo{ - name: name, - size: size, - isDir: isDir, + name: path.Base(name), + size: 0, + isDir: true, } } +func newFileInfo(name string, size int64) *fileInfo { + return &fileInfo{ + name: path.Base(name), + size: size, + isDir: false, + } +} + +func (fi *fileInfo) Info() (fs.FileInfo, error) { + return fi, nil +} + +func (fi *fileInfo) Type() fs.FileMode { + if fi.isDir { + return fs.ModeDir + } + + return 0 +} + func (fi *fileInfo) Name() string { return fi.name } @@ -47,17 +79,17 @@ func (fi *fileInfo) Size() int64 { return fi.size } -func (fi *fileInfo) Mode() os.FileMode { +func (fi *fileInfo) Mode() fs.FileMode { if fi.isDir { - return 0555 | os.ModeDir + return defaultMode | fs.ModeDir } - return 0555 + return defaultMode } func (fi *fileInfo) ModTime() time.Time { // TODO fix it - return time.Now() + return time.Time{} } func (fi *fileInfo) IsDir() bool { diff --git a/src/host/vfs/fs_test.go b/src/host/vfs/fs_test.go index 8a79fdd..414f556 100644 --- a/src/host/vfs/fs_test.go +++ b/src/host/vfs/fs_test.go @@ -12,13 +12,32 @@ func TestFileinfo(t *testing.T) { require := require.New(t) - fi := NewFileInfo("name", 42, false) + fi := newFileInfo("abc/name", 42) - require.Equal(fi.IsDir(), false) - require.Equal(fi.Name(), "name") - require.Equal(fi.Size(), int64(42)) + require.Equal("name", fi.Name()) + require.False(fi.IsDir()) + require.Equal(int64(42), fi.Size()) require.NotNil(fi.ModTime()) - require.Equal(fi.Mode(), fs.FileMode(0555)) - require.Equal(fi.Sys(), nil) + require.Zero(fi.Type() & fs.ModeDir) + require.Zero(fi.Mode() & fs.ModeDir) + require.Equal(fs.FileMode(0555), fi.Mode()) + require.Equal(nil, fi.Sys()) +} + +func TestDirInfo(t *testing.T) { + t.Parallel() + + require := require.New(t) + + fi := newDirInfo("abc/name") + + require.True(fi.IsDir()) + require.Equal("name", fi.Name()) + require.Equal(int64(0), fi.Size()) + require.NotNil(fi.ModTime()) + require.NotZero(fi.Type() & fs.ModeDir) + require.NotZero(fi.Mode() & fs.ModeDir) + require.Equal(defaultMode|fs.ModeDir, fi.Mode()) + require.Equal(nil, fi.Sys()) } diff --git a/src/host/vfs/memory.go b/src/host/vfs/memory.go index 1031a7d..eada6e0 100644 --- a/src/host/vfs/memory.go +++ b/src/host/vfs/memory.go @@ -2,6 +2,8 @@ package vfs import ( "bytes" + "io/fs" + "path" ) var _ Filesystem = &MemoryFs{} @@ -20,22 +22,37 @@ func (m *MemoryFs) Open(filename string) (File, error) { return getFile(m.files, filename) } -func (fs *MemoryFs) ReadDir(path string) (map[string]File, error) { - return listFilesInDir(fs.files, path) +func (fs *MemoryFs) ReadDir(path string) ([]fs.DirEntry, error) { + return listDirFromFiles(fs.files, path) +} + +// Stat implements Filesystem. +func (mfs *MemoryFs) Stat(filename string) (fs.FileInfo, error) { + file, ok := mfs.files[filename] + if !ok { + return nil, ErrNotExist + } + return newFileInfo(path.Base(filename), file.Size()), nil } var _ File = &MemoryFile{} type MemoryFile struct { + name string *bytes.Reader } -func NewMemoryFile(data []byte) *MemoryFile { +func NewMemoryFile(name string, data []byte) *MemoryFile { return &MemoryFile{ + name: name, Reader: bytes.NewReader(data), } } +func (d *MemoryFile) Stat() (fs.FileInfo, error) { + return newFileInfo(d.name, int64(d.Reader.Len())), nil +} + func (d *MemoryFile) Size() int64 { return int64(d.Reader.Len()) } diff --git a/src/host/vfs/memory_test.go b/src/host/vfs/memory_test.go index 9d090d8..224c8ef 100644 --- a/src/host/vfs/memory_test.go +++ b/src/host/vfs/memory_test.go @@ -13,7 +13,7 @@ func TestMemory(t *testing.T) { testData := "Hello" c := NewMemoryFS(map[string]*MemoryFile{ - "/dir/here": NewMemoryFile([]byte(testData)), + "/dir/here": NewMemoryFile("here", []byte(testData)), }) // fss := map[string]Filesystem{ @@ -32,7 +32,7 @@ func TestMemory(t *testing.T) { data := make([]byte, 5) n, err := f.Read(data) require.NoError(err) - require.Equal(n, 5) + require.Equal(5, n) require.Equal(string(data), testData) files, err := c.ReadDir("/") diff --git a/src/host/vfs/os.go b/src/host/vfs/os.go index 035b66d..4d09b05 100644 --- a/src/host/vfs/os.go +++ b/src/host/vfs/os.go @@ -11,10 +11,19 @@ type OsFS struct { hostDir string } +// Stat implements Filesystem. +func (fs *OsFS) Stat(filename string) (fs.FileInfo, error) { + if path.Clean(filename) == Separator { + return newDirInfo(Separator), nil + } + + return os.Stat(path.Join(fs.hostDir, filename)) +} + // Open implements Filesystem. func (fs *OsFS) Open(filename string) (File, error) { if path.Clean(filename) == Separator { - return &Dir{}, nil + return NewDir(filename), nil } osfile, err := os.Open(path.Join(fs.hostDir, filename)) @@ -25,21 +34,9 @@ func (fs *OsFS) Open(filename string) (File, error) { } // ReadDir implements Filesystem. -func (o *OsFS) ReadDir(dir string) (map[string]File, error) { +func (o *OsFS) ReadDir(dir string) ([]fs.DirEntry, error) { dir = path.Join(o.hostDir, dir) - entries, err := os.ReadDir(dir) - if err != nil { - return nil, err - } - out := map[string]File{} - for _, e := range entries { - if e.IsDir() { - out[e.Name()] = &Dir{} - } else { - out[e.Name()] = NewLazyOsFile(path.Join(dir, e.Name())) - } - } - return out, nil + return os.ReadDir(dir) } func NewOsFs(osDir string) *OsFS { @@ -60,6 +57,11 @@ func NewOsFile(f *os.File) *OsFile { var _ File = &OsFile{} +// Info implements File. +func (f *OsFile) Info() (fs.FileInfo, error) { + return f.f.Stat() +} + // Close implements File. func (f *OsFile) Close() error { return f.f.Close() @@ -101,6 +103,9 @@ type LazyOsFile struct { m sync.Mutex path string file *os.File + + // cached field + info fs.FileInfo } func NewLazyOsFile(path string) *LazyOsFile { @@ -127,25 +132,49 @@ func (f *LazyOsFile) open() error { // Close implements File. func (f *LazyOsFile) Close() error { + if f.file == nil { + return nil + } return f.file.Close() } // Read implements File. func (f *LazyOsFile) Read(p []byte) (n int, err error) { + err = f.open() + if err != nil { + return 0, err + } return f.file.Read(p) } // ReadAt implements File. func (f *LazyOsFile) ReadAt(p []byte, off int64) (n int, err error) { + err = f.open() + if err != nil { + return 0, err + } return f.file.ReadAt(p, off) } func (f *LazyOsFile) Stat() (fs.FileInfo, error) { - if f.file == nil { - return os.Stat(f.path) - } else { - return f.file.Stat() + f.m.Lock() + if f.info == nil { + if f.file == nil { + info, err := os.Stat(f.path) + if err != nil { + return nil, err + } + f.info = info + } else { + info, err := f.file.Stat() + if err != nil { + return nil, err + } + f.info = info + } } + f.m.Unlock() + return f.info, nil } // Size implements File. diff --git a/src/host/vfs/resolver.go b/src/host/vfs/resolver.go index df1ffd8..9bab3b8 100644 --- a/src/host/vfs/resolver.go +++ b/src/host/vfs/resolver.go @@ -3,27 +3,27 @@ package vfs import ( "fmt" "io/fs" + "path" + "slices" "strings" "sync" ) type ResolveFS struct { - osDir string - osFS *OsFS + rootFS Filesystem resolver *resolver } -func NewResolveFS(osDir string, factories map[string]FsFactory) *ResolveFS { +func NewResolveFS(rootFs Filesystem, factories map[string]FsFactory) *ResolveFS { return &ResolveFS{ - osDir: osDir, - osFS: NewOsFs(osDir), + rootFS: rootFs, resolver: newResolver(factories), } } // Open implements Filesystem. func (r *ResolveFS) Open(filename string) (File, error) { - fsPath, nestedFs, nestedFsPath, err := r.resolver.resolvePath(filename, r.osFS.Open) + fsPath, nestedFs, nestedFsPath, err := r.resolver.resolvePath(filename, r.rootFS.Open) if err != nil { return nil, err } @@ -31,12 +31,12 @@ func (r *ResolveFS) Open(filename string) (File, error) { return nestedFs.Open(nestedFsPath) } - return r.osFS.Open(fsPath) + return r.rootFS.Open(fsPath) } // ReadDir implements Filesystem. -func (r *ResolveFS) ReadDir(dir string) (map[string]File, error) { - fsPath, nestedFs, nestedFsPath, err := r.resolver.resolvePath(dir, r.osFS.Open) +func (r *ResolveFS) ReadDir(dir string) ([]fs.DirEntry, error) { + fsPath, nestedFs, nestedFsPath, err := r.resolver.resolvePath(dir, r.rootFS.Open) if err != nil { return nil, err } @@ -44,7 +44,32 @@ func (r *ResolveFS) ReadDir(dir string) (map[string]File, error) { return nestedFs.ReadDir(nestedFsPath) } - return r.osFS.ReadDir(fsPath) + entries, err := r.rootFS.ReadDir(fsPath) + if err != nil { + return nil, err + } + out := make([]fs.DirEntry, 0, len(entries)) + for _, e := range entries { + if r.resolver.isNestedFs(e.Name()) { + out = append(out, newDirInfo(e.Name())) + } else { + out = append(out, e) + } + } + return out, nil +} + +// Stat implements Filesystem. +func (r *ResolveFS) Stat(filename string) (fs.FileInfo, error) { + fsPath, nestedFs, nestedFsPath, err := r.resolver.resolvePath(filename, r.rootFS.Open) + if err != nil { + return nil, err + } + if nestedFs != nil { + return nestedFs.Stat(nestedFsPath) + } + + return r.rootFS.Stat(fsPath) } var _ Filesystem = &ResolveFS{} @@ -69,8 +94,18 @@ type resolver struct { type openFile func(path string) (File, error) +func (r *resolver) isNestedFs(f string) bool { + for ext := range r.factories { + if strings.HasSuffix(f, ext) { + return true + } + } + return true +} + // open requeue raw open, without resolver call func (r *resolver) resolvePath(name string, rawOpen openFile) (fsPath string, nestedFs Filesystem, nestedFsPath string, err error) { + name = path.Clean(name) name = strings.TrimPrefix(name, Separator) parts := strings.Split(name, Separator) @@ -89,11 +124,12 @@ PARTS_LOOP: } if nestOn == -1 { - return clean(name), nil, "", nil + return AbsPath(name), nil, "", nil } - fsPath = clean(strings.Join(parts[:nestOn], Separator)) - nestedFsPath = clean(strings.Join(parts[nestOn:], Separator)) + fsPath = AbsPath(path.Join(parts[:nestOn]...)) + + nestedFsPath = AbsPath(path.Join(parts[nestOn:]...)) // we dont need lock until now // it must be before fsmap read to exclude race condition: @@ -123,9 +159,8 @@ PARTS_LOOP: var ErrNotExist = fs.ErrNotExist func getFile[F File](m map[string]F, name string) (File, error) { - name = clean(name) if name == Separator { - return &Dir{}, nil + return &dir{}, nil } f, ok := m[name] @@ -135,27 +170,30 @@ func getFile[F File](m map[string]F, name string) (File, error) { for p := range m { if strings.HasPrefix(p, name) { - return &Dir{}, nil + return &dir{}, nil } } return nil, ErrNotExist } -func listFilesInDir[F File](m map[string]F, name string) (map[string]File, error) { - name = clean(name) - - out := map[string]File{} +func listDirFromFiles[F File](m map[string]F, name string) ([]fs.DirEntry, error) { + out := make([]fs.DirEntry, 0, len(m)) + name = AddTrailSlash(name) for p, f := range m { if strings.HasPrefix(p, name) { parts := strings.Split(trimRelPath(p, name), Separator) if len(parts) == 1 { - out[parts[0]] = f + out = append(out, newFileInfo(parts[0], f.Size())) } else { - out[parts[0]] = &Dir{} + out = append(out, newDirInfo(parts[0])) } + } } + out = slices.CompactFunc(out, func(de1, de2 fs.DirEntry) bool { + return de1.Name() == de2.Name() + }) return out, nil } diff --git a/src/host/vfs/resolver_test.go b/src/host/vfs/resolver_test.go index 401459f..ce2af5b 100644 --- a/src/host/vfs/resolver_test.go +++ b/src/host/vfs/resolver_test.go @@ -1,13 +1,21 @@ package vfs import ( + "io/fs" "os" + "path" "testing" "github.com/stretchr/testify/require" ) type Dummy struct { + name string +} + +// Stat implements File. +func (d *Dummy) Stat() (fs.FileInfo, error) { + return newFileInfo(d.name, 0), nil } func (d *Dummy) Size() int64 { @@ -35,15 +43,20 @@ var _ File = &Dummy{} type DummyFs struct { } +// Stat implements Filesystem. +func (*DummyFs) Stat(filename string) (fs.FileInfo, error) { + return newFileInfo(path.Base(filename), 0), nil // TODO +} + func (d *DummyFs) Open(filename string) (File, error) { return &Dummy{}, nil } -func (d *DummyFs) ReadDir(path string) (map[string]File, error) { +func (d *DummyFs) ReadDir(path string) ([]fs.DirEntry, error) { if path == "/dir/here" { - return map[string]File{ - "file1.txt": &Dummy{}, - "file2.txt": &Dummy{}, + return []fs.DirEntry{ + newFileInfo("file1.txt", 0), + newFileInfo("file2.txt", 0), }, nil } @@ -63,7 +76,7 @@ func TestResolver(t *testing.T) { require.Equal("/f1.rar", path) return &Dummy{}, nil }) - require.Nil(err) + require.NoError(err) require.Equal("/f1.rar", fsPath) require.Equal("/f2.rar", nestedFsPath) require.IsType(&archive{}, nestedFs) @@ -76,7 +89,7 @@ func TestResolver(t *testing.T) { require.Equal("/", path) return &Dummy{}, nil }) - require.Nil(err) + require.NoError(err) require.Nil(nestedFs) require.Equal("/", fsPath) require.Equal("", nestedFsPath) @@ -90,7 +103,7 @@ func TestResolver(t *testing.T) { require.Equal("/", path) return &Dummy{}, nil }) - require.Nil(err) + require.NoError(err) require.Nil(nestedFs) require.Equal("/", fsPath) require.Equal("", nestedFsPath) @@ -103,7 +116,7 @@ func TestResolver(t *testing.T) { require.Equal("/f1.rar", path) return &Dummy{}, nil }) - require.Nil(err) + require.NoError(err) require.Equal("/f1.rar", fsPath) require.Equal("/", nestedFsPath) require.IsType(&archive{}, nestedFs) @@ -116,7 +129,7 @@ func TestResolver(t *testing.T) { require.Equal("/test1/f1.rar", path) return &Dummy{}, nil }) - require.Nil(err) + require.NoError(err) require.IsType(&archive{}, nestedFs) require.Equal("/test1/f1.rar", fsPath) require.Equal("/", nestedFsPath) @@ -150,23 +163,43 @@ func TestFiles(t *testing.T) { require := require.New(t) files := map[string]*Dummy{ - "/test/file.txt": &Dummy{}, + "/test/file.txt": &Dummy{}, + "/test/file2.txt": &Dummy{}, + "/test1/file.txt": &Dummy{}, } { file, err := getFile(files, "/test") - require.Nil(err) - require.Equal(&Dir{}, file) + require.NoError(err) + require.Equal(&dir{}, file) } { file, err := getFile(files, "/test/file.txt") - require.Nil(err) + require.NoError(err) require.Equal(&Dummy{}, file) } - { - out, err := listFilesInDir(files, "/test") - require.Nil(err) - require.Contains(out, "file.txt") - require.Equal(&Dummy{}, out["file.txt"]) + out, err := listDirFromFiles(files, "/test") + require.NoError(err) + require.Len(out, 2) + require.Equal("file.txt", out[0].Name()) + require.Equal("file2.txt", out[1].Name()) + require.False(out[0].IsDir()) + require.False(out[1].IsDir()) + } + { + out, err := listDirFromFiles(files, "/test1") + require.NoError(err) + require.Len(out, 1) + require.Equal("file.txt", out[0].Name()) + require.False(out[0].IsDir()) + } + { + out, err := listDirFromFiles(files, "/") + require.NoError(err) + require.Len(out, 2) + require.Equal("test", out[0].Name()) + require.Equal("test1", out[1].Name()) + require.True(out[0].IsDir()) + require.True(out[1].IsDir()) } } diff --git a/src/host/vfs/torrent.go b/src/host/vfs/torrent.go index 2089f03..e4d9247 100644 --- a/src/host/vfs/torrent.go +++ b/src/host/vfs/torrent.go @@ -3,6 +3,8 @@ package vfs import ( "context" "io" + "io/fs" + "path" "sync" "time" @@ -14,10 +16,14 @@ import ( var _ Filesystem = &TorrentFs{} type TorrentFs struct { - mu sync.RWMutex - t *torrent.Torrent + mu sync.Mutex + t *torrent.Torrent + readTimeout int + //cache + filesCache map[string]*torrentFile + resolver *resolver } @@ -30,22 +36,24 @@ func NewTorrentFs(t *torrent.Torrent, readTimeout int) *TorrentFs { } func (fs *TorrentFs) files() map[string]*torrentFile { - files := make(map[string]*torrentFile) - <-fs.t.GotInfo() - for _, file := range fs.t.Files() { - if file.Priority() == torrent.PiecePriorityNone { - continue - } - - p := clean(file.Path()) - files[p] = &torrentFile{ - readerFunc: file.NewReader, - len: file.Length(), - timeout: fs.readTimeout, + if fs.filesCache == nil { + fs.mu.Lock() + <-fs.t.GotInfo() + files := fs.t.Files() + fs.filesCache = make(map[string]*torrentFile) + for _, file := range files { + p := AbsPath(file.Path()) + fs.filesCache[p] = &torrentFile{ + name: path.Base(p), + readerFunc: file.NewReader, + len: file.Length(), + timeout: fs.readTimeout, + } } + fs.mu.Unlock() } - return files + return fs.filesCache } func (fs *TorrentFs) rawOpen(path string) (File, error) { @@ -53,6 +61,36 @@ func (fs *TorrentFs) rawOpen(path string) (File, error) { return file, err } +func (fs *TorrentFs) rawStat(filename string) (fs.FileInfo, error) { + file, err := getFile(fs.files(), filename) + if err != nil { + return nil, err + } + if file.IsDir() { + return newDirInfo(path.Base(filename)), nil + } else { + return newFileInfo(path.Base(filename), file.Size()), nil + } + +} + +// Stat implements Filesystem. +func (fs *TorrentFs) Stat(filename string) (fs.FileInfo, error) { + if filename == Separator { + return newDirInfo(filename), nil + } + + fsPath, nestedFs, nestedFsPath, err := fs.resolver.resolvePath(filename, fs.rawOpen) + if err != nil { + return nil, err + } + if nestedFs != nil { + return nestedFs.Stat(nestedFsPath) + } + + return fs.rawStat(fsPath) +} + func (fs *TorrentFs) Open(filename string) (File, error) { fsPath, nestedFs, nestedFsPath, err := fs.resolver.resolvePath(filename, fs.rawOpen) if err != nil { @@ -65,7 +103,7 @@ func (fs *TorrentFs) Open(filename string) (File, error) { return fs.rawOpen(fsPath) } -func (fs *TorrentFs) ReadDir(name string) (map[string]File, error) { +func (fs *TorrentFs) ReadDir(name string) ([]fs.DirEntry, error) { fsPath, nestedFs, nestedFsPath, err := fs.resolver.resolvePath(name, fs.rawOpen) if err != nil { return nil, err @@ -74,7 +112,7 @@ func (fs *TorrentFs) ReadDir(name string) (map[string]File, error) { return nestedFs.ReadDir(nestedFsPath) } - return listFilesInDir(fs.files(), fsPath) + return listDirFromFiles(fs.files(), fsPath) } func (fs *TorrentFs) Unlink(name string) error { @@ -144,12 +182,18 @@ func (rw *readAtWrapper) Close() error { var _ File = &torrentFile{} type torrentFile struct { + name string + readerFunc func() torrent.Reader reader reader len int64 timeout int } +func (d *torrentFile) Stat() (fs.FileInfo, error) { + return newFileInfo(d.name, d.len), nil +} + func (d *torrentFile) load() { if d.reader != nil { return diff --git a/src/host/vfs/utils.go b/src/host/vfs/utils.go index 7f36933..e89977c 100644 --- a/src/host/vfs/utils.go +++ b/src/host/vfs/utils.go @@ -1,14 +1,25 @@ package vfs -import ( - "path" - "strings" -) +import "strings" func trimRelPath(p, t string) string { return strings.Trim(strings.TrimPrefix(p, t), "/") } -func clean(p string) string { - return path.Clean(Separator + strings.ReplaceAll(p, "\\", "/")) +// func clean(p string) string { +// return path.Clean(Separator + strings.ReplaceAll(p, "\\", "/")) +// } + +func AbsPath(p string) string { + if p == "" || p[0] != '/' { + return Separator + p + } + return p +} + +func AddTrailSlash(p string) string { + if p == "" || p[len(p)-1] != '/' { + return p + Separator + } + return p } diff --git a/src/http/http.go b/src/http/http.go index 7f2fa27..55a6590 100644 --- a/src/http/http.go +++ b/src/http/http.go @@ -8,6 +8,7 @@ import ( "git.kmsign.ru/royalcat/tstor/src/config" "git.kmsign.ru/royalcat/tstor/src/host/torrent" "github.com/anacrolix/missinggo/v2/filecache" + "github.com/gin-contrib/pprof" "github.com/gin-gonic/gin" "github.com/rs/zerolog/log" "github.com/shurcooL/httpfs/html/vfstemplate" @@ -19,6 +20,7 @@ func New(fc *filecache.Cache, ss *torrent.Stats, s *torrent.Service, logPath str r.Use(gin.Recovery()) r.Use(gin.ErrorLogger()) r.Use(Logger()) + pprof.Register(r) r.GET("/assets/*filepath", func(c *gin.Context) { c.FileFromFS(c.Request.URL.Path, http.FS(tstor.Assets)) diff --git a/src/iio/wrapper_test.go b/src/iio/wrapper_test.go index 071ce92..7d8a82d 100644 --- a/src/iio/wrapper_test.go +++ b/src/iio/wrapper_test.go @@ -16,7 +16,7 @@ func TestSeekerWrapper(t *testing.T) { require := require.New(t) - mf := vfs.NewMemoryFile(testData) + mf := vfs.NewMemoryFile("text.txt", testData) r := iio.NewSeekerWrapper(mf, mf.Size()) defer r.Close() diff --git a/src/mounts/fuse/mount.go b/src/mounts/fuse/mount.go index da6a390..a598612 100644 --- a/src/mounts/fuse/mount.go +++ b/src/mounts/fuse/mount.go @@ -174,13 +174,13 @@ func (fh *fileHandler) ListDir(path string) ([]string, error) { fh.mu.RLock() defer fh.mu.RUnlock() - var out []string files, err := fh.fs.ReadDir(path) if err != nil { return nil, err } - for p := range files { - out = append(out, p) + out := make([]string, 0, len(files)) + for _, p := range files { + out = append(out, p.Name()) } return out, nil diff --git a/src/mounts/fuse/mount_test.go b/src/mounts/fuse/mount_test.go index 3d16ca4..5a973af 100644 --- a/src/mounts/fuse/mount_test.go +++ b/src/mounts/fuse/mount_test.go @@ -25,7 +25,7 @@ func TestHandler(t *testing.T) { h := NewHandler(false, p) mem := vfs.NewMemoryFS(map[string]*vfs.MemoryFile{ - "/test.txt": vfs.NewMemoryFile([]byte("test")), + "/test.txt": vfs.NewMemoryFile("test.txt", []byte("test")), }) err := h.Mount(mem) @@ -52,7 +52,7 @@ func TestHandlerDriveLetter(t *testing.T) { h := NewHandler(false, p) mem := vfs.NewMemoryFS(map[string]*vfs.MemoryFile{ - "/test.txt": vfs.NewMemoryFile([]byte("test")), + "/test.txt": vfs.NewMemoryFile("test.txt", []byte("test")), }) err := h.Mount(mem) diff --git a/src/mounts/httpfs/httpfs.go b/src/mounts/httpfs/httpfs.go index f593903..303cf2d 100644 --- a/src/mounts/httpfs/httpfs.go +++ b/src/mounts/httpfs/httpfs.go @@ -21,32 +21,37 @@ func NewHTTPFS(fs vfs.Filesystem) *HTTPFS { return &HTTPFS{fs: fs} } -func (fs *HTTPFS) Open(name string) (http.File, error) { - f, err := fs.fs.Open(name) +func (hfs *HTTPFS) Open(name string) (http.File, error) { + f, err := hfs.fs.Open(name) if err != nil { return nil, err } - fi := vfs.NewFileInfo(name, f.Size(), f.IsDir()) - - // TODO make this lazy - fis, err := fs.filesToFileInfo(name) - if err != nil { - return nil, err + var fis []fs.FileInfo + if f.IsDir() { + // TODO make this lazy + fis, err = hfs.filesToFileInfo(name) + if err != nil { + return nil, err + } } - return newHTTPFile(f, fis, fi), nil + return newHTTPFile(f, fis), nil } -func (fs *HTTPFS) filesToFileInfo(path string) ([]fs.FileInfo, error) { - files, err := fs.fs.ReadDir(path) +func (hfs *HTTPFS) filesToFileInfo(name string) ([]fs.FileInfo, error) { + files, err := hfs.fs.ReadDir(name) if err != nil { return nil, err } - var out []os.FileInfo - for n, f := range files { - out = append(out, vfs.NewFileInfo(n, f.Size(), f.IsDir())) + out := make([]os.FileInfo, 0, len(files)) + for _, f := range files { + info, err := f.Info() + if err != nil { + return nil, err + } + out = append(out, info) } return out, nil @@ -55,33 +60,32 @@ func (fs *HTTPFS) filesToFileInfo(path string) ([]fs.FileInfo, error) { var _ http.File = &httpFile{} type httpFile struct { + f vfs.File + iio.ReaderSeeker mu sync.Mutex // dirPos is protected by mu. dirPos int dirContent []os.FileInfo - - fi fs.FileInfo } -func newHTTPFile(f vfs.File, fis []fs.FileInfo, fi fs.FileInfo) *httpFile { +func newHTTPFile(f vfs.File, dirContent []os.FileInfo) *httpFile { return &httpFile{ - dirContent: fis, - fi: fi, - + f: f, + dirContent: dirContent, ReaderSeeker: iio.NewSeekerWrapper(f, f.Size()), } } func (f *httpFile) Readdir(count int) ([]fs.FileInfo, error) { - f.mu.Lock() - defer f.mu.Unlock() - - if !f.fi.IsDir() { + if !f.f.IsDir() { return nil, os.ErrInvalid } + f.mu.Lock() + defer f.mu.Unlock() + old := f.dirPos if old >= len(f.dirContent) { // The os.File Readdir docs say that at the end of a directory, @@ -105,5 +109,5 @@ func (f *httpFile) Readdir(count int) ([]fs.FileInfo, error) { } func (f *httpFile) Stat() (fs.FileInfo, error) { - return f.fi, nil + return f.f.Stat() } diff --git a/src/mounts/nfs/handler.go b/src/mounts/nfs/handler.go new file mode 100644 index 0000000..d340062 --- /dev/null +++ b/src/mounts/nfs/handler.go @@ -0,0 +1,16 @@ +package nfs + +import ( + "git.kmsign.ru/royalcat/tstor/src/host/vfs" + nfs "github.com/willscott/go-nfs" + nfshelper "github.com/willscott/go-nfs/helpers" +) + +func NewNFSv3Handler(fs vfs.Filesystem) (nfs.Handler, error) { + bfs := &billyFsWrapper{fs: fs} + handler := nfshelper.NewNullAuthHandler(bfs) + cacheHelper := nfshelper.NewCachingHandler(handler, 1024*16) + // cacheHelper := NewCachingHandler(handler) + + return cacheHelper, nil +} diff --git a/src/mounts/nfs/wrapper-v3.go b/src/mounts/nfs/wrapper-v3.go new file mode 100644 index 0000000..195bd41 --- /dev/null +++ b/src/mounts/nfs/wrapper-v3.go @@ -0,0 +1,190 @@ +package nfs + +import ( + "io/fs" + "path/filepath" + + "git.kmsign.ru/royalcat/tstor/src/host/vfs" + "github.com/go-git/go-billy/v5" +) + +type billyFsWrapper struct { + fs vfs.Filesystem +} + +var _ billy.Filesystem = (*billyFsWrapper)(nil) +var _ billy.Dir = (*billyFsWrapper)(nil) + +// Chroot implements billy.Filesystem. +func (*billyFsWrapper) Chroot(path string) (billy.Filesystem, error) { + return nil, billy.ErrNotSupported +} + +// Create implements billy.Filesystem. +func (*billyFsWrapper) Create(filename string) (billy.File, error) { + return nil, billy.ErrNotSupported +} + +// Join implements billy.Filesystem. +func (*billyFsWrapper) Join(elem ...string) string { + return filepath.Join(elem...) +} + +// Lstat implements billy.Filesystem. +func (fs *billyFsWrapper) Lstat(filename string) (fs.FileInfo, error) { + info, err := fs.fs.Stat(filename) + if err != nil { + return nil, billyErr(err) + } + return info, nil +} + +// MkdirAll implements billy.Filesystem. +func (*billyFsWrapper) MkdirAll(filename string, perm fs.FileMode) error { + return billy.ErrNotSupported +} + +// Open implements billy.Filesystem. +func (f *billyFsWrapper) Open(filename string) (billy.File, error) { + file, err := f.fs.Open(filename) + if err != nil { + return nil, billyErr(err) + } + return &billyFile{ + name: filename, + file: file, + }, nil +} + +// OpenFile implements billy.Filesystem. +func (f *billyFsWrapper) OpenFile(filename string, flag int, perm fs.FileMode) (billy.File, error) { + file, err := f.fs.Open(filename) + if err != nil { + return nil, billyErr(err) + } + return &billyFile{ + name: filename, + file: file, + }, nil +} + +// ReadDir implements billy.Filesystem. +func (bfs *billyFsWrapper) ReadDir(path string) ([]fs.FileInfo, error) { + ffs, err := bfs.fs.ReadDir(path) + if err != nil { + return nil, billyErr(err) + } + + out := make([]fs.FileInfo, 0, len(ffs)) + for _, v := range ffs { + if info, ok := v.(fs.FileInfo); ok { + out = append(out, info) + } else { + info, err := v.Info() + if err != nil { + return nil, err + } + out = append(out, info) + } + + } + return out, nil +} + +// Readlink implements billy.Filesystem. +func (*billyFsWrapper) Readlink(link string) (string, error) { + return "", billy.ErrNotSupported +} + +// Remove implements billy.Filesystem. +func (*billyFsWrapper) Remove(filename string) error { + return billy.ErrNotSupported +} + +// Rename implements billy.Filesystem. +func (*billyFsWrapper) Rename(oldpath string, newpath string) error { + return billy.ErrNotSupported +} + +// Root implements billy.Filesystem. +func (*billyFsWrapper) Root() string { + return "/" +} + +// Stat implements billy.Filesystem. +func (f *billyFsWrapper) Stat(filename string) (fs.FileInfo, error) { + info, err := f.fs.Stat(filename) + if err != nil { + return nil, billyErr(err) + } + return info, nil +} + +// Symlink implements billy.Filesystem. +func (*billyFsWrapper) Symlink(target string, link string) error { + return billyErr(vfs.ErrNotImplemented) +} + +// TempFile implements billy.Filesystem. +func (*billyFsWrapper) TempFile(dir string, prefix string) (billy.File, error) { + return nil, billyErr(vfs.ErrNotImplemented) +} + +type billyFile struct { + name string + file vfs.File +} + +var _ billy.File = (*billyFile)(nil) + +// Close implements billy.File. +func (f *billyFile) Close() error { + return f.Close() +} + +// Name implements billy.File. +func (f *billyFile) Name() string { + return f.name +} + +// Read implements billy.File. +func (f *billyFile) Read(p []byte) (n int, err error) { + return f.Read(p) +} + +// ReadAt implements billy.File. +func (f *billyFile) ReadAt(p []byte, off int64) (n int, err error) { + return f.ReadAt(p, off) +} + +// Seek implements billy.File. +func (*billyFile) Seek(offset int64, whence int) (int64, error) { + return 0, billyErr(vfs.ErrNotImplemented) +} + +// Truncate implements billy.File. +func (*billyFile) Truncate(size int64) error { + return billyErr(vfs.ErrNotImplemented) +} + +// Write implements billy.File. +func (*billyFile) Write(p []byte) (n int, err error) { + return 0, billyErr(vfs.ErrNotImplemented) +} + +// Lock implements billy.File. +func (*billyFile) Lock() error { + return nil // TODO +} + +// Unlock implements billy.File. +func (*billyFile) Unlock() error { + return nil // TODO +} + +func billyErr(err error) error { + if err == vfs.ErrNotImplemented { + return billy.ErrNotSupported + } + return err +} diff --git a/src/mounts/nfs/wrapper-v4.go b/src/mounts/nfs/wrapper-v4.go new file mode 100644 index 0000000..e1e7bf3 --- /dev/null +++ b/src/mounts/nfs/wrapper-v4.go @@ -0,0 +1,164 @@ +package nfs + +// import ( +// "io/fs" + +// "git.kmsign.ru/royalcat/tstor/src/host/vfs" +// nfsfs "github.com/smallfz/libnfs-go/fs" +// ) + +// type nfsFsWrapper struct { +// fs vfs.Filesystem +// } + +// var _ nfsfs.FS = (*nfsFsWrapper)(nil) + +// // Attributes implements fs.FS. +// func (*nfsFsWrapper) Attributes() *nfsfs.Attributes { +// return &nfsfs.Attributes{ +// LinkSupport: true, +// SymlinkSupport: false, // unsopported +// ChownRestricted: true, // unsopported +// MaxName: 255, // common value +// NoTrunc: false, +// } +// } + +// // Stat implements fs.FS. +// func (*nfsFsWrapper) Stat(string) (nfsfs.FileInfo, error) { +// panic("unimplemented") +// } + +// // Chmod implements fs.FS. +// func (*nfsFsWrapper) Chmod(string, fs.FileMode) error { +// panic("unimplemented") +// } + +// // Chown implements fs.FS. +// func (*nfsFsWrapper) Chown(string, int, int) error { +// panic("unimplemented") +// } + +// // GetFileId implements fs.FS. +// func (*nfsFsWrapper) GetFileId(nfsfs.FileInfo) uint64 { +// panic("unimplemented") +// } + +// // GetHandle implements fs.FS. +// func (*nfsFsWrapper) GetHandle(nfsfs.FileInfo) ([]byte, error) { +// panic("unimplemented") +// } + +// // GetRootHandle implements fs.FS. +// func (*nfsFsWrapper) GetRootHandle() []byte { +// panic("unimplemented") +// } + +// // Link implements fs.FS. +// func (*nfsFsWrapper) Link(string, string) error { +// panic("unimplemented") +// } + +// // MkdirAll implements fs.FS. +// func (*nfsFsWrapper) MkdirAll(string, fs.FileMode) error { +// panic("unimplemented") +// } + +// // Open implements fs.FS. +// func (w *nfsFsWrapper) Open(name string) (nfsfs.File, error) { +// f, err := w.fs.Open(name) +// if err != nil { +// return nil, nfsErr(err) +// } +// } + +// // OpenFile implements fs.FS. +// func (w *nfsFsWrapper) OpenFile(string, int, fs.FileMode) (nfsfs.File, error) { +// panic("unimplemented") +// } + +// // Readlink implements fs.FS. +// func (*nfsFsWrapper) Readlink(string) (string, error) { +// panic("unimplemented") +// } + +// // Remove implements fs.FS. +// func (*nfsFsWrapper) Remove(string) error { +// panic("unimplemented") +// } + +// // Rename implements fs.FS. +// func (*nfsFsWrapper) Rename(string, string) error { +// panic("unimplemented") +// } + +// // ResolveHandle implements fs.FS. +// func (*nfsFsWrapper) ResolveHandle([]byte) (string, error) { +// panic("unimplemented") +// } + +// // Symlink implements fs.FS. +// func (*nfsFsWrapper) Symlink(string, string) error { +// return NotImplementedError +// } + +// var NotImplementedError = vfs.NotImplemented + +// func nfsErr(err error) error { +// if err == vfs.NotImplemented { +// return NotImplementedError +// } +// return err +// } + +// type nfsFile struct { +// name string +// f vfs.File +// } + +// // Close implements fs.File. +// func (f *nfsFile) Close() error { +// return f.f.Close() +// } + +// // Name implements fs.File. +// func (f *nfsFile) Name() string { +// return f.name +// } + +// // Read implements fs.File. +// func (f *nfsFile) Read(p []byte) (n int, err error) { +// return f.f.Read(p) +// } + +// // Readdir implements fs.File. +// func (f *nfsFile) Readdir(int) ([]nfsfs.FileInfo, error) { +// f.f.IsDir() +// } + +// // Seek implements fs.File. +// func (*nfsFile) Seek(offset int64, whence int) (int64, error) { +// panic("unimplemented") +// } + +// // Stat implements fs.File. +// func (*nfsFile) Stat() (nfsfs.FileInfo, error) { +// panic("unimplemented") +// } + +// // Sync implements fs.File. +// func (*nfsFile) Sync() error { +// panic("unimplemented") +// } + +// // Truncate implements fs.File. +// func (*nfsFile) Truncate() error { +// panic("unimplemented") +// } + +// // Write implements fs.File. +// func (*nfsFile) Write(p []byte) (n int, err error) { +// panic("unimplemented") +// } + +// var _ nfsfs.File = (*nfsFile)(nil) diff --git a/src/mounts/webdav/fs.go b/src/mounts/webdav/fs.go index 29f2727..9ff2561 100644 --- a/src/mounts/webdav/fs.go +++ b/src/mounts/webdav/fs.go @@ -3,8 +3,9 @@ package webdav import ( "context" "io" + "io/fs" "os" - "path/filepath" + "path" "sync" "time" @@ -24,30 +25,25 @@ func newFS(fs vfs.Filesystem) *WebDAV { } func (wd *WebDAV) OpenFile(ctx context.Context, name string, flag int, perm os.FileMode) (webdav.File, error) { - p := "/" + name + name = vfs.AbsPath(name) + // TODO handle flag and permissions - f, err := wd.lookupFile(p) + f, err := wd.lookupFile(name) if err != nil { return nil, err } - wdf := newFile(filepath.Base(p), f, func() ([]os.FileInfo, error) { - return wd.listDir(p) + wdf := newFile(path.Base(name), f, func() ([]fs.FileInfo, error) { + return wd.listDir(name) }) return wdf, nil } -func (wd *WebDAV) Stat(ctx context.Context, name string) (os.FileInfo, error) { - p := "/" + name - f, err := wd.lookupFile(p) - if err != nil { - return nil, err - } - fi := newFileInfo(name, f.Size(), f.IsDir()) - return fi, nil +func (wd *WebDAV) Stat(ctx context.Context, name string) (fs.FileInfo, error) { + return wd.fs.Stat(vfs.AbsPath(name)) } -func (wd *WebDAV) Mkdir(ctx context.Context, name string, perm os.FileMode) error { +func (wd *WebDAV) Mkdir(ctx context.Context, name string, perm fs.FileMode) error { return webdav.ErrNotImplemented } @@ -59,8 +55,8 @@ func (wd *WebDAV) Rename(ctx context.Context, oldName, newName string) error { return webdav.ErrNotImplemented } -func (wd *WebDAV) lookupFile(path string) (vfs.File, error) { - return wd.fs.Open(path) +func (wd *WebDAV) lookupFile(name string) (vfs.File, error) { + return wd.fs.Open(path.Clean(name)) } func (wd *WebDAV) listDir(path string) ([]os.FileInfo, error) { @@ -69,9 +65,13 @@ func (wd *WebDAV) listDir(path string) ([]os.FileInfo, error) { return nil, err } - var out []os.FileInfo - for n, f := range files { - out = append(out, newFileInfo(n, f.Size(), f.IsDir())) + out := make([]os.FileInfo, 0, len(files)) + for _, f := range files { + info, err := f.Info() + if err != nil { + return nil, err + } + out = append(out, info) } return out, nil diff --git a/src/mounts/webdav/fs_test.go b/src/mounts/webdav/fs_test.go index 5d703e8..606696f 100644 --- a/src/mounts/webdav/fs_test.go +++ b/src/mounts/webdav/fs_test.go @@ -13,16 +13,17 @@ import ( func TestWebDAVFilesystem(t *testing.T) { t.Parallel() + ctx := context.Background() require := require.New(t) mfs := vfs.NewMemoryFS(map[string]*vfs.MemoryFile{ - "/folder/file.txt": vfs.NewMemoryFile([]byte("test file content.")), + "/folder/file.txt": vfs.NewMemoryFile("file.txt", []byte("test file content.")), }) wfs := newFS(mfs) - dir, err := wfs.OpenFile(context.Background(), "/", 0, 0) + dir, err := wfs.OpenFile(ctx, "/", 0, 0) require.NoError(err) fi, err := dir.Readdir(0) @@ -30,7 +31,7 @@ func TestWebDAVFilesystem(t *testing.T) { require.Len(fi, 1) require.Equal("folder", fi[0].Name()) - file, err := wfs.OpenFile(context.Background(), "/folder/file.txt", 0, 0) + file, err := wfs.OpenFile(ctx, "/folder/file.txt", 0, 0) require.NoError(err) _, err = file.Readdir(0) require.ErrorIs(err, os.ErrInvalid) @@ -57,7 +58,7 @@ func TestWebDAVFilesystem(t *testing.T) { fInfo, err := wfs.Stat(context.Background(), "/folder/file.txt") require.NoError(err) require.Equal("/folder/file.txt", fInfo.Name()) - require.Equal(false, fInfo.IsDir()) + require.False(fInfo.IsDir()) require.Equal(int64(18), fInfo.Size()) } @@ -67,7 +68,7 @@ func TestErrNotImplemented(t *testing.T) { require := require.New(t) mfs := vfs.NewMemoryFS(map[string]*vfs.MemoryFile{ - "/folder/file.txt": vfs.NewMemoryFile([]byte("test file content.")), + "/folder/file.txt": vfs.NewMemoryFile("file.txt", []byte("test file content.")), }) wfs := newFS(mfs) diff --git a/src/mounts/webdav/http.go b/src/mounts/webdav/http.go index 3b95a83..80e4fdd 100644 --- a/src/mounts/webdav/http.go +++ b/src/mounts/webdav/http.go @@ -9,11 +9,12 @@ import ( ) func NewWebDAVServer(fs vfs.Filesystem, port int, user, pass string) error { - log.Info().Str("host", fmt.Sprintf("0.0.0.0:%d", port)).Msg("starting webDAV server") srv := newHandler(fs) - http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + serveMux := http.NewServeMux() + + serveMux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { username, password, _ := r.BasicAuth() if username == user && password == pass { srv.ServeHTTP(w, r) @@ -22,8 +23,16 @@ func NewWebDAVServer(fs vfs.Filesystem, port int, user, pass string) error { w.Header().Set("WWW-Authenticate", `Basic realm="BASIC WebDAV REALM"`) w.WriteHeader(401) - w.Write([]byte("401 Unauthorized\n")) + _, _ = w.Write([]byte("401 Unauthorized\n")) }) - return http.ListenAndServe(fmt.Sprintf("0.0.0.0:%d", port), nil) + //nolint:exhaustruct + httpServer := &http.Server{ + Addr: fmt.Sprintf("0.0.0.0:%d", port), + Handler: serveMux, + } + + log.Info().Str("host", httpServer.Addr).Msg("starting webDAV server") + + return httpServer.ListenAndServe() }