update
This commit is contained in:
parent
35913e0190
commit
6a1e338af4
34 changed files with 1900 additions and 355 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -4,3 +4,4 @@ bin/
|
|||
coverage.out
|
||||
bin
|
||||
build
|
||||
deploy-debug.sh
|
|
@ -42,3 +42,7 @@ models:
|
|||
extraFields:
|
||||
F:
|
||||
type: "*github.com/anacrolix/torrent.PeerConn"
|
||||
# TorrentProgress:
|
||||
# fields:
|
||||
# torrent:
|
||||
# resolver: true
|
||||
|
|
7
.vscode/launch.json
vendored
7
.vscode/launch.json
vendored
|
@ -4,6 +4,13 @@
|
|||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Launch file",
|
||||
"type": "go",
|
||||
"request": "launch",
|
||||
"mode": "debug",
|
||||
"program": "${file}"
|
||||
},
|
||||
{
|
||||
"name": "Launch Package",
|
||||
"type": "go",
|
||||
|
|
12
Makefile
12
Makefile
|
@ -34,11 +34,7 @@ go-generate:
|
|||
@echo " > Generating code files..."
|
||||
go generate ./...
|
||||
|
||||
.PHONY: help
|
||||
all: help
|
||||
help: Makefile
|
||||
@echo
|
||||
@echo " Choose a command run in "$(PROJECTNAME)":"
|
||||
@echo
|
||||
@sed -n 's/^##//p' $< | column -t -s ':' | sed -e 's/^/ /'
|
||||
@echo
|
||||
generate-graphql: src/delivery/graph/generated.go
|
||||
|
||||
src/delivery/graph/generated.go: .gqlgen.yml graphql/* graphql/types/* cmd/generate-graphql/*
|
||||
go run cmd/generate-graphql/main.go
|
||||
|
|
|
@ -10,14 +10,14 @@ import (
|
|||
"github.com/99designs/gqlgen/codegen/config"
|
||||
)
|
||||
|
||||
type plugin_ struct {
|
||||
type fieldDirectiveFix struct {
|
||||
}
|
||||
|
||||
func (plugin_) Name() string {
|
||||
func (fieldDirectiveFix) Name() string {
|
||||
return "Fix Directive hook called with wrong object"
|
||||
}
|
||||
|
||||
func (plugin_) GenerateCode(cfg *codegen.Data) error {
|
||||
func (fieldDirectiveFix) GenerateCode(cfg *codegen.Data) error {
|
||||
for _, input := range cfg.Inputs {
|
||||
for _, field := range input.Fields {
|
||||
if field.GoFieldType == codegen.GoFieldVariable {
|
||||
|
@ -56,7 +56,7 @@ func main() {
|
|||
}
|
||||
|
||||
err = api.Generate(cfg,
|
||||
api.AddPlugin(&plugin_{}),
|
||||
api.AddPlugin(&fieldDirectiveFix{}),
|
||||
)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err.Error())
|
|
@ -15,7 +15,7 @@ import (
|
|||
|
||||
"git.kmsign.ru/royalcat/tstor/src/config"
|
||||
"git.kmsign.ru/royalcat/tstor/src/host"
|
||||
"git.kmsign.ru/royalcat/tstor/src/host/filestorage"
|
||||
"git.kmsign.ru/royalcat/tstor/src/host/datastorage"
|
||||
"git.kmsign.ru/royalcat/tstor/src/host/service"
|
||||
"git.kmsign.ru/royalcat/tstor/src/host/store"
|
||||
"git.kmsign.ru/royalcat/tstor/src/host/vfs"
|
||||
|
@ -90,13 +90,13 @@ func run(configPath string) error {
|
|||
return fmt.Errorf("error creating node ID: %w", err)
|
||||
}
|
||||
|
||||
st, _, err := filestorage.Setup(conf.TorrentClient)
|
||||
st, _, err := datastorage.Setup(conf.TorrentClient)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer st.Close()
|
||||
|
||||
excludedFilesStore, err := store.NewExcludedFiles(conf.TorrentClient.MetadataFolder, st)
|
||||
excludedFilesStore, err := store.NewFileMappings(conf.TorrentClient.MetadataFolder, st)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -238,5 +238,5 @@ func run(configPath string) error {
|
|||
signal.Notify(sigChan, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
|
||||
<-sigChan
|
||||
|
||||
return nil
|
||||
return ts.Close()
|
||||
}
|
||||
|
|
39
go.mod
39
go.mod
|
@ -1,13 +1,14 @@
|
|||
module git.kmsign.ru/royalcat/tstor
|
||||
|
||||
go 1.21
|
||||
go 1.22.1
|
||||
|
||||
require (
|
||||
github.com/99designs/gqlgen v0.17.43
|
||||
github.com/anacrolix/dht/v2 v2.21.0
|
||||
github.com/RoaringBitmap/roaring v1.2.3
|
||||
github.com/anacrolix/dht/v2 v2.19.2-0.20221121215055-066ad8494444
|
||||
github.com/anacrolix/log v0.14.6-0.20231202035202-ed7a02cad0b4
|
||||
github.com/anacrolix/missinggo/v2 v2.7.3
|
||||
github.com/anacrolix/torrent v1.54.0
|
||||
github.com/anacrolix/torrent v1.55.0
|
||||
github.com/billziss-gh/cgofuse v1.5.0
|
||||
github.com/bodgit/sevenzip v1.4.5
|
||||
github.com/dgraph-io/badger/v4 v4.2.0
|
||||
|
@ -15,6 +16,10 @@ require (
|
|||
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/gofrs/uuid/v5 v5.0.0
|
||||
github.com/google/uuid v1.5.0
|
||||
github.com/hashicorp/go-multierror v1.1.1
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7
|
||||
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
|
||||
|
@ -22,27 +27,24 @@ require (
|
|||
github.com/knadh/koanf/v2 v2.0.1
|
||||
github.com/lmittmann/tint v1.0.4
|
||||
github.com/nwaples/rardecode/v2 v2.0.0-beta.2
|
||||
github.com/philippgille/gokv v0.6.0
|
||||
github.com/philippgille/gokv/badgerdb v0.6.0
|
||||
github.com/philippgille/gokv/encoding v0.6.0
|
||||
github.com/royalcat/kv v0.0.0-20240316134516-1bb692abce73
|
||||
github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c
|
||||
github.com/stretchr/testify v1.8.4
|
||||
github.com/urfave/cli/v2 v2.27.0
|
||||
github.com/vektah/gqlparser/v2 v2.5.11
|
||||
github.com/willscott/go-nfs v0.0.2
|
||||
go.uber.org/multierr v1.11.0
|
||||
golang.org/x/exp v0.0.0-20231226003508-02704c960a9b
|
||||
golang.org/x/net v0.19.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 // indirect
|
||||
github.com/RoaringBitmap/roaring v1.2.3 // indirect
|
||||
github.com/agnivade/levenshtein v1.1.1 // 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
|
||||
|
@ -60,12 +62,11 @@ require (
|
|||
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/cespare/xxhash v1.1.0 // 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/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dgraph-io/badger v1.6.0 // indirect
|
||||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 // indirect
|
||||
github.com/dustin/go-humanize v1.0.0 // indirect
|
||||
github.com/edsrzf/mmap-go v1.1.0 // indirect
|
||||
github.com/fatih/structs v1.1.0 // indirect
|
||||
|
@ -74,24 +75,21 @@ require (
|
|||
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.2.4 // 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/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/glog v1.1.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/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.5.0 // indirect
|
||||
github.com/google/flatbuffers v2.0.8+incompatible // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/hashicorp/errwrap v1.0.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||
github.com/huandu/xstrings v1.3.2 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/compress v1.17.4 // indirect
|
||||
|
@ -106,7 +104,6 @@ require (
|
|||
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/philippgille/gokv/util v0.0.0-20191011213304-eb77f15b9c61 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.19 // indirect
|
||||
github.com/pion/datachannel v1.5.2 // indirect
|
||||
github.com/pion/dtls/v2 v2.2.4 // indirect
|
||||
|
@ -141,7 +138,7 @@ require (
|
|||
github.com/willscott/go-nfs-client v0.0.0-20240104095149-b44639837b00 // 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.opencensus.io v0.24.0 // 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
|
||||
|
|
109
go.sum
109
go.sum
|
@ -21,11 +21,10 @@ filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmG
|
|||
filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
|
||||
github.com/99designs/gqlgen v0.17.43 h1:I4SYg6ahjowErAQcHFVKy5EcWuwJ3+Xw9z2fLpuFCPo=
|
||||
github.com/99designs/gqlgen v0.17.43/go.mod h1:lO0Zjy8MkZgBdv4T1U91x09r0e0WFOdhVUutlQs1Rsc=
|
||||
github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
|
||||
github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIoKjsnZuH8vjyaysT/ses3EvZeaV/1UkF2M=
|
||||
github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
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=
|
||||
|
@ -49,15 +48,15 @@ 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.21.0 h1:8nzI+faaynY9jOKmVgdmBZVrTo8B7ZE/LKEgN3Vl/Bs=
|
||||
github.com/anacrolix/dht/v2 v2.21.0/go.mod h1:SDGC+sEs1pnO2sJGYuhvIis7T8749dDHNfcjtdH4e3g=
|
||||
github.com/anacrolix/dht/v2 v2.19.2-0.20221121215055-066ad8494444 h1:8V0K09lrGoeT2KRJNOtspA7q+OMxGwQqK/Ug0IiaaRE=
|
||||
github.com/anacrolix/dht/v2 v2.19.2-0.20221121215055-066ad8494444/go.mod h1:MctKM1HS5YYDb3F30NGJxLE+QPuqWoT5ReW/4jt8xew=
|
||||
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-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=
|
||||
|
@ -96,8 +95,8 @@ github.com/anacrolix/sync v0.5.1/go.mod h1:BbecHL6jDSExojhNtgTFSBcdGerzNc64tz3DC
|
|||
github.com/anacrolix/tagflag v0.0.0-20180109131632-2146c8d41bf0/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pmhJXOKKCHw=
|
||||
github.com/anacrolix/tagflag v1.0.0/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pmhJXOKKCHw=
|
||||
github.com/anacrolix/tagflag v1.1.0/go.mod h1:Scxs9CV10NQatSmbyjqmqmeQNwGzlNe0CMUMIxqHIG8=
|
||||
github.com/anacrolix/torrent v1.54.0 h1:sl+2J1pHjJWq6+5G861+Yc74k2XTc/m8ijaMQR/8+2k=
|
||||
github.com/anacrolix/torrent v1.54.0/go.mod h1:is8GNob5qDeZ5Kq+pKPiE2xqYUi1ms7IgSB+CftZETk=
|
||||
github.com/anacrolix/torrent v1.55.0 h1:s9yh/YGdPmbN9dTa+0Inh2dLdrLQRvEAj1jdFW/Hdd8=
|
||||
github.com/anacrolix/torrent v1.55.0/go.mod h1:sBdZHBSZNj4de0m+EbYg7vvs/G/STubxu/GzzNbojsE=
|
||||
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=
|
||||
|
@ -109,7 +108,6 @@ github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHG
|
|||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
|
||||
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
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=
|
||||
|
@ -137,6 +135,8 @@ github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1
|
|||
github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
|
||||
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
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=
|
||||
|
@ -147,18 +147,13 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR
|
|||
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/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
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/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=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgraph-io/badger v1.6.0 h1:DshxFxZWXUcO0xX476VJC07Xsr6ZCBVRHKZ93Oh7Evo=
|
||||
github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=
|
||||
github.com/dgraph-io/badger/v4 v4.2.0 h1:kJrlajbXXL9DFTNuhhu9yCx7JJa4qpYWxtE8BzuWsEs=
|
||||
github.com/dgraph-io/badger/v4 v4.2.0/go.mod h1:qfCqhPoWDFJRx1gp5QwwyGo8xk1lbHUxvK9nK0OGAak=
|
||||
github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8=
|
||||
|
@ -176,7 +171,9 @@ github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1
|
|||
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=
|
||||
|
@ -215,8 +212,8 @@ 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.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
||||
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
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=
|
||||
|
@ -233,18 +230,18 @@ github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg
|
|||
github.com/go-playground/validator/v10 v10.14.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/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho=
|
||||
github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
|
||||
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/gofrs/uuid/v5 v5.0.0 h1:p544++a97kEL+svbcFbCQVM9KFu0Yo25UoISXGNNH9M=
|
||||
github.com/gofrs/uuid/v5 v5.0.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
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.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE=
|
||||
github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ=
|
||||
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=
|
||||
|
@ -262,25 +259,30 @@ 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 v2.0.8+incompatible h1:ivUb1cGomAB101ZM1T0nOiWz9pSrTMoa9+EiY7igmkM=
|
||||
github.com/google/flatbuffers v2.0.8+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=
|
||||
|
@ -290,6 +292,7 @@ github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OI
|
|||
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.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0/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=
|
||||
|
@ -311,7 +314,6 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
|
|||
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/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
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=
|
||||
|
@ -322,7 +324,6 @@ github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq
|
|||
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/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
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=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
|
@ -368,15 +369,12 @@ 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/lmittmann/tint v1.0.4 h1:LeYihpJ9hyGvE0w+K2okPTGUdVLfng1+nDNVR4vWISc=
|
||||
github.com/lmittmann/tint v1.0.4/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
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=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
|
||||
|
@ -406,24 +404,10 @@ 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 v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
|
||||
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/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
|
||||
github.com/philippgille/gokv v0.0.0-20191001201555-5ac9a20de634/go.mod h1:OCoWPt+mbYuTO1FUVrQ2SxQU0oaaHBsn6lRhFX3JHOc=
|
||||
github.com/philippgille/gokv v0.5.1-0.20191011213304-eb77f15b9c61/go.mod h1:OCoWPt+mbYuTO1FUVrQ2SxQU0oaaHBsn6lRhFX3JHOc=
|
||||
github.com/philippgille/gokv v0.6.0 h1:fNEx/tSwV73nzlYd3iRYB8F+SEVJNNFzH1gsaT8SK2c=
|
||||
github.com/philippgille/gokv v0.6.0/go.mod h1:tjXRFw9xDHgxLS8WJdfYotKGWp8TWqu4RdXjMDG/XBo=
|
||||
github.com/philippgille/gokv/badgerdb v0.6.0 h1:4Qigf2SpyXLF8KaM5nA5/D/0aD/bZevuAnrW4ZsDsjA=
|
||||
github.com/philippgille/gokv/badgerdb v0.6.0/go.mod h1:3u2avs8gtmCc0R0Bw4jKV8aaDfLb5V9JToSASyhpFGM=
|
||||
github.com/philippgille/gokv/encoding v0.0.0-20191011213304-eb77f15b9c61/go.mod h1:SjxSrCoeYrYn85oTtroyG1ePY8aE72nvLQlw8IYwAN8=
|
||||
github.com/philippgille/gokv/encoding v0.6.0 h1:P1TN+Aulpd6Qd7qcLqgPwoxzOQ42UHBXOovWvFxJRI8=
|
||||
github.com/philippgille/gokv/encoding v0.6.0/go.mod h1:/yKvq2BKJlKJsH7KMDrhDlEw2Pt3V1nKyFhs4iOqz5U=
|
||||
github.com/philippgille/gokv/test v0.0.0-20191011213304-eb77f15b9c61 h1:4tVyBgfpK0NSqu7tNZTwYfC/pbyWUR2y+O7mxEg5BTQ=
|
||||
github.com/philippgille/gokv/test v0.0.0-20191011213304-eb77f15b9c61/go.mod h1:EUc+s9ONc1+VOr9NUEd8S0YbGRrQd/gz/p+2tvwt12s=
|
||||
github.com/philippgille/gokv/util v0.0.0-20191011213304-eb77f15b9c61 h1:ril/jI0JgXNjPWwDkvcRxlZ09kgHXV2349xChjbsQ4o=
|
||||
github.com/philippgille/gokv/util v0.0.0-20191011213304-eb77f15b9c61/go.mod h1:2dBhsJgY/yVIkjY5V3AnDUxUbEPzT6uQ3LvoVT8TR20=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pierrec/lz4/v4 v4.1.19 h1:tYLzDnjDXh9qIxSTKHwXwOYmm9d887Y7Y1ZkyXYHAN4=
|
||||
github.com/pierrec/lz4/v4 v4.1.19/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
|
@ -505,9 +489,12 @@ github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE
|
|||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||
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/royalcat/kv v0.0.0-20240316120131-b774a9bff6f7 h1:fmBTD0RaTvWbd6KrgLVXSDUJ4dWTPOFUdkdHp+kYvRM=
|
||||
github.com/royalcat/kv v0.0.0-20240316120131-b774a9bff6f7/go.mod h1:Ff0Z/r1H3ojacpEe8SashMKJx6YCIhWrYtpdV8Y/k3A=
|
||||
github.com/royalcat/kv v0.0.0-20240316134516-1bb692abce73 h1:zeFE8Nx11oD6In+f+VDYwGH72t7NV6L5dqaNbDIhB1E=
|
||||
github.com/royalcat/kv v0.0.0-20240316134516-1bb692abce73/go.mod h1:Ff0Z/r1H3ojacpEe8SashMKJx6YCIhWrYtpdV8Y/k3A=
|
||||
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/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk=
|
||||
|
@ -526,12 +513,8 @@ github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:X
|
|||
github.com/smartystreets/goconvey v0.0.0-20190306220146-200a235640ff/go.mod h1:KSQcGKpxUMHk3nbYzs/tIBAM2iDooCn0BmttHOJEbLs=
|
||||
github.com/sosodev/duration v1.1.0 h1:kQcaiGbJaIsRqgQy7VGlZrVw1giWO+lDoX3MCPnpVO4=
|
||||
github.com/sosodev/duration v1.1.0/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
|
@ -558,7 +541,6 @@ github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDW
|
|||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
|
||||
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
|
||||
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||
|
@ -574,7 +556,6 @@ github.com/willscott/go-nfs v0.0.2 h1:BaBp1CpGDMooCT6bCgX6h6ZwgPcTMST4yToYZ9byee
|
|||
github.com/willscott/go-nfs v0.0.2/go.mod h1:SvullWeHxr/924WQNbUaZqtluBt2vuZ61g6yAV+xj7w=
|
||||
github.com/willscott/go-nfs-client v0.0.0-20240104095149-b44639837b00 h1:U0DnHRZFzoIV1oFEZczg5XyPut9yxk9jjtax/9Bxr/o=
|
||||
github.com/willscott/go-nfs-client v0.0.0-20240104095149-b44639837b00/go.mod h1:Tq++Lr/FgiS3X48q5FETemXiSLGuYMQT2sPjYNPJSwA=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
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/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
|
@ -588,19 +569,20 @@ 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.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.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=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go4.org v0.0.0-20200411211856-f5505b9728dd h1:BNJlw5kRTzdmyfh5U8F93HA2OwkP7ZGwA51eJ/0wKOU=
|
||||
go4.org v0.0.0-20200411211856-f5505b9728dd/go.mod h1:CIiUVy99QCPfoE13bO4EZaz5GZMZXMSBGhxRdsvzbkg=
|
||||
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/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/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=
|
||||
|
@ -660,13 +642,13 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR
|
|||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191011234655-491137f69257/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-20201110031124-69a78807bb2b/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-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
|
@ -703,7 +685,6 @@ golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5h
|
|||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
@ -712,11 +693,9 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
@ -831,20 +810,26 @@ 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.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
|
|
|
@ -1,10 +1,20 @@
|
|||
type Mutation {
|
||||
validateTorrents(filter: TorrentFilter!): Boolean!
|
||||
cleanupTorrents(files: Boolean, dryRun: Boolean!): Int!
|
||||
downloadTorrent(infohash: String!, file: String): DownloadTorrentResponse
|
||||
}
|
||||
|
||||
|
||||
input TorrentFilter @oneOf {
|
||||
everything: Boolean
|
||||
infohash: String
|
||||
# pathGlob: String!
|
||||
}
|
||||
|
||||
type DownloadTorrentResponse {
|
||||
task: Task
|
||||
}
|
||||
|
||||
type Task {
|
||||
id: ID!
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
directive @oneOf on INPUT_OBJECT | FIELD_DEFINITION
|
||||
directive @stream on FIELD_DEFINITION
|
||||
|
||||
scalar DateTime
|
||||
|
||||
|
@ -6,4 +7,3 @@ type Schema {
|
|||
query: Query
|
||||
mutation: Mutation
|
||||
}
|
||||
|
||||
|
|
16
graphql/subscription.graphql
Normal file
16
graphql/subscription.graphql
Normal file
|
@ -0,0 +1,16 @@
|
|||
type Subscription {
|
||||
taskProgress(taskID: ID!): Progress
|
||||
torrentDownloadUpdates: TorrentProgress
|
||||
}
|
||||
|
||||
|
||||
type TorrentProgress implements Progress {
|
||||
torrent: Torrent!
|
||||
current: Int!
|
||||
total: Int!
|
||||
}
|
||||
|
||||
interface Progress {
|
||||
current: Int!
|
||||
total: Int!
|
||||
}
|
102
pkg/uuid/uuid.go
Normal file
102
pkg/uuid/uuid.go
Normal file
|
@ -0,0 +1,102 @@
|
|||
package uuid
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
fuuid "github.com/gofrs/uuid/v5"
|
||||
)
|
||||
|
||||
var Nil = UUID{}
|
||||
|
||||
type UUIDList = []UUID
|
||||
|
||||
type UUID struct {
|
||||
fuuid.UUID
|
||||
}
|
||||
|
||||
func New() UUID {
|
||||
return UUID{fuuid.Must(fuuid.NewV7())}
|
||||
}
|
||||
|
||||
func NewFromTime(t time.Time) UUID {
|
||||
gen := fuuid.NewGenWithOptions(
|
||||
fuuid.WithEpochFunc(func() time.Time { return t }),
|
||||
)
|
||||
return UUID{fuuid.Must(gen.NewV7())}
|
||||
}
|
||||
|
||||
func NewP() *UUID {
|
||||
return &UUID{fuuid.Must(fuuid.NewV7())}
|
||||
}
|
||||
|
||||
func FromString(text string) (UUID, error) {
|
||||
u, err := fuuid.FromString(text)
|
||||
if err != nil {
|
||||
return Nil, err
|
||||
}
|
||||
|
||||
return UUID{u}, nil
|
||||
}
|
||||
|
||||
func MustFromString(text string) UUID {
|
||||
u, err := fuuid.FromString(text)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return UUID{u}
|
||||
}
|
||||
|
||||
func FromBytes(input []byte) (UUID, error) {
|
||||
u, err := fuuid.FromBytes(input)
|
||||
if err != nil {
|
||||
return Nil, err
|
||||
}
|
||||
|
||||
return UUID{u}, nil
|
||||
}
|
||||
|
||||
func (a *UUID) UnmarshalJSON(b []byte) error {
|
||||
var s string
|
||||
if err := json.Unmarshal(b, &s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if s == "" {
|
||||
a.UUID = fuuid.Nil
|
||||
return nil
|
||||
}
|
||||
|
||||
return a.UUID.Parse(s)
|
||||
}
|
||||
|
||||
func (a UUID) MarshalJSON() ([]byte, error) {
|
||||
if a.IsNil() {
|
||||
return json.Marshal("")
|
||||
}
|
||||
|
||||
return json.Marshal(a.UUID)
|
||||
}
|
||||
|
||||
// UnmarshalGQL implements the graphql.Unmarshaler interface
|
||||
func (u *UUID) UnmarshalGQL(v interface{}) error {
|
||||
id, ok := v.(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("uuid must be a string")
|
||||
}
|
||||
|
||||
return u.Parse(id)
|
||||
}
|
||||
|
||||
// MarshalGQL implements the graphql.Marshaler interface
|
||||
func (u UUID) MarshalGQL(w io.Writer) {
|
||||
b := []byte(strconv.Quote(u.String()))
|
||||
_, err := w.Write(b)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,9 @@
|
|||
package model
|
||||
|
||||
import "github.com/anacrolix/torrent"
|
||||
import (
|
||||
"git.kmsign.ru/royalcat/tstor/src/host/controller"
|
||||
"github.com/anacrolix/torrent"
|
||||
)
|
||||
|
||||
func MapPeerSource(source torrent.PeerSource) string {
|
||||
switch source {
|
||||
|
@ -22,3 +25,13 @@ func MapPeerSource(source torrent.PeerSource) string {
|
|||
return "Unknown"
|
||||
}
|
||||
}
|
||||
|
||||
func MapTorrent(t *controller.Torrent) *Torrent {
|
||||
return &Torrent{
|
||||
Infohash: t.InfoHash(),
|
||||
Name: t.Name(),
|
||||
BytesCompleted: t.BytesCompleted(),
|
||||
BytesMissing: t.BytesMissing(),
|
||||
T: t,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,12 @@ import (
|
|||
"github.com/anacrolix/torrent"
|
||||
)
|
||||
|
||||
type Progress interface {
|
||||
IsProgress()
|
||||
GetCurrent() int64
|
||||
GetTotal() int64
|
||||
}
|
||||
|
||||
type BooleanFilter struct {
|
||||
Eq *bool `json:"eq,omitempty"`
|
||||
}
|
||||
|
@ -21,6 +27,10 @@ type DateTimeFilter struct {
|
|||
Lte *time.Time `json:"lte,omitempty"`
|
||||
}
|
||||
|
||||
type DownloadTorrentResponse struct {
|
||||
Task *Task `json:"task,omitempty"`
|
||||
}
|
||||
|
||||
type IntFilter struct {
|
||||
Eq *int64 `json:"eq,omitempty"`
|
||||
Gt *int64 `json:"gt,omitempty"`
|
||||
|
@ -52,6 +62,13 @@ type StringFilter struct {
|
|||
In []string `json:"in,omitempty"`
|
||||
}
|
||||
|
||||
type Subscription struct {
|
||||
}
|
||||
|
||||
type Task struct {
|
||||
ID string `json:"id"`
|
||||
}
|
||||
|
||||
type Torrent struct {
|
||||
Name string `json:"name"`
|
||||
Infohash string `json:"infohash"`
|
||||
|
@ -85,6 +102,16 @@ type TorrentPeer struct {
|
|||
F *torrent.PeerConn `json:"-"`
|
||||
}
|
||||
|
||||
type TorrentProgress struct {
|
||||
Torrent *Torrent `json:"torrent"`
|
||||
Current int64 `json:"current"`
|
||||
Total int64 `json:"total"`
|
||||
}
|
||||
|
||||
func (TorrentProgress) IsProgress() {}
|
||||
func (this TorrentProgress) GetCurrent() int64 { return this.Current }
|
||||
func (this TorrentProgress) GetTotal() int64 { return this.Total }
|
||||
|
||||
type TorrentsFilter struct {
|
||||
Name *StringFilter `json:"name,omitempty"`
|
||||
BytesCompleted *IntFilter `json:"bytesCompleted,omitempty"`
|
||||
|
|
|
@ -7,8 +7,11 @@ package resolver
|
|||
import (
|
||||
"context"
|
||||
|
||||
"git.kmsign.ru/royalcat/tstor/pkg/uuid"
|
||||
graph "git.kmsign.ru/royalcat/tstor/src/delivery/graphql"
|
||||
"git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model"
|
||||
"git.kmsign.ru/royalcat/tstor/src/host/service"
|
||||
aih "github.com/anacrolix/torrent/types/infohash"
|
||||
)
|
||||
|
||||
// ValidateTorrents is the resolver for the validateTorrents field.
|
||||
|
@ -58,6 +61,25 @@ func (r *mutationResolver) CleanupTorrents(ctx context.Context, files *bool, dry
|
|||
}
|
||||
}
|
||||
|
||||
// DownloadTorrent is the resolver for the downloadTorrent field.
|
||||
func (r *mutationResolver) DownloadTorrent(ctx context.Context, infohash string, file *string) (*model.DownloadTorrentResponse, error) {
|
||||
f := ""
|
||||
if file != nil {
|
||||
f = *file
|
||||
}
|
||||
|
||||
err := r.Service.Download(ctx, &service.TorrentDownloadTask{
|
||||
ID: uuid.New(),
|
||||
InfoHash: aih.FromHexString(infohash),
|
||||
File: f,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &model.DownloadTorrentResponse{}, nil
|
||||
}
|
||||
|
||||
// Mutation returns graph.MutationResolver implementation.
|
||||
func (r *Resolver) Mutation() graph.MutationResolver { return &mutationResolver{r} }
|
||||
|
||||
|
|
|
@ -52,13 +52,7 @@ func (r *queryResolver) Torrents(ctx context.Context, filter *model.TorrentsFilt
|
|||
|
||||
tr := []*model.Torrent{}
|
||||
for _, t := range torrents {
|
||||
d := &model.Torrent{
|
||||
Infohash: t.InfoHash(),
|
||||
Name: t.Name(),
|
||||
BytesCompleted: t.BytesCompleted(),
|
||||
BytesMissing: t.BytesMissing(),
|
||||
T: t,
|
||||
}
|
||||
d := model.MapTorrent(t)
|
||||
|
||||
if !filterFunc(d) {
|
||||
continue
|
||||
|
|
54
src/delivery/graphql/resolver/subscription.resolvers.go
Normal file
54
src/delivery/graphql/resolver/subscription.resolvers.go
Normal file
|
@ -0,0 +1,54 @@
|
|||
package resolver
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
// Code generated by github.com/99designs/gqlgen version v0.17.43
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
graph "git.kmsign.ru/royalcat/tstor/src/delivery/graphql"
|
||||
"git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model"
|
||||
)
|
||||
|
||||
// TaskProgress is the resolver for the taskProgress field.
|
||||
func (r *subscriptionResolver) TaskProgress(ctx context.Context, taskID string) (<-chan model.Progress, error) {
|
||||
panic(fmt.Errorf("not implemented: TaskProgress - taskProgress"))
|
||||
}
|
||||
|
||||
// TorrentDownloadUpdates is the resolver for the torrentDownloadUpdates field.
|
||||
func (r *subscriptionResolver) TorrentDownloadUpdates(ctx context.Context) (<-chan *model.TorrentProgress, error) {
|
||||
out := make(chan *model.TorrentProgress)
|
||||
progress, err := r.Service.DownloadProgress(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer close(out)
|
||||
for p := range progress {
|
||||
if p.Torrent == nil {
|
||||
fmt.Println("nil torrent")
|
||||
continue
|
||||
}
|
||||
po := &model.TorrentProgress{
|
||||
Torrent: model.MapTorrent(p.Torrent),
|
||||
Current: p.Current,
|
||||
Total: p.Total,
|
||||
}
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case out <- po:
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// Subscription returns graph.SubscriptionResolver implementation.
|
||||
func (r *Resolver) Subscription() graph.SubscriptionResolver { return &subscriptionResolver{r} }
|
||||
|
||||
type subscriptionResolver struct{ *Resolver }
|
|
@ -19,7 +19,7 @@ func (r *torrentResolver) Name(ctx context.Context, obj *model.Torrent) (string,
|
|||
// Files is the resolver for the files field.
|
||||
func (r *torrentResolver) Files(ctx context.Context, obj *model.Torrent) ([]*model.TorrentFile, error) {
|
||||
out := []*model.TorrentFile{}
|
||||
files, err := obj.T.Files()
|
||||
files, err := obj.T.Files(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -37,17 +37,17 @@ func (r *torrentResolver) Files(ctx context.Context, obj *model.Torrent) ([]*mod
|
|||
// ExcludedFiles is the resolver for the excludedFiles field.
|
||||
func (r *torrentResolver) ExcludedFiles(ctx context.Context, obj *model.Torrent) ([]*model.TorrentFile, error) {
|
||||
out := []*model.TorrentFile{}
|
||||
files, err := obj.T.ExcludedFiles()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, f := range files {
|
||||
out = append(out, &model.TorrentFile{
|
||||
Filename: f.DisplayPath(),
|
||||
Size: f.Length(),
|
||||
F: f,
|
||||
})
|
||||
}
|
||||
// files, err := obj.T.ExcludedFiles()
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// for _, f := range files {
|
||||
// out = append(out, &model.TorrentFile{
|
||||
// Filename: f.DisplayPath(),
|
||||
// Size: f.Length(),
|
||||
// F: f,
|
||||
// })
|
||||
// }
|
||||
return out, nil
|
||||
}
|
||||
|
||||
|
|
197
src/export/nfs/cache.go
Normal file
197
src/export/nfs/cache.go
Normal file
|
@ -0,0 +1,197 @@
|
|||
package nfs
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"io/fs"
|
||||
"reflect"
|
||||
"slices"
|
||||
|
||||
"github.com/willscott/go-nfs"
|
||||
|
||||
"github.com/go-git/go-billy/v5"
|
||||
"github.com/google/uuid"
|
||||
lru "github.com/hashicorp/golang-lru/v2"
|
||||
)
|
||||
|
||||
// NewCachingHandler wraps a handler to provide a basic to/from-file handle cache.
|
||||
func NewCachingHandler(h nfs.Handler, limit int) nfs.Handler {
|
||||
return NewCachingHandlerWithVerifierLimit(h, limit, limit)
|
||||
}
|
||||
|
||||
// NewCachingHandlerWithVerifierLimit provides a basic to/from-file handle cache that can be tuned with a smaller cache of active directory listings.
|
||||
func NewCachingHandlerWithVerifierLimit(h nfs.Handler, limit int, verifierLimit int) nfs.Handler {
|
||||
if limit < 2 || verifierLimit < 2 {
|
||||
nfs.Log.Warnf("Caching handler created with insufficient cache to support directory listing", "size", limit, "verifiers", verifierLimit)
|
||||
}
|
||||
cache, _ := lru.New[uuid.UUID, entry](limit)
|
||||
reverseCache := make(map[string][]uuid.UUID)
|
||||
verifiers, _ := lru.New[uint64, verifier](verifierLimit)
|
||||
return &CachingHandler{
|
||||
Handler: h,
|
||||
activeHandles: cache,
|
||||
reverseHandles: reverseCache,
|
||||
activeVerifiers: verifiers,
|
||||
cacheLimit: limit,
|
||||
}
|
||||
}
|
||||
|
||||
// CachingHandler implements to/from handle via an LRU cache.
|
||||
type CachingHandler struct {
|
||||
nfs.Handler
|
||||
activeHandles *lru.Cache[uuid.UUID, entry]
|
||||
reverseHandles map[string][]uuid.UUID
|
||||
activeVerifiers *lru.Cache[uint64, verifier]
|
||||
cacheLimit int
|
||||
}
|
||||
|
||||
type entry struct {
|
||||
f billy.Filesystem
|
||||
p []string
|
||||
}
|
||||
|
||||
// ToHandle takes a file and represents it with an opaque handle to reference it.
|
||||
// In stateless nfs (when it's serving a unix fs) this can be the device + inode
|
||||
// but we can generalize with a stateful local cache of handed out IDs.
|
||||
func (c *CachingHandler) ToHandle(f billy.Filesystem, path []string) []byte {
|
||||
joinedPath := f.Join(path...)
|
||||
|
||||
if handle := c.searchReverseCache(f, joinedPath); handle != nil {
|
||||
return handle
|
||||
}
|
||||
|
||||
id := uuid.New()
|
||||
|
||||
newPath := make([]string, len(path))
|
||||
|
||||
copy(newPath, path)
|
||||
evictedKey, evictedPath, ok := c.activeHandles.GetOldest()
|
||||
if evicted := c.activeHandles.Add(id, entry{f, newPath}); evicted && ok {
|
||||
rk := evictedPath.f.Join(evictedPath.p...)
|
||||
c.evictReverseCache(rk, evictedKey)
|
||||
}
|
||||
|
||||
if _, ok := c.reverseHandles[joinedPath]; !ok {
|
||||
c.reverseHandles[joinedPath] = []uuid.UUID{}
|
||||
}
|
||||
c.reverseHandles[joinedPath] = append(c.reverseHandles[joinedPath], id)
|
||||
b, _ := id.MarshalBinary()
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// FromHandle converts from an opaque handle to the file it represents
|
||||
func (c *CachingHandler) FromHandle(fh []byte) (billy.Filesystem, []string, error) {
|
||||
id, err := uuid.FromBytes(fh)
|
||||
if err != nil {
|
||||
return nil, []string{}, err
|
||||
}
|
||||
|
||||
if f, ok := c.activeHandles.Get(id); ok {
|
||||
for _, k := range c.activeHandles.Keys() {
|
||||
candidate, _ := c.activeHandles.Peek(k)
|
||||
if hasPrefix(f.p, candidate.p) {
|
||||
_, _ = c.activeHandles.Get(k)
|
||||
}
|
||||
}
|
||||
|
||||
return f.f, slices.Clone(f.p), nil
|
||||
}
|
||||
return nil, []string{}, &nfs.NFSStatusError{NFSStatus: nfs.NFSStatusStale}
|
||||
}
|
||||
|
||||
func (c *CachingHandler) searchReverseCache(f billy.Filesystem, path string) []byte {
|
||||
uuids, exists := c.reverseHandles[path]
|
||||
|
||||
if !exists {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, id := range uuids {
|
||||
if candidate, ok := c.activeHandles.Get(id); ok {
|
||||
if reflect.DeepEqual(candidate.f, f) {
|
||||
return id[:]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *CachingHandler) evictReverseCache(path string, handle uuid.UUID) {
|
||||
uuids, exists := c.reverseHandles[path]
|
||||
|
||||
if !exists {
|
||||
return
|
||||
}
|
||||
for i, u := range uuids {
|
||||
if u == handle {
|
||||
uuids = append(uuids[:i], uuids[i+1:]...)
|
||||
c.reverseHandles[path] = uuids
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *CachingHandler) InvalidateHandle(fs billy.Filesystem, handle []byte) error {
|
||||
//Remove from cache
|
||||
id, _ := uuid.FromBytes(handle)
|
||||
entry, ok := c.activeHandles.Get(id)
|
||||
if ok {
|
||||
rk := entry.f.Join(entry.p...)
|
||||
c.evictReverseCache(rk, id)
|
||||
}
|
||||
c.activeHandles.Remove(id)
|
||||
return nil
|
||||
}
|
||||
|
||||
// HandleLimit exports how many file handles can be safely stored by this cache.
|
||||
func (c *CachingHandler) HandleLimit() int {
|
||||
return c.cacheLimit
|
||||
}
|
||||
|
||||
func hasPrefix(path, prefix []string) bool {
|
||||
if len(prefix) > len(path) {
|
||||
return false
|
||||
}
|
||||
for i, e := range prefix {
|
||||
if path[i] != e {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
type verifier struct {
|
||||
path string
|
||||
contents []fs.FileInfo
|
||||
}
|
||||
|
||||
func hashPathAndContents(path string, contents []fs.FileInfo) uint64 {
|
||||
//calculate a cookie-verifier.
|
||||
vHash := sha256.New()
|
||||
|
||||
// Add the path to avoid collisions of directories with the same content
|
||||
vHash.Write(binary.BigEndian.AppendUint64([]byte{}, uint64(len(path))))
|
||||
vHash.Write([]byte(path))
|
||||
|
||||
for _, c := range contents {
|
||||
vHash.Write([]byte(c.Name())) // Never fails according to the docs
|
||||
}
|
||||
|
||||
verify := vHash.Sum(nil)[0:8]
|
||||
return binary.BigEndian.Uint64(verify)
|
||||
}
|
||||
|
||||
func (c *CachingHandler) VerifierFor(path string, contents []fs.FileInfo) uint64 {
|
||||
id := hashPathAndContents(path, contents)
|
||||
c.activeVerifiers.Add(id, verifier{path, contents})
|
||||
return id
|
||||
}
|
||||
|
||||
func (c *CachingHandler) DataForVerifier(path string, id uint64) []fs.FileInfo {
|
||||
if cache, ok := c.activeVerifiers.Get(id); ok {
|
||||
return cache.contents
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -17,7 +17,7 @@ func NewNFSv3Handler(fs vfs.Filesystem) (nfs.Handler, error) {
|
|||
bfs := &billyFsWrapper{fs: fs, log: nfslog}
|
||||
handler := nfshelper.NewNullAuthHandler(bfs)
|
||||
|
||||
cacheHelper := nfshelper.NewCachingHandler(handler, 1024*16)
|
||||
cacheHelper := nfshelper.NewCachingHandler(handler, 1024)
|
||||
|
||||
// cacheHelper := NewCachingHandler(handler)
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
|
@ -11,10 +12,10 @@ import (
|
|||
type Torrent struct {
|
||||
torrentFilePath string
|
||||
t *torrent.Torrent
|
||||
rep *store.ExlcudedFiles
|
||||
rep *store.FilesMappings
|
||||
}
|
||||
|
||||
func NewTorrent(t *torrent.Torrent, rep *store.ExlcudedFiles) *Torrent {
|
||||
func NewTorrent(t *torrent.Torrent, rep *store.FilesMappings) *Torrent {
|
||||
return &Torrent{t: t, rep: rep}
|
||||
}
|
||||
|
||||
|
@ -26,13 +27,13 @@ func (s *Torrent) Torrent() *torrent.Torrent {
|
|||
return s.t
|
||||
}
|
||||
|
||||
func (s *Torrent) Name() string {
|
||||
<-s.t.GotInfo()
|
||||
if name := s.t.Name(); name != "" {
|
||||
func (c *Torrent) Name() string {
|
||||
<-c.t.GotInfo()
|
||||
if name := c.t.Name(); name != "" {
|
||||
return name
|
||||
}
|
||||
|
||||
return s.InfoHash()
|
||||
return c.InfoHash()
|
||||
}
|
||||
|
||||
func (s *Torrent) InfoHash() string {
|
||||
|
@ -50,8 +51,13 @@ func (s *Torrent) BytesMissing() int64 {
|
|||
return s.t.BytesMissing()
|
||||
}
|
||||
|
||||
func (s *Torrent) Files() ([]*torrent.File, error) {
|
||||
excludedFiles, err := s.rep.ExcludedFiles(s.t.InfoHash())
|
||||
func (s *Torrent) Length() int64 {
|
||||
<-s.t.GotInfo()
|
||||
return s.t.Length()
|
||||
}
|
||||
|
||||
func (s *Torrent) Files(ctx context.Context) ([]*torrent.File, error) {
|
||||
fileMappings, err := s.rep.FileMappings(ctx, s.t.InfoHash())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -60,25 +66,30 @@ func (s *Torrent) Files() ([]*torrent.File, error) {
|
|||
files := s.t.Files()
|
||||
files = slices.DeleteFunc(files, func(file *torrent.File) bool {
|
||||
p := file.Path()
|
||||
|
||||
if strings.Contains(p, "/.pad/") {
|
||||
return false
|
||||
}
|
||||
|
||||
if !slices.Contains(excludedFiles, p) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
if target, ok := fileMappings[p]; ok && target == "" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
for _, tf := range files {
|
||||
s.isFileComplete(tf.BeginPieceIndex(), tf.EndPieceIndex())
|
||||
}
|
||||
|
||||
return files, nil
|
||||
}
|
||||
|
||||
func Map[T, U any](ts []T, f func(T) U) []U {
|
||||
us := make([]U, len(ts))
|
||||
for i := range ts {
|
||||
us[i] = f(ts[i])
|
||||
}
|
||||
return us
|
||||
}
|
||||
|
||||
func (s *Torrent) ExcludeFile(ctx context.Context, f *torrent.File) error {
|
||||
return s.rep.ExcludeFile(ctx, f)
|
||||
}
|
||||
|
||||
func (s *Torrent) isFileComplete(startIndex int, endIndex int) bool {
|
||||
for i := startIndex; i < endIndex; i++ {
|
||||
if !s.t.Piece(i).State().Complete {
|
||||
|
@ -88,35 +99,6 @@ func (s *Torrent) isFileComplete(startIndex int, endIndex int) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func (s *Torrent) ExcludedFiles() ([]*torrent.File, error) {
|
||||
excludedFiles, err := s.rep.ExcludedFiles(s.t.InfoHash())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
<-s.t.GotInfo()
|
||||
files := s.t.Files()
|
||||
files = slices.DeleteFunc(files, func(file *torrent.File) bool {
|
||||
p := file.Path()
|
||||
|
||||
if strings.Contains(p, "/.pad/") {
|
||||
return false
|
||||
}
|
||||
|
||||
if slices.Contains(excludedFiles, p) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
return files, nil
|
||||
}
|
||||
|
||||
func (s *Torrent) ExcludeFile(f *torrent.File) error {
|
||||
return s.rep.ExcludeFile(f)
|
||||
}
|
||||
|
||||
func (s *Torrent) ValidateTorrent() error {
|
||||
<-s.t.GotInfo()
|
||||
s.t.VerifyData()
|
||||
|
|
172
src/host/datastorage/piece_storage.go
Normal file
172
src/host/datastorage/piece_storage.go
Normal file
|
@ -0,0 +1,172 @@
|
|||
package datastorage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"git.kmsign.ru/royalcat/tstor/src/host/controller"
|
||||
"github.com/anacrolix/torrent"
|
||||
"github.com/anacrolix/torrent/metainfo"
|
||||
"github.com/anacrolix/torrent/storage"
|
||||
"github.com/anacrolix/torrent/types/infohash"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/royalcat/kv"
|
||||
)
|
||||
|
||||
type PieceStorage struct {
|
||||
basePath string
|
||||
completion storage.PieceCompletion
|
||||
dirInfohash kv.Store[string, infohash.T]
|
||||
}
|
||||
|
||||
func NewPieceStorage(path string, completion storage.PieceCompletion) *PieceStorage {
|
||||
return &PieceStorage{
|
||||
basePath: path,
|
||||
completion: completion,
|
||||
}
|
||||
}
|
||||
|
||||
var _ DataStorage = (*PieceStorage)(nil)
|
||||
|
||||
// OpenTorrent implements FileStorageDeleter.
|
||||
func (p *PieceStorage) OpenTorrent(info *metainfo.Info, infoHash infohash.T) (storage.TorrentImpl, error) {
|
||||
torrentPath := path.Join(p.basePath, infoHash.HexString())
|
||||
descriptors := []*os.File{}
|
||||
|
||||
return storage.TorrentImpl{
|
||||
Piece: func(piece metainfo.Piece) storage.PieceImpl {
|
||||
hash := piece.Hash().HexString()
|
||||
piecePrefixDir := path.Join(torrentPath, hash[:2])
|
||||
err := os.MkdirAll(piecePrefixDir, os.ModePerm|os.ModeDir)
|
||||
if err != nil {
|
||||
return &errPiece{err: err}
|
||||
}
|
||||
piecePath := path.Join(torrentPath, hash[:2], hash)
|
||||
file, err := os.OpenFile(piecePath, os.O_CREATE|os.O_RDWR, os.ModePerm)
|
||||
if err != nil {
|
||||
return &errPiece{err: err}
|
||||
}
|
||||
pk := metainfo.PieceKey{
|
||||
InfoHash: infoHash,
|
||||
Index: piece.Index(),
|
||||
}
|
||||
return newPieceFile(pk, file, p.completion)
|
||||
|
||||
// file, err os.OpenFile(piecePath)
|
||||
},
|
||||
Flush: func() error {
|
||||
var res error
|
||||
for _, f := range descriptors {
|
||||
if err := f.Sync(); err != nil {
|
||||
res = multierror.Append(res, err)
|
||||
}
|
||||
}
|
||||
return res
|
||||
},
|
||||
Close: func() error {
|
||||
var res error
|
||||
for _, f := range descriptors {
|
||||
if err := f.Close(); err != nil {
|
||||
res = multierror.Append(res, err)
|
||||
}
|
||||
}
|
||||
return res
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Close implements FileStorageDeleter.
|
||||
func (p *PieceStorage) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteFile implements FileStorageDeleter.
|
||||
func (p *PieceStorage) DeleteFile(file *torrent.File) error {
|
||||
return fmt.Errorf("not implemented")
|
||||
}
|
||||
|
||||
// CleanupDirs implements DataStorage.
|
||||
func (p *PieceStorage) CleanupDirs(ctx context.Context, expected []*controller.Torrent, dryRun bool) (int, error) {
|
||||
return 0, nil // TODO
|
||||
}
|
||||
|
||||
// CleanupFiles implements DataStorage.
|
||||
func (p *PieceStorage) CleanupFiles(ctx context.Context, expected []*controller.Torrent, dryRun bool) (int, error) {
|
||||
return 0, nil // TODO
|
||||
}
|
||||
|
||||
func newPieceFile(pk metainfo.PieceKey, file *os.File, completion storage.PieceCompletionGetSetter) *piece {
|
||||
return &piece{
|
||||
pk: pk,
|
||||
File: file,
|
||||
completion: completion,
|
||||
}
|
||||
}
|
||||
|
||||
type piece struct {
|
||||
*os.File
|
||||
pk metainfo.PieceKey
|
||||
completion storage.PieceCompletionGetSetter
|
||||
}
|
||||
|
||||
// Completion implements storage.PieceImpl.
|
||||
func (p *piece) Completion() storage.Completion {
|
||||
compl, err := p.completion.Get(p.pk)
|
||||
if err != nil {
|
||||
return storage.Completion{Complete: false, Ok: false, Err: err}
|
||||
}
|
||||
return compl
|
||||
}
|
||||
|
||||
// MarkComplete implements storage.PieceImpl.
|
||||
func (p *piece) MarkComplete() error {
|
||||
return p.completion.Set(p.pk, true)
|
||||
}
|
||||
|
||||
// MarkNotComplete implements storage.PieceImpl.
|
||||
func (p *piece) MarkNotComplete() error {
|
||||
return p.completion.Set(p.pk, false)
|
||||
}
|
||||
|
||||
var _ storage.PieceImpl = (*piece)(nil)
|
||||
var _ io.WriterTo = (*piece)(nil)
|
||||
|
||||
type errPiece struct {
|
||||
err error
|
||||
}
|
||||
|
||||
// WriteTo implements io.WriterTo.
|
||||
func (p *errPiece) WriteTo(io.Writer) (int64, error) {
|
||||
return 0, p.err
|
||||
}
|
||||
|
||||
// ReadAt implements storage.PieceImpl.
|
||||
func (p *errPiece) ReadAt([]byte, int64) (int, error) {
|
||||
return 0, p.err
|
||||
}
|
||||
|
||||
// WriteAt implements storage.PieceImpl.
|
||||
func (p *errPiece) WriteAt([]byte, int64) (int, error) {
|
||||
return 0, p.err
|
||||
}
|
||||
|
||||
// Completion implements storage.PieceImpl.
|
||||
func (p *errPiece) Completion() storage.Completion {
|
||||
return storage.Completion{Complete: false, Ok: false, Err: p.err}
|
||||
}
|
||||
|
||||
// MarkComplete implements storage.PieceImpl.
|
||||
func (p *errPiece) MarkComplete() error {
|
||||
return p.err
|
||||
}
|
||||
|
||||
// MarkNotComplete implements storage.PieceImpl.
|
||||
func (p *errPiece) MarkNotComplete() error {
|
||||
return p.err
|
||||
}
|
||||
|
||||
var _ storage.PieceImpl = (*errPiece)(nil)
|
||||
var _ io.WriterTo = (*errPiece)(nil)
|
|
@ -1,4 +1,4 @@
|
|||
package filestorage
|
||||
package datastorage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
@ -10,7 +10,7 @@ import (
|
|||
"github.com/anacrolix/torrent/storage"
|
||||
)
|
||||
|
||||
func Setup(cfg config.TorrentClient) (*FileStorage, storage.PieceCompletion, error) {
|
||||
func Setup(cfg config.TorrentClient) (DataStorage, storage.PieceCompletion, error) {
|
||||
pcp := filepath.Join(cfg.MetadataFolder, "piece-completion")
|
||||
if err := os.MkdirAll(pcp, 0744); err != nil {
|
||||
return nil, nil, fmt.Errorf("error creating piece completion folder: %w", err)
|
|
@ -1,4 +1,4 @@
|
|||
package filestorage
|
||||
package datastorage
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
@ -14,9 +14,11 @@ import (
|
|||
"github.com/anacrolix/torrent/storage"
|
||||
)
|
||||
|
||||
type FileStorageDeleter interface {
|
||||
type DataStorage interface {
|
||||
storage.ClientImplCloser
|
||||
DeleteFile(file *torrent.File) error
|
||||
CleanupDirs(ctx context.Context, expected []*controller.Torrent, dryRun bool) (int, error)
|
||||
CleanupFiles(ctx context.Context, expected []*controller.Torrent, dryRun bool) (int, error)
|
||||
}
|
||||
|
||||
// NewFileStorage creates a new ClientImplCloser that stores files using the OS native filesystem.
|
||||
|
@ -137,7 +139,7 @@ func (fs *FileStorage) CleanupFiles(ctx context.Context, expected []*controller.
|
|||
expectedEntries := []string{}
|
||||
{
|
||||
for _, e := range expected {
|
||||
files, err := e.Files()
|
||||
files, err := e.Files(ctx)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
130
src/host/service/queue.go
Normal file
130
src/host/service/queue.go
Normal file
|
@ -0,0 +1,130 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"git.kmsign.ru/royalcat/tstor/pkg/uuid"
|
||||
"git.kmsign.ru/royalcat/tstor/src/host/controller"
|
||||
"github.com/anacrolix/torrent"
|
||||
"github.com/anacrolix/torrent/types/infohash"
|
||||
)
|
||||
|
||||
type TorrentDownloadTask struct {
|
||||
ID uuid.UUID
|
||||
InfoHash infohash.T
|
||||
File string
|
||||
}
|
||||
|
||||
func (s *Service) Download(ctx context.Context, task *TorrentDownloadTask) error {
|
||||
t, ok := s.c.Torrent(task.InfoHash)
|
||||
if !ok {
|
||||
return fmt.Errorf("torrent with IH %s not found", task.InfoHash.HexString())
|
||||
}
|
||||
|
||||
if task.File != "" {
|
||||
var file *torrent.File
|
||||
for _, tf := range t.Files() {
|
||||
if tf.Path() == task.File {
|
||||
file = tf
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if file == nil {
|
||||
return fmt.Errorf("file %s not found in torrent torrent with IH %s", task.File, task.InfoHash.HexString())
|
||||
}
|
||||
|
||||
file.Download()
|
||||
return nil
|
||||
}
|
||||
|
||||
t.DownloadAll()
|
||||
return nil
|
||||
}
|
||||
|
||||
// func (s *Service) DownloadAndWait(ctx context.Context, task *TorrentDownloadTask) error {
|
||||
// t, ok := s.c.Torrent(task.InfoHash)
|
||||
// if !ok {
|
||||
// return fmt.Errorf("torrent with IH %s not found", task.InfoHash.HexString())
|
||||
// }
|
||||
|
||||
// if task.File != "" {
|
||||
// var file *torrent.File
|
||||
// for _, tf := range t.Files() {
|
||||
// if tf.Path() == task.File {
|
||||
// file = tf
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
|
||||
// if file == nil {
|
||||
// return fmt.Errorf("file %s not found in torrent torrent with IH %s", task.File, task.InfoHash.HexString())
|
||||
// }
|
||||
|
||||
// file.Download()
|
||||
// return waitPieceRange(ctx, t, file.BeginPieceIndex(), file.EndPieceIndex())
|
||||
|
||||
// }
|
||||
|
||||
// t.DownloadAll()
|
||||
// select {
|
||||
// case <-ctx.Done():
|
||||
// return ctx.Err()
|
||||
// case <-t.Complete.On():
|
||||
// return nil
|
||||
// }
|
||||
// }
|
||||
|
||||
// func waitPieceRange(ctx context.Context, t *torrent.Torrent, start, end int) error {
|
||||
// for i := start; i < end; i++ {
|
||||
// timer := time.NewTimer(time.Millisecond)
|
||||
// for {
|
||||
// select {
|
||||
// case <-ctx.Done():
|
||||
// return ctx.Err()
|
||||
// case <-timer.C:
|
||||
// if t.PieceState(i).Complete {
|
||||
// continue
|
||||
// }
|
||||
// }
|
||||
|
||||
// }
|
||||
// }
|
||||
// return nil
|
||||
// }
|
||||
|
||||
type TorrentProgress struct {
|
||||
Torrent *controller.Torrent
|
||||
Current int64
|
||||
Total int64
|
||||
}
|
||||
|
||||
func (s *Service) DownloadProgress(ctx context.Context) (<-chan TorrentProgress, error) {
|
||||
torrents, err := s.ListTorrents(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out := make(chan TorrentProgress, 1)
|
||||
go func() {
|
||||
defer close(out)
|
||||
for _, t := range torrents {
|
||||
sub := t.Torrent().SubscribePieceStateChanges()
|
||||
go func() {
|
||||
for range sub.Values {
|
||||
out <- TorrentProgress{
|
||||
Torrent: t,
|
||||
Current: t.BytesCompleted(),
|
||||
Total: t.Length(),
|
||||
}
|
||||
}
|
||||
}()
|
||||
defer sub.Close()
|
||||
}
|
||||
|
||||
<-ctx.Done()
|
||||
}()
|
||||
|
||||
return out, nil
|
||||
}
|
|
@ -11,9 +11,10 @@ import (
|
|||
"time"
|
||||
|
||||
"git.kmsign.ru/royalcat/tstor/src/host/controller"
|
||||
"git.kmsign.ru/royalcat/tstor/src/host/filestorage"
|
||||
"git.kmsign.ru/royalcat/tstor/src/host/datastorage"
|
||||
"git.kmsign.ru/royalcat/tstor/src/host/store"
|
||||
"git.kmsign.ru/royalcat/tstor/src/host/vfs"
|
||||
"go.uber.org/multierr"
|
||||
|
||||
"github.com/anacrolix/torrent"
|
||||
"github.com/anacrolix/torrent/bencode"
|
||||
|
@ -24,21 +25,21 @@ import (
|
|||
|
||||
type Service struct {
|
||||
c *torrent.Client
|
||||
excludedFiles *store.ExlcudedFiles
|
||||
excludedFiles *store.FilesMappings
|
||||
infoBytes *store.InfoBytes
|
||||
|
||||
torrentLoaded chan struct{}
|
||||
|
||||
// stats *Stats
|
||||
DefaultPriority types.PiecePriority
|
||||
Storage *filestorage.FileStorage
|
||||
Storage datastorage.DataStorage
|
||||
SourceDir string
|
||||
|
||||
log *slog.Logger
|
||||
addTimeout, readTimeout int
|
||||
}
|
||||
|
||||
func NewService(sourceDir string, c *torrent.Client, storage *filestorage.FileStorage, excludedFiles *store.ExlcudedFiles, infoBytes *store.InfoBytes, addTimeout, readTimeout int) *Service {
|
||||
func NewService(sourceDir string, c *torrent.Client, storage datastorage.DataStorage, excludedFiles *store.FilesMappings, infoBytes *store.InfoBytes, addTimeout, readTimeout int) *Service {
|
||||
s := &Service{
|
||||
log: slog.With("component", "torrent-service"),
|
||||
c: c,
|
||||
|
@ -66,6 +67,12 @@ func NewService(sourceDir string, c *torrent.Client, storage *filestorage.FileSt
|
|||
|
||||
var _ vfs.FsFactory = (*Service)(nil).NewTorrentFs
|
||||
|
||||
func (s *Service) Close() error {
|
||||
err := multierr.Combine(s.c.Close()...)
|
||||
err = multierr.Append(err, s.Storage.Close())
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Service) AddTorrent(ctx context.Context, f vfs.File) (*torrent.Torrent, error) {
|
||||
defer f.Close()
|
||||
|
||||
|
@ -102,17 +109,17 @@ func (s *Service) AddTorrent(ctx context.Context, f vfs.File) (*torrent.Torrent,
|
|||
if err != nil {
|
||||
infoBytes = nil
|
||||
} else {
|
||||
for _, t := range s.c.Torrents() {
|
||||
if t.Name() == info.BestName() && t.InfoHash() != spec.InfoHash {
|
||||
<-t.GotInfo()
|
||||
if !isTorrentCompatable(*t.Info(), info) {
|
||||
return nil, fmt.Errorf(
|
||||
"torrent with name '%s' not compatable existing infohash: %s, new: %s",
|
||||
t.Name(), t.InfoHash().HexString(), spec.InfoHash.HexString(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
// for _, t := range s.c.Torrents() {
|
||||
// if t.Name() == info.BestName() && t.InfoHash() != spec.InfoHash {
|
||||
// <-t.GotInfo()
|
||||
// if !isTorrentCompatable(*t.Info(), info) {
|
||||
// return nil, fmt.Errorf(
|
||||
// "torrent with name '%s' not compatable existing infohash: %s, new: %s",
|
||||
// t.Name(), t.InfoHash().HexString(), spec.InfoHash.HexString(),
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
t, _ = s.c.AddTorrentOpt(torrent.AddTorrentOpts{
|
||||
|
@ -123,7 +130,6 @@ func (s *Service) AddTorrent(ctx context.Context, f vfs.File) (*torrent.Torrent,
|
|||
})
|
||||
t.AllowDataDownload()
|
||||
t.AllowDataUpload()
|
||||
t.DownloadAll()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
|
|
|
@ -1,94 +0,0 @@
|
|||
package store
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"github.com/anacrolix/torrent"
|
||||
"github.com/anacrolix/torrent/metainfo"
|
||||
"github.com/philippgille/gokv"
|
||||
"github.com/philippgille/gokv/badgerdb"
|
||||
"github.com/philippgille/gokv/encoding"
|
||||
)
|
||||
|
||||
func NewExcludedFiles(metaDir string, storage TorrentFileDeleter) (*ExlcudedFiles, error) {
|
||||
excludedFilesStore, err := badgerdb.NewStore(badgerdb.Options{
|
||||
Dir: filepath.Join(metaDir, "excluded-files"),
|
||||
Codec: encoding.JSON,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r := &ExlcudedFiles{
|
||||
excludedFiles: excludedFilesStore,
|
||||
storage: storage,
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
type ExlcudedFiles struct {
|
||||
m sync.RWMutex
|
||||
excludedFiles gokv.Store
|
||||
storage TorrentFileDeleter
|
||||
}
|
||||
|
||||
var ErrNotFound = errors.New("not found")
|
||||
|
||||
type TorrentFileDeleter interface {
|
||||
DeleteFile(file *torrent.File) error
|
||||
}
|
||||
|
||||
func (r *ExlcudedFiles) ExcludeFile(file *torrent.File) error {
|
||||
r.m.Lock()
|
||||
defer r.m.Unlock()
|
||||
|
||||
hash := file.Torrent().InfoHash()
|
||||
var excludedFiles []string
|
||||
found, err := r.excludedFiles.Get(hash.AsString(), &excludedFiles)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !found {
|
||||
excludedFiles = []string{}
|
||||
}
|
||||
excludedFiles = unique(append(excludedFiles, file.Path()))
|
||||
|
||||
err = r.storage.DeleteFile(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return r.excludedFiles.Set(hash.AsString(), excludedFiles)
|
||||
}
|
||||
|
||||
func (r *ExlcudedFiles) ExcludedFiles(hash metainfo.Hash) ([]string, error) {
|
||||
r.m.Lock()
|
||||
defer r.m.Unlock()
|
||||
|
||||
var excludedFiles []string
|
||||
found, err := r.excludedFiles.Get(hash.AsString(), &excludedFiles)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !found {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return excludedFiles, nil
|
||||
}
|
||||
|
||||
func unique[C comparable](intSlice []C) []C {
|
||||
keys := make(map[C]bool)
|
||||
list := []C{}
|
||||
for _, entry := range intSlice {
|
||||
if _, value := keys[entry]; !value {
|
||||
keys[entry] = true
|
||||
list = append(list, entry)
|
||||
}
|
||||
}
|
||||
return list
|
||||
}
|
57
src/host/store/file-mappings.go
Normal file
57
src/host/store/file-mappings.go
Normal file
|
@ -0,0 +1,57 @@
|
|||
package store
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/anacrolix/torrent"
|
||||
"github.com/anacrolix/torrent/types/infohash"
|
||||
"github.com/royalcat/kv"
|
||||
)
|
||||
|
||||
func NewFileMappings(metaDir string, storage TorrentFileDeleter) (*FilesMappings, error) {
|
||||
str, err := kv.NewBadgerKVBytes[string, string](filepath.Join(metaDir, "file-mappings"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r := &FilesMappings{
|
||||
mappings: str,
|
||||
storage: storage,
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
type FilesMappings struct {
|
||||
mappings kv.Store[string, string]
|
||||
storage TorrentFileDeleter
|
||||
}
|
||||
|
||||
var ErrNotFound = errors.New("not found")
|
||||
|
||||
type TorrentFileDeleter interface {
|
||||
DeleteFile(file *torrent.File) error
|
||||
}
|
||||
|
||||
func fileKey(file *torrent.File) string {
|
||||
return file.Torrent().InfoHash().HexString() + "/" + file.Path()
|
||||
}
|
||||
|
||||
func (r *FilesMappings) MapFile(ctx context.Context, file *torrent.File, target string) error {
|
||||
return r.mappings.Set(ctx, fileKey(file), target)
|
||||
}
|
||||
|
||||
func (r *FilesMappings) ExcludeFile(ctx context.Context, file *torrent.File) error {
|
||||
return r.mappings.Set(ctx, fileKey(file), "")
|
||||
}
|
||||
|
||||
func (r *FilesMappings) FileMappings(ctx context.Context, ih infohash.T) (map[string]string, error) {
|
||||
out := map[string]string{}
|
||||
err := r.mappings.RangeWithPrefix(ctx, ih.HexString(), func(k, v string) bool {
|
||||
out[k] = v
|
||||
return true
|
||||
})
|
||||
return out, err
|
||||
}
|
|
@ -21,7 +21,7 @@ func TestFileinfo(t *testing.T) {
|
|||
require.Zero(fi.Type() & fs.ModeDir)
|
||||
require.Zero(fi.Mode() & fs.ModeDir)
|
||||
require.Equal(fs.FileMode(0555), fi.Mode())
|
||||
require.Equal(nil, fi.Sys())
|
||||
require.Nil(fi.Sys())
|
||||
}
|
||||
|
||||
func TestDirInfo(t *testing.T) {
|
||||
|
@ -38,6 +38,6 @@ func TestDirInfo(t *testing.T) {
|
|||
require.NotZero(fi.Type() & fs.ModeDir)
|
||||
require.NotZero(fi.Mode() & fs.ModeDir)
|
||||
require.Equal(defaultMode|fs.ModeDir, fi.Mode())
|
||||
require.Equal(nil, fi.Sys())
|
||||
require.Nil(fi.Sys())
|
||||
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
|
||||
"git.kmsign.ru/royalcat/tstor/src/host/controller"
|
||||
"git.kmsign.ru/royalcat/tstor/src/iio"
|
||||
"github.com/RoaringBitmap/roaring"
|
||||
"github.com/anacrolix/missinggo/v2"
|
||||
"github.com/anacrolix/torrent"
|
||||
"golang.org/x/exp/maps"
|
||||
|
@ -46,17 +47,14 @@ func (fs *TorrentFs) files() (map[string]File, error) {
|
|||
return fs.filesCache, nil
|
||||
}
|
||||
|
||||
files, err := fs.c.Files()
|
||||
files, err := fs.c.Files(context.Background())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fs.filesCache = make(map[string]File)
|
||||
for _, file := range files {
|
||||
if file.BytesCompleted() == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
file.Download()
|
||||
p := AbsPath(file.Path())
|
||||
|
||||
fs.filesCache[p] = &torrentFile{
|
||||
|
@ -107,6 +105,24 @@ DEFAULT_DIR:
|
|||
return fs.filesCache, nil
|
||||
}
|
||||
|
||||
func anyPeerHasFiles(file *torrent.File) bool {
|
||||
for _, conn := range file.Torrent().PeerConns() {
|
||||
if bitmapHaveFile(conn.PeerPieces(), file) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func bitmapHaveFile(bitmap *roaring.Bitmap, file *torrent.File) bool {
|
||||
for i := file.BeginPieceIndex(); i < file.EndPieceIndex(); i++ {
|
||||
if !bitmap.ContainsInt(i) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func listFilesRecursive(vfs Filesystem, start string) (map[string]File, error) {
|
||||
out := make(map[string]File, 0)
|
||||
entries, err := vfs.ReadDir(start)
|
||||
|
@ -222,7 +238,7 @@ func (fs *TorrentFs) Unlink(name string) error {
|
|||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
return fs.c.ExcludeFile(tfile.file)
|
||||
return fs.c.ExcludeFile(context.Background(), tfile.file)
|
||||
}
|
||||
|
||||
type reader interface {
|
||||
|
|
21
src/host/vfs/virtdir/vds.go
Normal file
21
src/host/vfs/virtdir/vds.go
Normal file
|
@ -0,0 +1,21 @@
|
|||
package virtdir
|
||||
|
||||
type SourceType string
|
||||
|
||||
const (
|
||||
VirtDirYtDlp SourceType = "yt-dlp"
|
||||
)
|
||||
|
||||
type VirtDirSource interface {
|
||||
SourceType() SourceType
|
||||
}
|
||||
|
||||
var _ VirtDirSource = (*VirtDirSourceYtDlp)(nil)
|
||||
|
||||
type VirtDirSourceYtDlp struct {
|
||||
URL string `json:"url"`
|
||||
}
|
||||
|
||||
func (VirtDirSourceYtDlp) SourceType() SourceType {
|
||||
return VirtDirYtDlp
|
||||
}
|
138
src/log/nfs.go
138
src/log/nfs.go
|
@ -11,13 +11,14 @@ import (
|
|||
var _ nfs.Logger = (*NFSLog)(nil)
|
||||
|
||||
type NFSLog struct {
|
||||
level nfs.LogLevel
|
||||
// r *slog.Logger
|
||||
l *slog.Logger
|
||||
}
|
||||
|
||||
func NewNFSLog(r *slog.Logger) nfs.Logger {
|
||||
return &NFSLog{
|
||||
// r: r,
|
||||
level: nfs.DebugLevel,
|
||||
// l: r.Level(zerolog.DebugLevel),
|
||||
l: r,
|
||||
}
|
||||
|
@ -25,43 +26,75 @@ func NewNFSLog(r *slog.Logger) nfs.Logger {
|
|||
|
||||
// Debug implements nfs.Logger.
|
||||
func (l *NFSLog) Debug(args ...interface{}) {
|
||||
if l.level < nfs.DebugLevel {
|
||||
return
|
||||
}
|
||||
|
||||
l.l.Debug(fmt.Sprint(args...))
|
||||
}
|
||||
|
||||
// Debugf implements nfs.Logger.
|
||||
func (l *NFSLog) Debugf(format string, args ...interface{}) {
|
||||
if l.level < nfs.DebugLevel {
|
||||
return
|
||||
}
|
||||
|
||||
l.l.Debug(fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
// Error implements nfs.Logger.
|
||||
func (l *NFSLog) Error(args ...interface{}) {
|
||||
if l.level < nfs.ErrorLevel {
|
||||
return
|
||||
}
|
||||
|
||||
l.l.Error(fmt.Sprint(args...))
|
||||
}
|
||||
|
||||
// Errorf implements nfs.Logger.
|
||||
func (l *NFSLog) Errorf(format string, args ...interface{}) {
|
||||
if l.level < nfs.ErrorLevel {
|
||||
return
|
||||
}
|
||||
|
||||
l.l.Error(fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
// Fatal implements nfs.Logger.
|
||||
func (l *NFSLog) Fatal(args ...interface{}) {
|
||||
if l.level < nfs.FatalLevel {
|
||||
return
|
||||
}
|
||||
|
||||
l.l.Error(fmt.Sprint(args...))
|
||||
log.Fatal(args...)
|
||||
}
|
||||
|
||||
// Fatalf implements nfs.Logger.
|
||||
func (l *NFSLog) Fatalf(format string, args ...interface{}) {
|
||||
if l.level < nfs.FatalLevel {
|
||||
return
|
||||
}
|
||||
|
||||
l.l.Error(fmt.Sprintf(format, args...))
|
||||
log.Fatalf(format, args...)
|
||||
}
|
||||
|
||||
// Info implements nfs.Logger.
|
||||
func (l *NFSLog) Info(args ...interface{}) {
|
||||
if l.level < nfs.InfoLevel {
|
||||
return
|
||||
}
|
||||
|
||||
l.l.Info(fmt.Sprint(args...))
|
||||
}
|
||||
|
||||
// Infof implements nfs.Logger.
|
||||
func (l *NFSLog) Infof(format string, args ...interface{}) {
|
||||
if l.level < nfs.InfoLevel {
|
||||
return
|
||||
}
|
||||
|
||||
l.l.Info(fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
|
@ -79,102 +112,85 @@ func (l *NFSLog) Panicf(format string, args ...interface{}) {
|
|||
|
||||
// Print implements nfs.Logger.
|
||||
func (l *NFSLog) Print(args ...interface{}) {
|
||||
if l.level < nfs.InfoLevel {
|
||||
return
|
||||
}
|
||||
|
||||
l.l.Info(fmt.Sprint(args...))
|
||||
}
|
||||
|
||||
// Printf implements nfs.Logger.
|
||||
func (l *NFSLog) Printf(format string, args ...interface{}) {
|
||||
if l.level < nfs.InfoLevel {
|
||||
return
|
||||
}
|
||||
|
||||
l.l.Info(fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
// Trace implements nfs.Logger.
|
||||
func (l *NFSLog) Trace(args ...interface{}) {
|
||||
if l.level < nfs.TraceLevel {
|
||||
return
|
||||
}
|
||||
|
||||
l.l.Debug(fmt.Sprint(args...))
|
||||
}
|
||||
|
||||
// Tracef implements nfs.Logger.
|
||||
func (l *NFSLog) Tracef(format string, args ...interface{}) {
|
||||
if l.level < nfs.TraceLevel {
|
||||
return
|
||||
}
|
||||
|
||||
l.l.Debug(fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
// Warn implements nfs.Logger.
|
||||
func (l *NFSLog) Warn(args ...interface{}) {
|
||||
if l.level < nfs.WarnLevel {
|
||||
return
|
||||
}
|
||||
|
||||
l.l.Warn(fmt.Sprint(args...))
|
||||
}
|
||||
|
||||
// Warnf implements nfs.Logger.
|
||||
func (l *NFSLog) Warnf(format string, args ...interface{}) {
|
||||
if l.level < nfs.WarnLevel {
|
||||
return
|
||||
}
|
||||
|
||||
l.l.Warn(fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
// GetLevel implements nfs.Logger.
|
||||
func (l *NFSLog) GetLevel() nfs.LogLevel {
|
||||
// zl := l.l.Handler()
|
||||
// switch zl {
|
||||
// case zerolog.PanicLevel, zerolog.Disabled:
|
||||
// return nfs.PanicLevel
|
||||
// case zerolog.FatalLevel:
|
||||
// return nfs.FatalLevel
|
||||
// case zerolog.ErrorLevel:
|
||||
// return nfs.ErrorLevel
|
||||
// case zerolog.WarnLevel:
|
||||
// return nfs.WarnLevel
|
||||
// case zerolog.InfoLevel:
|
||||
// return nfs.InfoLevel
|
||||
// case zerolog.DebugLevel:
|
||||
// return nfs.DebugLevel
|
||||
// case zerolog.TraceLevel:
|
||||
// return nfs.TraceLevel
|
||||
// }
|
||||
return nfs.TraceLevel
|
||||
return l.level
|
||||
}
|
||||
|
||||
// ParseLevel implements nfs.Logger.
|
||||
func (l *NFSLog) ParseLevel(level string) (nfs.LogLevel, error) {
|
||||
// switch level {
|
||||
// case "panic":
|
||||
// return nfs.PanicLevel, nil
|
||||
// case "fatal":
|
||||
// return nfs.FatalLevel, nil
|
||||
// case "error":
|
||||
// return nfs.ErrorLevel, nil
|
||||
// case "warn":
|
||||
// return nfs.WarnLevel, nil
|
||||
// case "info":
|
||||
// return nfs.InfoLevel, nil
|
||||
// case "debug":
|
||||
// return nfs.DebugLevel, nil
|
||||
// case "trace":
|
||||
// return nfs.TraceLevel, nil
|
||||
// }
|
||||
// var ll nfs.LogLevel
|
||||
// return ll, fmt.Errorf("invalid log level %q", level)
|
||||
return nfs.TraceLevel, fmt.Errorf("level change not supported")
|
||||
switch level {
|
||||
case "panic":
|
||||
return nfs.PanicLevel, nil
|
||||
case "fatal":
|
||||
return nfs.FatalLevel, nil
|
||||
case "error":
|
||||
return nfs.ErrorLevel, nil
|
||||
case "warn":
|
||||
return nfs.WarnLevel, nil
|
||||
case "info":
|
||||
return nfs.InfoLevel, nil
|
||||
case "debug":
|
||||
return nfs.DebugLevel, nil
|
||||
case "trace":
|
||||
return nfs.TraceLevel, nil
|
||||
}
|
||||
return 0, fmt.Errorf("invalid log level %q", level)
|
||||
}
|
||||
|
||||
// SetLevel implements nfs.Logger.
|
||||
func (l *NFSLog) SetLevel(level nfs.LogLevel) {
|
||||
// switch level {
|
||||
// case nfs.PanicLevel:
|
||||
// l.l = l.r.Level(zerolog.PanicLevel)
|
||||
// return
|
||||
// case nfs.FatalLevel:
|
||||
// l.l = l.r.Level(zerolog.FatalLevel)
|
||||
// return
|
||||
// case nfs.ErrorLevel:
|
||||
// l.l = l.r.Level(zerolog.ErrorLevel)
|
||||
// return
|
||||
// case nfs.WarnLevel:
|
||||
// l.l = l.r.Level(zerolog.WarnLevel)
|
||||
// return
|
||||
// case nfs.InfoLevel:
|
||||
// l.l = l.r.Level(zerolog.InfoLevel)
|
||||
// return
|
||||
// case nfs.DebugLevel:
|
||||
// l.l = l.r.Level(zerolog.DebugLevel)
|
||||
// return
|
||||
// case nfs.TraceLevel:
|
||||
// l.l = l.r.Level(zerolog.TraceLevel)
|
||||
// return
|
||||
// }
|
||||
l.level = level
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue