Migrate to full rclone rcd
This commit is contained in:
@@ -41,8 +41,8 @@ LABEL org.opencontainers.image.title = "decypharr"
|
|||||||
LABEL org.opencontainers.image.authors = "sirrobot01"
|
LABEL org.opencontainers.image.authors = "sirrobot01"
|
||||||
LABEL org.opencontainers.image.documentation = "https://github.com/sirrobot01/decypharr/blob/main/README.md"
|
LABEL org.opencontainers.image.documentation = "https://github.com/sirrobot01/decypharr/blob/main/README.md"
|
||||||
|
|
||||||
# Install dependencies
|
# Install dependencies including rclone
|
||||||
RUN apk add --no-cache fuse3 ca-certificates su-exec shadow && \
|
RUN apk add --no-cache fuse3 ca-certificates su-exec shadow rclone && \
|
||||||
echo "user_allow_other" >> /etc/fuse.conf
|
echo "user_allow_other" >> /etc/fuse.conf
|
||||||
|
|
||||||
# Copy binaries and entrypoint
|
# Copy binaries and entrypoint
|
||||||
|
|||||||
@@ -148,6 +148,15 @@ func startServices(ctx context.Context, cancelSvc context.CancelFunc, wd *webdav
|
|||||||
return srv.Start(ctx)
|
return srv.Start(ctx)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Start rclone RC server if enabled
|
||||||
|
safeGo(func() error {
|
||||||
|
rcManager := store.Get().RcloneManager()
|
||||||
|
if rcManager == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return rcManager.Start(ctx)
|
||||||
|
})
|
||||||
|
|
||||||
safeGo(func() error {
|
safeGo(func() error {
|
||||||
arr := store.Get().Arr()
|
arr := store.Get().Arr()
|
||||||
if arr == nil {
|
if arr == nil {
|
||||||
|
|||||||
49
go.mod
49
go.mod
@@ -11,7 +11,6 @@ require (
|
|||||||
github.com/go-co-op/gocron/v2 v2.16.1
|
github.com/go-co-op/gocron/v2 v2.16.1
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/gorilla/sessions v1.4.0
|
github.com/gorilla/sessions v1.4.0
|
||||||
github.com/rclone/rclone v1.70.3
|
|
||||||
github.com/robfig/cron/v3 v3.0.1
|
github.com/robfig/cron/v3 v3.0.1
|
||||||
github.com/rs/zerolog v1.33.0
|
github.com/rs/zerolog v1.33.0
|
||||||
github.com/stanNthe5/stringbuf v0.0.3
|
github.com/stanNthe5/stringbuf v0.0.3
|
||||||
@@ -23,58 +22,18 @@ require (
|
|||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
bazil.org/fuse v0.0.0-20230120002735-62a210ff1fd5 // indirect
|
|
||||||
cloud.google.com/go/compute/metadata v0.7.0 // indirect
|
|
||||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
|
|
||||||
github.com/Max-Sum/base32768 v0.0.0-20230304063302-18e6ce5945fd // indirect
|
|
||||||
github.com/aalpar/deheap v0.0.0-20210914013432-0cc84d79dec3 // indirect
|
|
||||||
github.com/abbot/go-http-auth v0.4.0 // indirect
|
|
||||||
github.com/anacrolix/missinggo v1.3.0 // indirect
|
github.com/anacrolix/missinggo v1.3.0 // indirect
|
||||||
github.com/anacrolix/missinggo/v2 v2.7.3 // indirect
|
github.com/anacrolix/missinggo/v2 v2.7.3 // indirect
|
||||||
github.com/benbjohnson/clock v1.3.0 // indirect
|
github.com/benbjohnson/clock v1.3.0 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
|
||||||
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 // indirect
|
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||||
github.com/coreos/go-semver v0.3.1 // indirect
|
github.com/google/go-cmp v0.7.0 // indirect
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
|
||||||
github.com/ebitengine/purego v0.8.4 // indirect
|
|
||||||
github.com/go-darwin/apfs v0.0.0-20211011131704-f84b94dbf348 // indirect
|
|
||||||
github.com/go-git/go-billy/v5 v5.6.2 // indirect
|
|
||||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
|
||||||
github.com/gorilla/securecookie v1.1.2 // indirect
|
github.com/gorilla/securecookie v1.1.2 // indirect
|
||||||
github.com/hanwen/go-fuse/v2 v2.7.2 // indirect
|
|
||||||
github.com/huandu/xstrings v1.3.2 // indirect
|
github.com/huandu/xstrings v1.3.2 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
|
||||||
github.com/jonboulle/clockwork v0.5.0 // indirect
|
github.com/jonboulle/clockwork v0.5.0 // indirect
|
||||||
github.com/jzelinskie/whirlpool v0.0.0-20201016144138-0675e54bb004 // indirect
|
|
||||||
github.com/lanrat/extsort v1.0.2 // indirect
|
|
||||||
github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 // indirect
|
|
||||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||||
github.com/moby/sys/mountinfo v0.7.2 // indirect
|
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
|
||||||
github.com/pkg/xattr v0.4.10 // indirect
|
|
||||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
|
||||||
github.com/prometheus/client_golang v1.22.0 // indirect
|
|
||||||
github.com/prometheus/client_model v0.6.2 // indirect
|
|
||||||
github.com/prometheus/common v0.64.0 // indirect
|
|
||||||
github.com/prometheus/procfs v0.16.1 // indirect
|
|
||||||
github.com/rfjakob/eme v1.1.2 // indirect
|
|
||||||
github.com/shirou/gopsutil/v4 v4.25.5 // indirect
|
|
||||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect
|
|
||||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a // indirect
|
|
||||||
github.com/spf13/cobra v1.9.1 // indirect
|
|
||||||
github.com/spf13/pflag v1.0.6 // indirect
|
|
||||||
github.com/tklauser/go-sysconf v0.3.15 // indirect
|
|
||||||
github.com/tklauser/numcpus v0.10.0 // indirect
|
|
||||||
github.com/unknwon/goconfig v1.0.0 // indirect
|
|
||||||
github.com/winfsp/cgofuse v1.6.0 // indirect
|
|
||||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
|
||||||
golang.org/x/sys v0.33.0 // indirect
|
golang.org/x/sys v0.33.0 // indirect
|
||||||
golang.org/x/term v0.32.0 // indirect
|
|
||||||
golang.org/x/text v0.26.0 // indirect
|
|
||||||
golang.org/x/time v0.12.0 // indirect
|
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect
|
|
||||||
google.golang.org/protobuf v1.36.6 // indirect
|
|
||||||
)
|
)
|
||||||
|
|||||||
386
go.sum
386
go.sum
@@ -1,62 +1,13 @@
|
|||||||
bazil.org/fuse v0.0.0-20230120002735-62a210ff1fd5 h1:A0NsYy4lDBZAC6QiYeJ4N+XuHIKBpyhAVRMHRQZKTeQ=
|
|
||||||
bazil.org/fuse v0.0.0-20230120002735-62a210ff1fd5/go.mod h1:gG3RZAMXCa/OTes6rr9EwusmR1OH1tDDy+cg9c5YliY=
|
|
||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
cloud.google.com/go v0.34.0 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg=
|
|
||||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
cloud.google.com/go/auth v0.16.2 h1:QvBAGFPLrDeoiNjyfVunhQ10HKNYuOwZ5noee0M5df4=
|
|
||||||
cloud.google.com/go/auth v0.16.2/go.mod h1:sRBas2Y1fB1vZTdurouM0AzuYQBMZinrUYL8EufhtEA=
|
|
||||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
|
|
||||||
cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
|
|
||||||
cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU=
|
|
||||||
cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo=
|
|
||||||
crawshaw.io/iox v0.0.0-20181124134642-c51c3df30797/go.mod h1:sXBiorCo8c46JlQV3oXPKINnZ8mcqnye1EkVkqsectk=
|
crawshaw.io/iox v0.0.0-20181124134642-c51c3df30797/go.mod h1:sXBiorCo8c46JlQV3oXPKINnZ8mcqnye1EkVkqsectk=
|
||||||
crawshaw.io/sqlite v0.3.2/go.mod h1:igAO5JulrQ1DbdZdtVq48mnZUBAPOeFzer7VhDWNtW4=
|
crawshaw.io/sqlite v0.3.2/go.mod h1:igAO5JulrQ1DbdZdtVq48mnZUBAPOeFzer7VhDWNtW4=
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 h1:Gt0j3wceWMwPmiazCa8MzMA0MfhmPIz0Qp0FJ6qcM0U=
|
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0/go.mod h1:Ot/6aikWnKWi4l9QB7qVSwa8iMphQNqkWALMoNT3rzM=
|
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.0 h1:j8BorDEigD8UFOSZQiSqAMOOleyQOOQPnUAwV+Ls1gA=
|
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.0/go.mod h1:JdM5psgjfBf5fo2uWOZhflPWyDBZ/O/CNAH9CtsuZE4=
|
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 h1:FPKJS1T+clwv+OLGt13a8UjqeRuh0O4SJ3lUriThc+4=
|
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1/go.mod h1:j2chePtV91HrC22tGoRX3sGY42uF13WzmmV80/OdVAA=
|
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.1 h1:lhZdRq7TIx0GJQvSyX2Si406vrYsov2FXGp/RnSEtcs=
|
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.1/go.mod h1:8cl44BDmi+effbARHMQjgOKA2AYvcohNm7KEt42mSV8=
|
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azfile v1.5.1 h1:iXgRWOnlPG3AZwBYInDOOJ3PVe3mrL2EPkCY4KfGxKw=
|
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azfile v1.5.1/go.mod h1:WtRlkDNMdVDrsTyLXNHkVrzkvfbdZXgoCu4PZbq9rgg=
|
|
||||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8=
|
|
||||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
|
|
||||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 h1:oygO0locgZJe7PpYPXT5A29ZkwJaPqcva7BVeemZOZs=
|
|
||||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
|
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/Files-com/files-sdk-go/v3 v3.2.173 h1:OPDjpkEWXO+WSGX1qQ10Y51do178i9z4DdFpI25B+iY=
|
|
||||||
github.com/Files-com/files-sdk-go/v3 v3.2.173/go.mod h1:HnPrW1lljxOjdkR5Wm6DjtdHwWdcm/afts2N6O+iiJo=
|
|
||||||
github.com/IBM/go-sdk-core/v5 v5.20.0 h1:rG1fn5GmJfFzVtpDKndsk6MgcarluG8YIWf89rVqLP8=
|
|
||||||
github.com/IBM/go-sdk-core/v5 v5.20.0/go.mod h1:Q3BYO6iDA2zweQPDGbNTtqft5tDcEpm6RTuqMlPcvbw=
|
|
||||||
github.com/Max-Sum/base32768 v0.0.0-20230304063302-18e6ce5945fd h1:nzE1YQBdx1bq9IlZinHa+HVffy+NmVRoKr+wHN8fpLE=
|
|
||||||
github.com/Max-Sum/base32768 v0.0.0-20230304063302-18e6ce5945fd/go.mod h1:C8yoIfvESpM3GD07OCHU7fqI7lhwyZ2Td1rbNbTAhnc=
|
|
||||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
|
||||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
|
||||||
github.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf h1:yc9daCCYUefEs69zUkSzubzjBbL+cmOXgnmt9Fyd9ug=
|
|
||||||
github.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf/go.mod h1:o0ESU9p83twszAU8LBeJKFAAMX14tISa0yk4Oo5TOqo=
|
|
||||||
github.com/ProtonMail/gluon v0.17.1-0.20230724134000-308be39be96e h1:lCsqUUACrcMC83lg5rTo9Y0PnPItE61JSfvMyIcANwk=
|
|
||||||
github.com/ProtonMail/gluon v0.17.1-0.20230724134000-308be39be96e/go.mod h1:Og5/Dz1MiGpCJn51XujZwxiLG7WzvvjE5PRpZBQmAHo=
|
|
||||||
github.com/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw=
|
|
||||||
github.com/ProtonMail/go-crypto v1.3.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE=
|
|
||||||
github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f h1:tCbYj7/299ekTTXpdwKYF8eBlsYsDVoggDAuAjoK66k=
|
|
||||||
github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f/go.mod h1:gcr0kNtGBqin9zDW9GOHcVntrwnjrK+qdJ06mWYBybw=
|
|
||||||
github.com/ProtonMail/go-srp v0.0.7 h1:Sos3Qk+th4tQR64vsxGIxYpN3rdnG9Wf9K4ZloC1JrI=
|
|
||||||
github.com/ProtonMail/go-srp v0.0.7/go.mod h1:giCp+7qRnMIcCvI6V6U3S1lDDXDQYx2ewJ6F/9wdlJk=
|
|
||||||
github.com/ProtonMail/gopenpgp/v2 v2.9.0 h1:ruLzBmwe4dR1hdnrsEJ/S7psSBmV15gFttFUPP/+/kE=
|
|
||||||
github.com/ProtonMail/gopenpgp/v2 v2.9.0/go.mod h1:IldDyh9Hv1ZCCYatTuuEt1XZJ0OPjxLpTarDfglih7s=
|
|
||||||
github.com/PuerkitoBio/goquery v1.10.3 h1:pFYcNSqHxBD06Fpj/KsbStFRsgRATgnf3LeXiUkhzPo=
|
|
||||||
github.com/PuerkitoBio/goquery v1.10.3/go.mod h1:tMUX0zDMHXYlAQk6p35XxQMqMweEKB7iK7iLNd4RH4Y=
|
|
||||||
github.com/RoaringBitmap/roaring v0.4.7/go.mod h1:8khRDP4HmeXns4xIj9oGrKSz7XTQiJx2zgh7AcNke4w=
|
github.com/RoaringBitmap/roaring v0.4.7/go.mod h1:8khRDP4HmeXns4xIj9oGrKSz7XTQiJx2zgh7AcNke4w=
|
||||||
github.com/RoaringBitmap/roaring v0.4.17/go.mod h1:D3qVegWTmfCaX4Bl5CrBE9hfrSrrXIr8KVNvRsDi1NI=
|
github.com/RoaringBitmap/roaring v0.4.17/go.mod h1:D3qVegWTmfCaX4Bl5CrBE9hfrSrrXIr8KVNvRsDi1NI=
|
||||||
github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo=
|
github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo=
|
||||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||||
github.com/aalpar/deheap v0.0.0-20210914013432-0cc84d79dec3 h1:hhdWprfSpFbN7lz3W1gM40vOgvSh1WCSMxYD6gGB4Hs=
|
|
||||||
github.com/aalpar/deheap v0.0.0-20210914013432-0cc84d79dec3/go.mod h1:XaUnRxSCYgL3kkgX0QHIV0D+znljPIDImxlv2kbGv0Y=
|
|
||||||
github.com/abbot/go-http-auth v0.4.0 h1:QjmvZ5gSC7jm3Zg54DqWE/T5m1t2AfDu6QlXJT0EVT0=
|
|
||||||
github.com/abbot/go-http-auth v0.4.0/go.mod h1:Cz6ARTIzApMJDzh5bRMSUou6UMSp0IEXg9km/ci7TJM=
|
|
||||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
@@ -84,124 +35,35 @@ github.com/anacrolix/tagflag v1.0.0/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pm
|
|||||||
github.com/anacrolix/tagflag v1.1.0/go.mod h1:Scxs9CV10NQatSmbyjqmqmeQNwGzlNe0CMUMIxqHIG8=
|
github.com/anacrolix/tagflag v1.1.0/go.mod h1:Scxs9CV10NQatSmbyjqmqmeQNwGzlNe0CMUMIxqHIG8=
|
||||||
github.com/anacrolix/torrent v1.55.0 h1:s9yh/YGdPmbN9dTa+0Inh2dLdrLQRvEAj1jdFW/Hdd8=
|
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/torrent v1.55.0/go.mod h1:sBdZHBSZNj4de0m+EbYg7vvs/G/STubxu/GzzNbojsE=
|
||||||
github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM=
|
|
||||||
github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA=
|
|
||||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||||
github.com/appscode/go-querystring v0.0.0-20170504095604-0126cfb3f1dc h1:LoL75er+LKDHDUfU5tRvFwxH0LjPpZN8OoG8Ll+liGU=
|
|
||||||
github.com/appscode/go-querystring v0.0.0-20170504095604-0126cfb3f1dc/go.mod h1:w648aMHEgFYS6xb0KVMMtZ2uMeemhiKCuD2vj6gY52A=
|
|
||||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
|
|
||||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
|
||||||
github.com/aws/aws-sdk-go-v2 v1.36.3 h1:mJoei2CxPutQVxaATCzDUjcZEjVRdpsiiXi2o38yqWM=
|
|
||||||
github.com/aws/aws-sdk-go-v2 v1.36.3/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg=
|
|
||||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.10 h1:zAybnyUQXIZ5mok5Jqwlf58/TFE7uvd3IAsa1aF9cXs=
|
|
||||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.10/go.mod h1:qqvMj6gHLR/EXWZw4ZbqlPbQUyenf4h82UQUlKc+l14=
|
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.29.14 h1:f+eEi/2cKCg9pqKBoAIwRGzVb70MRKqWX4dg1BDcSJM=
|
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.29.14/go.mod h1:wVPHWcIFv3WO89w0rE10gzf17ZYy+UVS1Geq8Iei34g=
|
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.67 h1:9KxtdcIA/5xPNQyZRgUSpYOE6j9Bc4+D7nZua0KGYOM=
|
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.67/go.mod h1:p3C44m+cfnbv763s52gCqrjaqyPikj9Sg47kUVaNZQQ=
|
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 h1:x793wxmUWVDhshP8WW2mlnXuFrO4cOd3HLBroh1paFw=
|
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30/go.mod h1:Jpne2tDnYiFascUEs2AWHJL9Yp7A5ZVy3TNyxaAjD6M=
|
|
||||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.49 h1:7gss+6H2mrrFtBrkokJRR2TzQD9qkpGA4N6BvIP/pCM=
|
|
||||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.49/go.mod h1:30PBx0ENoUCJm2AxzgCue8j7KEjb9ci4enxy6CCOjbE=
|
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 h1:ZK5jHhnrioRkUNOc+hOgQKlUL5JeC3S6JgLxtQ+Rm0Q=
|
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34/go.mod h1:p4VfIceZokChbA9FzMbRGz5OV+lekcVtHlPKEO0gSZY=
|
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 h1:SZwFm17ZUNNg5Np0ioo/gq8Mn6u9w19Mri8DnJ15Jf0=
|
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34/go.mod h1:dFZsC0BLo346mvKQLWmoJxT+Sjp+qcVR1tRVHQGOH9Q=
|
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo=
|
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo=
|
|
||||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34 h1:ZNTqv4nIdE/DiBfUUfXcLZ/Spcuz+RjeziUtNJackkM=
|
|
||||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34/go.mod h1:zf7Vcd1ViW7cPqYWEHLHJkS50X0JS2IKz9Cgaj6ugrs=
|
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 h1:eAh2A4b5IzM/lum78bZ590jy36+d/aFLgKF/4Vd1xPE=
|
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3/go.mod h1:0yKJC/kb8sAnmlYa6Zs3QVYqaC8ug2AbnNChv5Ox3uA=
|
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.2 h1:BCG7DCXEXpNCcpwCxg1oi9pkJWH2+eZzTn9MY56MbVw=
|
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.2/go.mod h1:iu6FSzgt+M2/x3Dk8zhycdIcHjEFb36IS8HVUVFoMg0=
|
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 h1:dM9/92u2F1JbDaGooxTq18wmmFzbJRfXfVfy96/1CXM=
|
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15/go.mod h1:SwFBy2vjtA0vZbjjaFtfN045boopadnoVPhu4Fv66vY=
|
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15 h1:moLQUoVq91LiqT1nbvzDukyqAlCv89ZmwaHw/ZFlFZg=
|
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15/go.mod h1:ZH34PJUc8ApjBIfgQCFvkWcUDBtl/WTD+uiYHjd8igA=
|
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.72.3 h1:WZOmJfCDV+4tYacLxpiojoAdT5sxTfB3nTqQNtZu+J4=
|
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.72.3/go.mod h1:xMekrnhmJ5aqmyxtmALs7mlvXw5xRh+eYjOjvrIIFJ4=
|
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.3 h1:1Gw+9ajCV1jogloEv1RRnvfRFia2cL6c9cuKV2Ps+G8=
|
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.3/go.mod h1:qs4a9T5EMLl/Cajiw2TcbNt2UNo/Hqlyp+GiuG4CFDI=
|
|
||||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1 h1:hXmVKytPfTy5axZ+fYbR5d0cFmC3JvwLm5kM83luako=
|
|
||||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1/go.mod h1:MlYRNmYu/fGPoxBQVvBYr9nyr948aY/WLUvwBMBJubs=
|
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.19 h1:1XuUZ8mYJw9B6lzAkXhqHlJd/XvaX32evhproijJEZY=
|
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.19/go.mod h1:cQnB8CUnxbMU82JvlqjKR2HBOm3fe9pWorWBza6MBJ4=
|
|
||||||
github.com/aws/smithy-go v1.22.3 h1:Z//5NuZCSW6R4PhQ93hShNbyBbn8BWCmCVCt+Q8Io5k=
|
|
||||||
github.com/aws/smithy-go v1.22.3/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI=
|
|
||||||
github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
|
github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
|
||||||
github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||||
github.com/benbjohnson/immutable v0.2.0/go.mod h1:uc6OHo6PN2++n98KHLxW8ef4W42ylHiQSENghE1ezxI=
|
github.com/benbjohnson/immutable v0.2.0/go.mod h1:uc6OHo6PN2++n98KHLxW8ef4W42ylHiQSENghE1ezxI=
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
github.com/bradenaw/juniper v0.15.3 h1:RHIAMEDTpvmzV1wg1jMAHGOoI2oJUSPx3lxRldXnFGo=
|
|
||||||
github.com/bradenaw/juniper v0.15.3/go.mod h1:UX4FX57kVSaDp4TPqvSjkAAewmRFAfXf27BOs5z9dq8=
|
|
||||||
github.com/bradfitz/iter v0.0.0-20140124041915-454541ec3da2/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo=
|
github.com/bradfitz/iter v0.0.0-20140124041915-454541ec3da2/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo=
|
||||||
github.com/bradfitz/iter v0.0.0-20190303215204-33e6a9893b0c/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo=
|
github.com/bradfitz/iter v0.0.0-20190303215204-33e6a9893b0c/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo=
|
||||||
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 h1:GKTyiRCL6zVf5wWaqKnf+7Qs6GbEPfd4iMOitWzXJx8=
|
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 h1:GKTyiRCL6zVf5wWaqKnf+7Qs6GbEPfd4iMOitWzXJx8=
|
||||||
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8/go.mod h1:spo1JLcs67NmW1aVLEgtA8Yy1elc+X8y5SRW1sFW4Og=
|
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8/go.mod h1:spo1JLcs67NmW1aVLEgtA8Yy1elc+X8y5SRW1sFW4Og=
|
||||||
github.com/buengese/sgzip v0.1.1 h1:ry+T8l1mlmiWEsDrH/YHZnCVWD2S3im1KLsyO+8ZmTU=
|
|
||||||
github.com/buengese/sgzip v0.1.1/go.mod h1:i5ZiXGF3fhV7gL1xaRRL1nDnmpNj0X061FQzOS8VMas=
|
|
||||||
github.com/calebcase/tmpfile v1.0.3 h1:BZrOWZ79gJqQ3XbAQlihYZf/YCV0H4KPIdM5K5oMpJo=
|
|
||||||
github.com/calebcase/tmpfile v1.0.3/go.mod h1:UAUc01aHeC+pudPagY/lWvt2qS9ZO5Zzof6/tIUzqeI=
|
|
||||||
github.com/cavaliergopher/grab/v3 v3.0.1 h1:4z7TkBfmPjmLAAmkkAZNX/6QJ1nNFdv3SdIHXju0Fr4=
|
github.com/cavaliergopher/grab/v3 v3.0.1 h1:4z7TkBfmPjmLAAmkkAZNX/6QJ1nNFdv3SdIHXju0Fr4=
|
||||||
github.com/cavaliergopher/grab/v3 v3.0.1/go.mod h1:1U/KNnD+Ft6JJiYoYBAimKH2XrYptb8Kl3DFGmsjpq4=
|
github.com/cavaliergopher/grab/v3 v3.0.1/go.mod h1:1U/KNnD+Ft6JJiYoYBAimKH2XrYptb8Kl3DFGmsjpq4=
|
||||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
|
||||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
|
||||||
github.com/chilts/sid v0.0.0-20190607042430-660e94789ec9 h1:z0uK8UQqjMVYzvk4tiiu3obv2B44+XBsvgEJREQfnO8=
|
|
||||||
github.com/chilts/sid v0.0.0-20190607042430-660e94789ec9/go.mod h1:Jl2neWsQaDanWORdqZ4emBl50J4/aRBBS4FyyG9/PFo=
|
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
|
|
||||||
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
|
||||||
github.com/cloudinary/cloudinary-go/v2 v2.10.0 h1:Gi4p2KmmA6E9M7MI43PFw/hd4svnkHmR0ElfMcpLkHE=
|
|
||||||
github.com/cloudinary/cloudinary-go/v2 v2.10.0/go.mod h1:ireC4gqVetsjVhYlwjUJwKTbZuWjEIynbR9zQTlqsvo=
|
|
||||||
github.com/cloudsoda/go-smb2 v0.0.0-20250228001242-d4c70e6251cc h1:t8YjNUCt1DimB4HCIXBztwWMhgxr5yG5/YaRl9Afdfg=
|
|
||||||
github.com/cloudsoda/go-smb2 v0.0.0-20250228001242-d4c70e6251cc/go.mod h1:CgWpFCFWzzEA5hVkhAc6DZZzGd3czx+BblvOzjmg6KA=
|
|
||||||
github.com/cloudsoda/sddl v0.0.0-20250224235906-926454e91efc h1:0xCWmFKBmarCqqqLeM7jFBSw/Or81UEElFqO8MY+GDs=
|
|
||||||
github.com/cloudsoda/sddl v0.0.0-20250224235906-926454e91efc/go.mod h1:uvR42Hb/t52HQd7x5/ZLzZEK8oihrFpgnodIJ1vte2E=
|
|
||||||
github.com/colinmarc/hdfs/v2 v2.4.0 h1:v6R8oBx/Wu9fHpdPoJJjpGSUxo8NhHIwrwsfhFvU9W0=
|
|
||||||
github.com/colinmarc/hdfs/v2 v2.4.0/go.mod h1:0NAO+/3knbMx6+5pCv+Hcbaz4xn/Zzbn9+WIib2rKVI=
|
|
||||||
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
|
|
||||||
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
|
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
|
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
|
||||||
github.com/creasty/defaults v1.8.0 h1:z27FJxCAa0JKt3utc0sCImAEb+spPucmKoOdLHvHYKk=
|
|
||||||
github.com/creasty/defaults v1.8.0/go.mod h1:iGzKe6pbEHnpMPtfDXZEr0NVxWnPTjb1bbDy08fPzYM=
|
|
||||||
github.com/cronokirby/saferith v0.33.0 h1:TgoQlfsD4LIwx71+ChfRcIpjkw+RPOapDEVxa+LhwLo=
|
|
||||||
github.com/cronokirby/saferith v0.33.0/go.mod h1:QKJhjoqUtBsXCAVEjw38mFqoi7DebT7kthcD7UzbnoA=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
||||||
github.com/dropbox/dropbox-sdk-go-unofficial/v6 v6.0.5 h1:FT+t0UEDykcor4y3dMVKXIiWJETBpRgERYTGlmMd7HU=
|
|
||||||
github.com/dropbox/dropbox-sdk-go-unofficial/v6 v6.0.5/go.mod h1:rSS3kM9XMzSQ6pw91Qgd6yB5jdt70N4OdtrAf74As5M=
|
|
||||||
github.com/dustin/go-humanize v0.0.0-20180421182945-02af3965c54e/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
github.com/dustin/go-humanize v0.0.0-20180421182945-02af3965c54e/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||||
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
||||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
||||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||||
github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw=
|
|
||||||
github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
|
||||||
github.com/emersion/go-message v0.18.2 h1:rl55SQdjd9oJcIoQNhubD2Acs1E6IzlZISRTK7x/Lpg=
|
|
||||||
github.com/emersion/go-message v0.18.2/go.mod h1:XpJyL70LwRvq2a8rVbHXikPgKj8+aI0kGdHlg16ibYA=
|
|
||||||
github.com/emersion/go-vcard v0.0.0-20241024213814-c9703dde27ff h1:4N8wnS3f1hNHSmFD5zgFkWCyA4L1kCDkImPAtK7D6tg=
|
|
||||||
github.com/emersion/go-vcard v0.0.0-20241024213814-c9703dde27ff/go.mod h1:HMJKR5wlh/ziNp+sHEDV2ltblO4JD2+IdDOWtGcQBTM=
|
|
||||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
|
||||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
|
||||||
github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg=
|
|
||||||
github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag=
|
|
||||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY=
|
|
||||||
github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok=
|
|
||||||
github.com/geoffgarside/ber v1.2.0 h1:/loowoRcs/MWLYmGX9QtIAbA+V/FrnVLsMMPhwiRm64=
|
|
||||||
github.com/geoffgarside/ber v1.2.0/go.mod h1:jVPKeCbj6MvQZhwLYsGwaGI52oUorHoHKNecGT85ZCc=
|
|
||||||
github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
|
github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
|
||||||
github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
|
github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
|
||||||
github.com/glycerine/go-unsnap-stream v0.0.0-20190901134440-81cf024a9e0a/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
|
github.com/glycerine/go-unsnap-stream v0.0.0-20190901134440-81cf024a9e0a/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
|
||||||
@@ -212,45 +74,14 @@ github.com/go-chi/chi/v5 v5.2.2 h1:CMwsvRVTbXVytCk1Wd72Zy1LAsAh9GxMmSNWLHCG618=
|
|||||||
github.com/go-chi/chi/v5 v5.2.2/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
|
github.com/go-chi/chi/v5 v5.2.2/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
|
||||||
github.com/go-co-op/gocron/v2 v2.16.1 h1:ux/5zxVRveCaCuTtNI3DiOk581KC1KpJbpJFYUEVYwo=
|
github.com/go-co-op/gocron/v2 v2.16.1 h1:ux/5zxVRveCaCuTtNI3DiOk581KC1KpJbpJFYUEVYwo=
|
||||||
github.com/go-co-op/gocron/v2 v2.16.1/go.mod h1:opexeOFy5BplhsKdA7bzY9zeYih8I8/WNJ4arTIFPVc=
|
github.com/go-co-op/gocron/v2 v2.16.1/go.mod h1:opexeOFy5BplhsKdA7bzY9zeYih8I8/WNJ4arTIFPVc=
|
||||||
github.com/go-darwin/apfs v0.0.0-20211011131704-f84b94dbf348 h1:JnrjqG5iR07/8k7NqrLNilRsl3s1EPRQEGvbPyOce68=
|
|
||||||
github.com/go-darwin/apfs v0.0.0-20211011131704-f84b94dbf348/go.mod h1:Czxo/d1g948LtrALAZdL04TL/HnkopquAjxYUuI02bo=
|
|
||||||
github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM=
|
|
||||||
github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU=
|
|
||||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
|
||||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
|
||||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
|
||||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
|
||||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
|
||||||
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
|
||||||
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
|
||||||
github.com/go-openapi/errors v0.22.1 h1:kslMRRnK7NCb/CvR1q1VWuEQCEIsBGn5GgKD9e+HYhU=
|
|
||||||
github.com/go-openapi/errors v0.22.1/go.mod h1:+n/5UdIqdVnLIJ6Q9Se8HNGUXYaY6CN8ImWzfi/Gzp0=
|
|
||||||
github.com/go-openapi/strfmt v0.23.0 h1:nlUS6BCqcnAk0pyhi9Y+kdDVZdZMHfEKQiS4HaMgO/c=
|
|
||||||
github.com/go-openapi/strfmt v0.23.0/go.mod h1:NrtIpfKtWIygRkKVsxh7XQMDQW5HKQl6S5ik2elW+K4=
|
|
||||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
|
||||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
|
||||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
|
||||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
|
||||||
github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k=
|
|
||||||
github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
|
|
||||||
github.com/go-resty/resty/v2 v2.16.5 h1:hBKqmWrr7uRc3euHVqmh1HTHcKn99Smr7o5spptdhTM=
|
|
||||||
github.com/go-resty/resty/v2 v2.16.5/go.mod h1:hkJtXbA2iKHzJheXYvQ8snQES5ZLGKMwQ07xAwp/fiA=
|
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E=
|
|
||||||
github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0=
|
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/gogo/protobuf v1.2.0/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-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI=
|
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
|
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
@@ -276,90 +107,34 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX
|
|||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
|
|
||||||
github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
|
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4=
|
|
||||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA=
|
|
||||||
github.com/googleapis/gax-go/v2 v2.14.2 h1:eBLnkZ9635krYIPD+ag1USrOAI0Nr0QYF3+/3GqO0k0=
|
|
||||||
github.com/googleapis/gax-go/v2 v2.14.2/go.mod h1:ON64QhlJkhVtSqp4v1uaK92VyZ2gmvDQsweuyLV+8+w=
|
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20190309154008-847fc94819f9/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20190309154008-847fc94819f9/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99 h1:twflg0XRTjwKpxb/jFExr4HGq6on2dEOmnL6FV+fgPw=
|
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||||
github.com/gorilla/schema v1.4.1 h1:jUg5hUjCSDZpNGLuXQOgIWGdlgrIdYvgQ0wZtdK1M3E=
|
|
||||||
github.com/gorilla/schema v1.4.1/go.mod h1:Dg5SSm5PV60mhF2NFaTV1xuYYj8tV8NOPRo4FggUMnM=
|
|
||||||
github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA=
|
github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA=
|
||||||
github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo=
|
github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo=
|
||||||
github.com/gorilla/sessions v1.4.0 h1:kpIYOp/oi6MG/p5PgxApU8srsSw9tuFbt46Lt7auzqQ=
|
github.com/gorilla/sessions v1.4.0 h1:kpIYOp/oi6MG/p5PgxApU8srsSw9tuFbt46Lt7auzqQ=
|
||||||
github.com/gorilla/sessions v1.4.0/go.mod h1:FLWm50oby91+hl7p/wRxDth9bWSuk0qVL2emc7lT5ik=
|
github.com/gorilla/sessions v1.4.0/go.mod h1:FLWm50oby91+hl7p/wRxDth9bWSuk0qVL2emc7lT5ik=
|
||||||
github.com/hanwen/go-fuse/v2 v2.7.2 h1:SbJP1sUP+n1UF8NXBA14BuojmTez+mDgOk0bC057HQw=
|
|
||||||
github.com/hanwen/go-fuse/v2 v2.7.2/go.mod h1:ugNaD/iv5JYyS1Rcvi57Wz7/vrLQJo10mmketmoef48=
|
|
||||||
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
|
||||||
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
|
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
|
||||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
|
||||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
|
||||||
github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
|
|
||||||
github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
|
|
||||||
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
|
|
||||||
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
|
||||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/henrybear327/Proton-API-Bridge v1.0.0 h1:gjKAaWfKu++77WsZTHg6FUyPC5W0LTKWQciUm8PMZb0=
|
|
||||||
github.com/henrybear327/Proton-API-Bridge v1.0.0/go.mod h1:gunH16hf6U74W2b9CGDaWRadiLICsoJ6KRkSt53zLts=
|
|
||||||
github.com/henrybear327/go-proton-api v1.0.0 h1:zYi/IbjLwFAW7ltCeqXneUGJey0TN//Xo851a/BgLXw=
|
|
||||||
github.com/henrybear327/go-proton-api v1.0.0/go.mod h1:w63MZuzufKcIZ93pwRgiOtxMXYafI8H74D77AxytOBc=
|
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo=
|
github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo=
|
||||||
github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4=
|
github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4=
|
||||||
github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||||
github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw=
|
github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw=
|
||||||
github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
|
||||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
|
||||||
github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8=
|
|
||||||
github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
|
|
||||||
github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo=
|
|
||||||
github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM=
|
|
||||||
github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg=
|
|
||||||
github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo=
|
|
||||||
github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o=
|
|
||||||
github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg=
|
|
||||||
github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh687T8=
|
|
||||||
github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs=
|
|
||||||
github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY=
|
|
||||||
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
|
|
||||||
github.com/jlaffaye/ftp v0.2.1-0.20240918233326-1b970516f5d3 h1:ZxO6Qr2GOXPdcW80Mcn3nemvilMPvpWqxrNfK2ZnNNs=
|
|
||||||
github.com/jlaffaye/ftp v0.2.1-0.20240918233326-1b970516f5d3/go.mod h1:dvLUr/8Fs9a2OBrEnCC5duphbkz/k/mSy5OkXg3PAgI=
|
|
||||||
github.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I=
|
github.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I=
|
||||||
github.com/jonboulle/clockwork v0.5.0/go.mod h1:3mZlmanh0g2NDKO5TWZVJAfofYk64M7XN3SzBPjZF60=
|
github.com/jonboulle/clockwork v0.5.0/go.mod h1:3mZlmanh0g2NDKO5TWZVJAfofYk64M7XN3SzBPjZF60=
|
||||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
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.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
|
||||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
github.com/jtolio/noiseconn v0.0.0-20231127013910-f6d9ecbf1de7 h1:JcltaO1HXM5S2KYOYcKgAV7slU0xPy1OcvrVgn98sRQ=
|
|
||||||
github.com/jtolio/noiseconn v0.0.0-20231127013910-f6d9ecbf1de7/go.mod h1:MEkhEPFwP3yudWO0lj6vfYpLIB+3eIcuIW+e0AZzUQk=
|
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
github.com/jzelinskie/whirlpool v0.0.0-20201016144138-0675e54bb004 h1:G+9t9cEtnC9jFiTxyptEKuNIAbiN5ZCQzX2a74lj3xg=
|
|
||||||
github.com/jzelinskie/whirlpool v0.0.0-20201016144138-0675e54bb004/go.mod h1:KmHnJWQrgEvbuy0vcvj00gtMqbvNn1L+3YUZLK/B92c=
|
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
|
||||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
|
||||||
github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
|
|
||||||
github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/koofr/go-httpclient v0.0.0-20240520111329-e20f8f203988 h1:CjEMN21Xkr9+zwPmZPaJJw+apzVbjGL5uK/6g9Q2jGU=
|
|
||||||
github.com/koofr/go-httpclient v0.0.0-20240520111329-e20f8f203988/go.mod h1:/agobYum3uo/8V6yPVnq+R82pyVGCeuWW5arT4Txn8A=
|
|
||||||
github.com/koofr/go-koofrclient v0.0.0-20221207135200-cbd7fc9ad6a6 h1:FHVoZMOVRA+6/y4yRlbiR3WvsrOcKBd/f64H7YiWR2U=
|
|
||||||
github.com/koofr/go-koofrclient v0.0.0-20221207135200-cbd7fc9ad6a6/go.mod h1:MRAz4Gsxd+OzrZ0owwrUHc0zLESL+1Y5syqK/sJxK2A=
|
|
||||||
github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
|
|
||||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
@@ -368,16 +143,6 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
|||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
|
||||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
|
||||||
github.com/lanrat/extsort v1.0.2 h1:p3MLVpQEPwEGPzeLBb+1eSErzRl6Bgjgr+qnIs2RxrU=
|
|
||||||
github.com/lanrat/extsort v1.0.2/go.mod h1:ivzsdLm8Tv+88qbdpMElV6Z15StlzPUtZSKsGb51hnQ=
|
|
||||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
|
||||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
|
||||||
github.com/lpar/date v1.0.0 h1:bq/zVqFTUmsxvd/CylidY4Udqpr9BOFrParoP6p0x/I=
|
|
||||||
github.com/lpar/date v1.0.0/go.mod h1:KjYe0dDyMQTgpqcUz4LEIeM5VZwhggjVx/V2dtc8NSo=
|
|
||||||
github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 h1:PpXWgLPs+Fqr325bN2FD2ISlRRztXibcX6e8f5FR5Dc=
|
|
||||||
github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
|
|
||||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
||||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||||
@@ -386,87 +151,42 @@ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D
|
|||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
|
||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
|
||||||
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/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg=
|
|
||||||
github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4=
|
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=
|
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=
|
||||||
github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw=
|
github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
github.com/ncw/swift/v2 v2.0.4 h1:hHWVFxn5/YaTWAASmn4qyq2p6OyP/Hm3vMLzkjEqR7w=
|
|
||||||
github.com/ncw/swift/v2 v2.0.4/go.mod h1:cbAO76/ZwcFrFlHdXPjaqWZ9R7Hdar7HpjRXBfbjigk=
|
|
||||||
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
|
|
||||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||||
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||||
github.com/oracle/oci-go-sdk/v65 v65.93.0 h1:L6cfEXHZYW9WXD+q0g+HPvLS5TkZjpn3b0RlkLWOLpM=
|
|
||||||
github.com/oracle/oci-go-sdk/v65 v65.93.0/go.mod h1:u6XRPsw9tPziBh76K7GrrRXPa8P8W3BQeqJ6ZZt9VLA=
|
|
||||||
github.com/panjf2000/ants/v2 v2.11.3 h1:AfI0ngBoXJmYOpDh9m516vjqoUu2sLrIVgppI9TZVpg=
|
|
||||||
github.com/panjf2000/ants/v2 v2.11.3/go.mod h1:8u92CYMUc6gyvTIw8Ru7Mt7+/ESnJahz5EVtqfrilek=
|
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
|
||||||
github.com/pengsrc/go-shared v0.2.1-0.20190131101655-1999055a4a14 h1:XeOYlK9W1uCmhjJSsY78Mcuh7MVkNjTzmHx1yBzizSU=
|
|
||||||
github.com/pengsrc/go-shared v0.2.1-0.20190131101655-1999055a4a14/go.mod h1:jVblp62SafmidSkvWrXyxAme3gaTfEtWwRPGz5cpvHg=
|
|
||||||
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
|
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
|
||||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
|
|
||||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
|
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/sftp v1.13.9 h1:4NGkvGudBL7GteO3m6qnaQ4pC0Kvf0onSVc9gR3EWBw=
|
|
||||||
github.com/pkg/sftp v1.13.9/go.mod h1:OBN7bVXdstkFFN/gdnHPUb5TE8eb8G1Rp9wCItqjkkA=
|
|
||||||
github.com/pkg/xattr v0.4.10 h1:Qe0mtiNFHQZ296vRgUjRCoPHPqH7VdTOrZx3g0T+pGA=
|
|
||||||
github.com/pkg/xattr v0.4.10/go.mod h1:di8WF84zAKk8jzR1UBTEWh9AUlIZZ7M/JNt8e9B6ktU=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
|
|
||||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
|
||||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||||
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
||||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||||
github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
|
github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
|
||||||
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
|
|
||||||
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
|
|
||||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
|
||||||
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
|
||||||
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
|
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
|
||||||
github.com/prometheus/common v0.64.0 h1:pdZeA+g617P7oGv1CzdTzyeShxAGrTBsolKNOLQPGO4=
|
|
||||||
github.com/prometheus/common v0.64.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
|
|
||||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||||
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
||||||
github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||||
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
|
|
||||||
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
|
|
||||||
github.com/putdotio/go-putio/putio v0.0.0-20200123120452-16d982cac2b8 h1:Y258uzXU/potCYnQd1r6wlAnoMB68BiCkCcCnKx1SH8=
|
|
||||||
github.com/putdotio/go-putio/putio v0.0.0-20200123120452-16d982cac2b8/go.mod h1:bSJjRokAHHOhA+XFxplld8w2R/dXLH7Z3BZ532vhFwU=
|
|
||||||
github.com/rclone/rclone v1.70.3 h1:rg/WNh4DmSVZyKP2tHZ4lAaWEyMi7h/F0r7smOMA3IE=
|
|
||||||
github.com/rclone/rclone v1.70.3/go.mod h1:nLyN+hpxAsQn9Rgt5kM774lcRDad82x/KqQeBZ83cMo=
|
|
||||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||||
github.com/relvacode/iso8601 v1.6.0 h1:eFXUhMJN3Gz8Rcq82f9DTMW0svjtAVuIEULglM7QHTU=
|
|
||||||
github.com/relvacode/iso8601 v1.6.0/go.mod h1:FlNp+jz+TXpyRqgmM7tnzHHzBnz776kmAH2h3sZCn0I=
|
|
||||||
github.com/rfjakob/eme v1.1.2 h1:SxziR8msSOElPayZNFfQw4Tjx/Sbaeeh3eRvrHVMUs4=
|
|
||||||
github.com/rfjakob/eme v1.1.2/go.mod h1:cVvpasglm/G3ngEfcfT/Wt0GwhkuO32pf/poW6Nyk1k=
|
|
||||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||||
@@ -474,35 +194,13 @@ github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7
|
|||||||
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||||
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
|
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
|
||||||
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
|
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
|
||||||
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5PCi+MFsC7HjREoAz1BU+Mq60+05gifQSsHSDG/8=
|
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5PCi+MFsC7HjREoAz1BU+Mq60+05gifQSsHSDG/8=
|
||||||
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 h1:OkMGxebDjyw0ULyrTYWeN0UNCCkmCWfjPnIA2W6oviI=
|
|
||||||
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06/go.mod h1:+ePHsJ1keEjQtpvf9HHw0f4ZeJ0TLRsxhunSI2hYJSs=
|
|
||||||
github.com/samber/lo v1.50.0 h1:XrG0xOeHs+4FQ8gJR97zDz5uOFMW7OwFWiFVzqopKgY=
|
|
||||||
github.com/samber/lo v1.50.0/go.mod h1:RjZyNk6WSnUFRKK6EyOhsRJMqft3G+pg7dCWHQCWvsc=
|
|
||||||
github.com/shirou/gopsutil/v4 v4.25.5 h1:rtd9piuSMGeU8g1RMXjZs9y9luK5BwtnG7dZaQUJAsc=
|
|
||||||
github.com/shirou/gopsutil/v4 v4.25.5/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c=
|
|
||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
|
||||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
|
||||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA=
|
|
||||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
|
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
github.com/smartystreets/assertions v0.0.0-20190215210624-980c5ac6f3ac h1:wbW+Bybf9pXxnCFAOWZTqkRjAc7rAIwo2e1ArUhiHxg=
|
|
||||||
github.com/smartystreets/assertions v0.0.0-20190215210624-980c5ac6f3ac/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
github.com/smartystreets/assertions v0.0.0-20190215210624-980c5ac6f3ac/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
|
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
|
||||||
github.com/smartystreets/goconvey v0.0.0-20190306220146-200a235640ff/go.mod h1:KSQcGKpxUMHk3nbYzs/tIBAM2iDooCn0BmttHOJEbLs=
|
github.com/smartystreets/goconvey v0.0.0-20190306220146-200a235640ff/go.mod h1:KSQcGKpxUMHk3nbYzs/tIBAM2iDooCn0BmttHOJEbLs=
|
||||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a h1:pa8hGb/2YqsZKovtsgrwcDH1RZhVbTKCjLp47XpqCDs=
|
|
||||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
|
||||||
github.com/sony/gobreaker v1.0.0 h1:feX5fGGXSl3dYd4aHZItw+FpHLvvoaqkawKjVNiFMNQ=
|
|
||||||
github.com/sony/gobreaker v1.0.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
|
|
||||||
github.com/spacemonkeygo/monkit/v3 v3.0.24 h1:cKixJ+evHnfJhWNyIZjBy5hoW8LTWmrJXPo18tzLNrk=
|
|
||||||
github.com/spacemonkeygo/monkit/v3 v3.0.24/go.mod h1:XkZYGzknZwkD0AKUnZaSXhRiVTLCkq7CWVa3IsE72gA=
|
|
||||||
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
|
|
||||||
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
|
|
||||||
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
|
||||||
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
|
||||||
github.com/stanNthe5/stringbuf v0.0.3 h1:3ChRipDckEY6FykaQ1Dowy3B+ZQa72EDBCasvT5+D1w=
|
github.com/stanNthe5/stringbuf v0.0.3 h1:3ChRipDckEY6FykaQ1Dowy3B+ZQa72EDBCasvT5+D1w=
|
||||||
github.com/stanNthe5/stringbuf v0.0.3/go.mod h1:hii5Vr+mucoWkNJlIYQVp8YvuPtq45fFnJEAhcPf2cQ=
|
github.com/stanNthe5/stringbuf v0.0.3/go.mod h1:hii5Vr+mucoWkNJlIYQVp8YvuPtq45fFnJEAhcPf2cQ=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
@@ -513,52 +211,14 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
|
|||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/t3rm1n4l/go-mega v0.0.0-20241213151442-a19cff0ec7b5 h1:Sa+sR8aaAMFwxhXWENEnE6ZpqhZ9d7u1RT2722Rw6hc=
|
|
||||||
github.com/t3rm1n4l/go-mega v0.0.0-20241213151442-a19cff0ec7b5/go.mod h1:UdZiFUFu6e2WjjtjxivwXWcwc1N/8zgbkBR9QNucUOY=
|
|
||||||
github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||||
github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||||
github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||||
github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4=
|
|
||||||
github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4=
|
|
||||||
github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso=
|
|
||||||
github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ=
|
|
||||||
github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c h1:u6SKchux2yDvFQnDHS3lPnIRmfVJ5Sxy3ao2SIdysLQ=
|
|
||||||
github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM=
|
|
||||||
github.com/unknwon/goconfig v1.0.0 h1:rS7O+CmUdli1T+oDm7fYj1MwqNWtEJfNj+FqcUHML8U=
|
|
||||||
github.com/unknwon/goconfig v1.0.0/go.mod h1:qu2ZQ/wcC/if2u32263HTVC39PeOQRSmidQk3DuDFQ8=
|
|
||||||
github.com/willf/bitset v1.1.9/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
github.com/willf/bitset v1.1.9/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
||||||
github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
||||||
github.com/winfsp/cgofuse v1.6.0 h1:re3W+HTd0hj4fISPBqfsrwyvPFpzqhDu8doJ9nOPDB0=
|
|
||||||
github.com/winfsp/cgofuse v1.6.0/go.mod h1:uxjoF2jEYT3+x+vC2KJddEGdk/LU8pRowXmyVMHSV5I=
|
|
||||||
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
|
|
||||||
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
|
|
||||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
|
|
||||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
|
|
||||||
github.com/yunify/qingstor-sdk-go/v3 v3.2.0 h1:9sB2WZMgjwSUNZhrgvaNGazVltoFUUfuS9f0uCWtTr8=
|
|
||||||
github.com/yunify/qingstor-sdk-go/v3 v3.2.0/go.mod h1:KciFNuMu6F4WLk9nGwwK69sCGKLCdd9f97ac/wfumS4=
|
|
||||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
|
||||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
|
||||||
github.com/zeebo/blake3 v0.2.4 h1:KYQPkhpRtcqh0ssGYcKLG1JYvddkEA8QwCM/yBqhaZI=
|
|
||||||
github.com/zeebo/blake3 v0.2.4/go.mod h1:7eeQ6d2iXWRGF6npfaxl2CU+xy2Fjo2gxeyZGCRUjcE=
|
|
||||||
github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM=
|
|
||||||
github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4=
|
|
||||||
go.etcd.io/bbolt v1.4.0 h1:TU77id3TnN/zKr7CO/uk+fBCwF2jGcMuw2B/FMAzYIk=
|
|
||||||
go.etcd.io/bbolt v1.4.0/go.mod h1:AsD+OCi/qPN1giOX1aiLAha3o1U8rAz65bvN4j0sRuk=
|
|
||||||
go.mongodb.org/mongo-driver v1.17.4 h1:jUorfmVzljjr0FLzYQsGP8cgN/qzzxlY9Vh0C9KFXVw=
|
|
||||||
go.mongodb.org/mongo-driver v1.17.4/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
|
|
||||||
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||||
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
|
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
|
|
||||||
go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
|
|
||||||
go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
|
|
||||||
go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
|
|
||||||
go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
|
|
||||||
go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
|
|
||||||
go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
|
|
||||||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
@@ -570,8 +230,6 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
|||||||
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
|
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
|
||||||
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
|
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476 h1:bsqhLWFR6G6xiQcb+JoGqdKdRU6WzPWmK8E0jxTjzo4=
|
|
||||||
golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8=
|
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
@@ -590,14 +248,11 @@ golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
|
|||||||
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
|
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
|
|
||||||
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
|
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
|
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
|
||||||
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@@ -608,91 +263,50 @@ golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5h
|
|||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/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-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||||
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
|
|
||||||
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
|
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
|
|
||||||
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
|
|
||||||
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
|
|
||||||
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
|
||||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
||||||
google.golang.org/api v0.236.0 h1:CAiEiDVtO4D/Qja2IA9VzlFrgPnK3XVMmRoJZlSWbc0=
|
|
||||||
google.golang.org/api v0.236.0/go.mod h1:X1WF9CU2oTc+Jml1tiIxGmWFK/UZezdqEu09gcxZAj4=
|
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE=
|
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
|
||||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
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.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok=
|
|
||||||
google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
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-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 v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
|
||||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
gopkg.in/validator.v2 v2.0.1 h1:xF0KWyGWXm/LM2G1TrEjqOu4pa6coO9AlWSf3msVfDY=
|
|
||||||
gopkg.in/validator.v2 v2.0.1/go.mod h1:lIUZBlB3Im4s/eYp39Ry/wkR02yOPhZ9IwIRBjuPuG8=
|
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
moul.io/http2curl/v2 v2.3.0 h1:9r3JfDzWPcbIklMOs2TnIFzDYvfAZvjeavG6EzP7jYs=
|
|
||||||
moul.io/http2curl/v2 v2.3.0/go.mod h1:RW4hyBjTWSYDOxapodpNEtX0g5Eb16sxklBqmd2RHcE=
|
|
||||||
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
|
||||||
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
|
||||||
storj.io/common v0.0.0-20250605163628-70ca83b6228e h1:Ar4dEFhvK+hjTIAibwkz41A3rCY6IicqsLnvvb5M/4w=
|
|
||||||
storj.io/common v0.0.0-20250605163628-70ca83b6228e/go.mod h1:1+Y92GXn/TiNuBny5/vJUyW7+zdOFpc8y9I7eGYPyDE=
|
|
||||||
storj.io/drpc v0.0.35-0.20250513201419-f7819ea69b55 h1:8OE12DvUnB9lfZcHe7IDGsuhjrY9GBAr964PVHmhsro=
|
|
||||||
storj.io/drpc v0.0.35-0.20250513201419-f7819ea69b55/go.mod h1:Y9LZaa8esL1PW2IDMqJE7CFSNq7d5bQ3RI7mGPtmKMg=
|
|
||||||
storj.io/eventkit v0.0.0-20250410172343-61f26d3de156 h1:5MZ0CyMbG6Pi0rRzUWVG6dvpXjbBYEX2oyXuj+tT+sk=
|
|
||||||
storj.io/eventkit v0.0.0-20250410172343-61f26d3de156/go.mod h1:CpnM6kfZV58dcq3lpbo/IQ4/KoutarnTSHY0GYVwnYw=
|
|
||||||
storj.io/infectious v0.0.2 h1:rGIdDC/6gNYAStsxsZU79D/MqFjNyJc1tsyyj9sTl7Q=
|
|
||||||
storj.io/infectious v0.0.2/go.mod h1:QEjKKww28Sjl1x8iDsjBpOM4r1Yp8RsowNcItsZJ1Vs=
|
|
||||||
storj.io/picobuf v0.0.4 h1:qswHDla+YZ2TovGtMnU4astjvrADSIz84FXRn0qgP6o=
|
|
||||||
storj.io/picobuf v0.0.4/go.mod h1:hSMxmZc58MS/2qSLy1I0idovlO7+6K47wIGUyRZa6mg=
|
|
||||||
storj.io/uplink v1.13.1 h1:C8RdW/upALoCyuF16Lod9XGCXEdbJAS+ABQy9JO/0pA=
|
|
||||||
storj.io/uplink v1.13.1/go.mod h1:x0MQr4UfFsQBwgVWZAtEsLpuwAn6dg7G0Mpne1r516E=
|
|
||||||
|
|||||||
@@ -12,14 +12,14 @@ import (
|
|||||||
"github.com/sirrobot01/decypharr/pkg/debrid/providers/debrid_link"
|
"github.com/sirrobot01/decypharr/pkg/debrid/providers/debrid_link"
|
||||||
"github.com/sirrobot01/decypharr/pkg/debrid/providers/realdebrid"
|
"github.com/sirrobot01/decypharr/pkg/debrid/providers/realdebrid"
|
||||||
"github.com/sirrobot01/decypharr/pkg/debrid/providers/torbox"
|
"github.com/sirrobot01/decypharr/pkg/debrid/providers/torbox"
|
||||||
"github.com/sirrobot01/decypharr/pkg/debrid/store"
|
debridStore "github.com/sirrobot01/decypharr/pkg/debrid/store"
|
||||||
"github.com/sirrobot01/decypharr/pkg/debrid/types"
|
"github.com/sirrobot01/decypharr/pkg/debrid/types"
|
||||||
"github.com/sirrobot01/decypharr/pkg/mount"
|
"github.com/sirrobot01/decypharr/pkg/rclone"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Debrid struct {
|
type Debrid struct {
|
||||||
cache *store.Cache // Could be nil if not using WebDAV
|
cache *debridStore.Cache // Could be nil if not using WebDAV
|
||||||
client types.Client // HTTP client for making requests to the debrid service
|
client types.Client // HTTP client for making requests to the debrid service
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,7 +27,7 @@ func (de *Debrid) Client() types.Client {
|
|||||||
return de.client
|
return de.client
|
||||||
}
|
}
|
||||||
|
|
||||||
func (de *Debrid) Cache() *store.Cache {
|
func (de *Debrid) Cache() *debridStore.Cache {
|
||||||
return de.cache
|
return de.cache
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ type Storage struct {
|
|||||||
lastUsed string
|
lastUsed string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStorage() *Storage {
|
func NewStorage(rcManager *rclone.Manager) *Storage {
|
||||||
cfg := config.Get()
|
cfg := config.Get()
|
||||||
|
|
||||||
_logger := logger.Default()
|
_logger := logger.Default()
|
||||||
@@ -63,15 +63,15 @@ func NewStorage() *Storage {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
cache *store.Cache
|
cache *debridStore.Cache
|
||||||
mounter *mount.Mount
|
mounter *rclone.Mount
|
||||||
)
|
)
|
||||||
_log := client.Logger()
|
_log := client.Logger()
|
||||||
if dc.UseWebDav {
|
if dc.UseWebDav {
|
||||||
if cfg.Rclone.Enabled {
|
if cfg.Rclone.Enabled && rcManager != nil {
|
||||||
mounter = mount.NewMount(dc.Name, webdavUrl)
|
mounter = rclone.NewMount(dc.Name, webdavUrl, rcManager)
|
||||||
}
|
}
|
||||||
cache = store.NewDebridCache(dc, client, mounter)
|
cache = debridStore.NewDebridCache(dc, client, mounter)
|
||||||
_log.Info().Msg("Debrid Service started with WebDAV")
|
_log.Info().Msg("Debrid Service started with WebDAV")
|
||||||
} else {
|
} else {
|
||||||
_log.Info().Msg("Debrid Service started")
|
_log.Info().Msg("Debrid Service started")
|
||||||
@@ -147,10 +147,10 @@ func (d *Storage) Clients() map[string]types.Client {
|
|||||||
return clientsCopy
|
return clientsCopy
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Storage) Caches() map[string]*store.Cache {
|
func (d *Storage) Caches() map[string]*debridStore.Cache {
|
||||||
d.mu.RLock()
|
d.mu.RLock()
|
||||||
defer d.mu.RUnlock()
|
defer d.mu.RUnlock()
|
||||||
cachesCopy := make(map[string]*store.Cache)
|
cachesCopy := make(map[string]*debridStore.Cache)
|
||||||
for name, debrid := range d.debrids {
|
for name, debrid := range d.debrids {
|
||||||
if debrid != nil && debrid.cache != nil {
|
if debrid != nil && debrid.cache != nil {
|
||||||
cachesCopy[name] = debrid.cache
|
cachesCopy[name] = debrid.cache
|
||||||
@@ -221,7 +221,7 @@ func Process(ctx context.Context, store *Storage, selectedDebrid string, magnet
|
|||||||
debridTorrent.DownloadUncached = false
|
debridTorrent.DownloadUncached = false
|
||||||
}
|
}
|
||||||
|
|
||||||
for index, db := range clients {
|
for _, db := range clients {
|
||||||
_logger := db.Logger()
|
_logger := db.Logger()
|
||||||
_logger.Info().
|
_logger.Info().
|
||||||
Str("Debrid", db.Name()).
|
Str("Debrid", db.Name()).
|
||||||
@@ -242,7 +242,7 @@ func Process(ctx context.Context, store *Storage, selectedDebrid string, magnet
|
|||||||
}
|
}
|
||||||
dbt.Arr = a
|
dbt.Arr = a
|
||||||
_logger.Info().Str("id", dbt.Id).Msgf("Torrent: %s submitted to %s", dbt.Name, db.Name())
|
_logger.Info().Str("id", dbt.Id).Msgf("Torrent: %s submitted to %s", dbt.Name, db.Name())
|
||||||
store.lastUsed = index
|
store.lastUsed = db.Name()
|
||||||
|
|
||||||
torrent, err := db.CheckStatus(dbt)
|
torrent, err := db.CheckStatus(dbt)
|
||||||
if err != nil && torrent != nil && torrent.Id != "" {
|
if err != nil && torrent != nil && torrent.Id != "" {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/sirrobot01/decypharr/pkg/mount"
|
"github.com/sirrobot01/decypharr/pkg/rclone"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -107,10 +107,10 @@ type Cache struct {
|
|||||||
|
|
||||||
config config.Debrid
|
config config.Debrid
|
||||||
customFolders []string
|
customFolders []string
|
||||||
mounter *mount.Mount
|
mounter *rclone.Mount
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDebridCache(dc config.Debrid, client types.Client, mounter *mount.Mount) *Cache {
|
func NewDebridCache(dc config.Debrid, client types.Client, mounter *rclone.Mount) *Cache {
|
||||||
cfg := config.Get()
|
cfg := config.Get()
|
||||||
cet, err := time.LoadLocation("CET")
|
cet, err := time.LoadLocation("CET")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -29,6 +29,12 @@ func (fi *fileInfo) IsDir() bool { return fi.isDir }
|
|||||||
func (fi *fileInfo) ID() string { return fi.id }
|
func (fi *fileInfo) ID() string { return fi.id }
|
||||||
func (fi *fileInfo) Sys() interface{} { return nil }
|
func (fi *fileInfo) Sys() interface{} { return nil }
|
||||||
|
|
||||||
|
type RcloneRC struct {
|
||||||
|
URL string
|
||||||
|
User string
|
||||||
|
Pass string
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Cache) RefreshListings(refreshRclone bool) {
|
func (c *Cache) RefreshListings(refreshRclone bool) {
|
||||||
// Copy the torrents to a string|time map
|
// Copy the torrents to a string|time map
|
||||||
c.torrents.refreshListing() // refresh torrent listings
|
c.torrents.refreshListing() // refresh torrent listings
|
||||||
@@ -147,10 +153,6 @@ func (c *Cache) refreshRcloneWithRC(dirs []string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.RcUrl == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
client := http.DefaultClient
|
client := http.DefaultClient
|
||||||
// Create form data
|
// Create form data
|
||||||
data := c.buildRcloneRequestData(dirs)
|
data := c.buildRcloneRequestData(dirs)
|
||||||
|
|||||||
@@ -1,443 +0,0 @@
|
|||||||
package mount
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"github.com/rs/zerolog"
|
|
||||||
"github.com/sirrobot01/decypharr/internal/logger"
|
|
||||||
"net/url"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
"sync/atomic"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/rclone/rclone/cmd/mountlib"
|
|
||||||
"github.com/rclone/rclone/fs"
|
|
||||||
"github.com/rclone/rclone/fs/config"
|
|
||||||
"github.com/rclone/rclone/vfs"
|
|
||||||
"github.com/rclone/rclone/vfs/vfscommon"
|
|
||||||
|
|
||||||
_ "github.com/rclone/rclone/backend/local" // Local backend (required for VFS cache)
|
|
||||||
_ "github.com/rclone/rclone/backend/webdav" // WebDAV backend
|
|
||||||
_ "github.com/rclone/rclone/cmd/cmount" // Custom mount for macOS
|
|
||||||
_ "github.com/rclone/rclone/cmd/mount" // Standard FUSE mount
|
|
||||||
// Try to import available mount backends for macOS
|
|
||||||
// These are conditional imports that may or may not work depending on system setup
|
|
||||||
_ "github.com/rclone/rclone/cmd/mount2" // Alternative FUSE mount
|
|
||||||
|
|
||||||
configPkg "github.com/sirrobot01/decypharr/internal/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
func getMountFn() (mountlib.MountFn, error) {
|
|
||||||
// Try mount methods in order of preference
|
|
||||||
for _, method := range []string{"", "mount", "cmount", "mount2"} {
|
|
||||||
_, mountFn := mountlib.ResolveMountMethod(method)
|
|
||||||
if mountFn != nil {
|
|
||||||
return mountFn, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, errors.New("no suitable mount function found")
|
|
||||||
}
|
|
||||||
|
|
||||||
type Mount struct {
|
|
||||||
Provider string
|
|
||||||
LocalPath string
|
|
||||||
WebDAVURL string
|
|
||||||
mountPoint *mountlib.MountPoint
|
|
||||||
cancel context.CancelFunc
|
|
||||||
mounted atomic.Bool
|
|
||||||
logger zerolog.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewMount(provider, webdavURL string) *Mount {
|
|
||||||
cfg := configPkg.Get()
|
|
||||||
_logger := logger.New("mount-" + provider)
|
|
||||||
mountPath := filepath.Join(cfg.Rclone.MountPath, provider)
|
|
||||||
_url, err := url.JoinPath(webdavURL, provider)
|
|
||||||
if err != nil {
|
|
||||||
_url = fmt.Sprintf("%s/%s", webdavURL, provider)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get mount function to validate if FUSE is available
|
|
||||||
mountFn, err := getMountFn()
|
|
||||||
if err != nil || mountFn == nil {
|
|
||||||
_logger.Warn().Err(err).Msgf("Mount function not available for %s, using WebDAV URL %s", provider, _url)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return &Mount{
|
|
||||||
Provider: provider,
|
|
||||||
LocalPath: mountPath,
|
|
||||||
WebDAVURL: _url,
|
|
||||||
logger: _logger,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Mount) Mount(ctx context.Context) error {
|
|
||||||
if m.mounted.Load() {
|
|
||||||
m.logger.Info().Msgf("Mount %s is already mounted at %s", m.Provider, m.LocalPath)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := os.MkdirAll(m.LocalPath, 0755); err != nil && !os.IsExist(err) {
|
|
||||||
return fmt.Errorf("failed to create mount directory %s: %w", m.LocalPath, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the mount point is already busy/mounted
|
|
||||||
if m.isMountBusy() {
|
|
||||||
m.logger.Warn().Msgf("Mount point %s appears to be busy, attempting cleanup", m.LocalPath)
|
|
||||||
if err := m.forceUnmount(); err != nil {
|
|
||||||
m.logger.Error().Err(err).Msgf("Failed to cleanup busy mount point %s", m.LocalPath)
|
|
||||||
return fmt.Errorf("mount point %s is busy and cleanup failed: %w", m.LocalPath, err)
|
|
||||||
}
|
|
||||||
m.logger.Info().Msgf("Successfully cleaned up busy mount point %s", m.LocalPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create mount context
|
|
||||||
mountCtx, cancel := context.WithCancel(ctx)
|
|
||||||
m.cancel = cancel
|
|
||||||
|
|
||||||
if err := setRcloneConfig(m.Provider, m.WebDAVURL); err != nil {
|
|
||||||
return fmt.Errorf("failed to set rclone config: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the mount function - try different mount methods
|
|
||||||
mountFn, err := getMountFn()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to get mount function for %s: %w", m.Provider, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
if err := m.performMount(mountCtx, mountFn); err != nil {
|
|
||||||
m.logger.Error().Err(err).Msgf("Failed to mount %s at %s", m.Provider, m.LocalPath)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
m.mounted.Store(true)
|
|
||||||
m.logger.Info().Msgf("Successfully mounted %s WebDAV at %s", m.Provider, m.LocalPath)
|
|
||||||
<-mountCtx.Done() // Wait for context cancellation
|
|
||||||
}()
|
|
||||||
m.logger.Info().Msgf("Mount process started for %s at %s", m.Provider, m.LocalPath)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func setRcloneConfig(configName, webdavURL string) error {
|
|
||||||
// Set configuration in rclone's config system using FileSetValue
|
|
||||||
config.FileSetValue(configName, "type", "webdav")
|
|
||||||
config.FileSetValue(configName, "url", webdavURL)
|
|
||||||
config.FileSetValue(configName, "vendor", "other")
|
|
||||||
config.FileSetValue(configName, "pacer_min_sleep", "0")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Mount) performMount(ctx context.Context, mountfn mountlib.MountFn) error {
|
|
||||||
// Create filesystem from config
|
|
||||||
fsrc, err := fs.NewFs(ctx, fmt.Sprintf("%s:", m.Provider))
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to create filesystem: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get global rclone config
|
|
||||||
rcloneOpt := configPkg.Get().Rclone
|
|
||||||
|
|
||||||
// Parse cache mode
|
|
||||||
var cacheMode vfscommon.CacheMode
|
|
||||||
switch rcloneOpt.VfsCacheMode {
|
|
||||||
case "off":
|
|
||||||
cacheMode = vfscommon.CacheModeOff
|
|
||||||
case "minimal":
|
|
||||||
cacheMode = vfscommon.CacheModeMinimal
|
|
||||||
case "writes":
|
|
||||||
cacheMode = vfscommon.CacheModeWrites
|
|
||||||
case "full":
|
|
||||||
cacheMode = vfscommon.CacheModeFull
|
|
||||||
default:
|
|
||||||
cacheMode = vfscommon.CacheModeOff
|
|
||||||
}
|
|
||||||
|
|
||||||
vfsOpt := &vfscommon.Options{}
|
|
||||||
|
|
||||||
vfsOpt.Init() // Initialize VFS options with default values
|
|
||||||
|
|
||||||
vfsOpt.CacheMode = cacheMode
|
|
||||||
|
|
||||||
// Set VFS options based on rclone configuration
|
|
||||||
if rcloneOpt.NoChecksum {
|
|
||||||
vfsOpt.NoChecksum = rcloneOpt.NoChecksum
|
|
||||||
}
|
|
||||||
if rcloneOpt.NoModTime {
|
|
||||||
vfsOpt.NoModTime = rcloneOpt.NoModTime
|
|
||||||
}
|
|
||||||
if rcloneOpt.UID != 0 {
|
|
||||||
vfsOpt.UID = rcloneOpt.UID
|
|
||||||
}
|
|
||||||
if rcloneOpt.GID != 0 {
|
|
||||||
vfsOpt.GID = rcloneOpt.GID
|
|
||||||
}
|
|
||||||
if rcloneOpt.Umask != "" {
|
|
||||||
var umask vfscommon.FileMode
|
|
||||||
if err := umask.Set(rcloneOpt.Umask); err == nil {
|
|
||||||
vfsOpt.Umask = umask
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse duration strings
|
|
||||||
if rcloneOpt.DirCacheTime != "" {
|
|
||||||
if dirCacheTime, err := time.ParseDuration(rcloneOpt.DirCacheTime); err == nil {
|
|
||||||
vfsOpt.DirCacheTime = fs.Duration(dirCacheTime)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if rcloneOpt.VfsCachePollInterval != "" {
|
|
||||||
if vfsCachePollInterval, err := time.ParseDuration(rcloneOpt.VfsCachePollInterval); err == nil {
|
|
||||||
vfsOpt.CachePollInterval = fs.Duration(vfsCachePollInterval)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if rcloneOpt.VfsCacheMaxAge != "" {
|
|
||||||
if vfsCacheMaxAge, err := time.ParseDuration(rcloneOpt.VfsCacheMaxAge); err == nil {
|
|
||||||
vfsOpt.CacheMaxAge = fs.Duration(vfsCacheMaxAge)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if rcloneOpt.VfsReadChunkSizeLimit != "" {
|
|
||||||
var chunkSizeLimit fs.SizeSuffix
|
|
||||||
if err := chunkSizeLimit.Set(rcloneOpt.VfsReadChunkSizeLimit); err == nil {
|
|
||||||
vfsOpt.ChunkSizeLimit = chunkSizeLimit
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if rcloneOpt.VfsReadAhead != "" {
|
|
||||||
var readAhead fs.SizeSuffix
|
|
||||||
if err := readAhead.Set(rcloneOpt.VfsReadAhead); err == nil {
|
|
||||||
vfsOpt.ReadAhead = readAhead
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if rcloneOpt.VfsReadChunkSize != "" {
|
|
||||||
var chunkSize fs.SizeSuffix
|
|
||||||
if err := chunkSize.Set(rcloneOpt.VfsReadChunkSize); err == nil {
|
|
||||||
vfsOpt.ChunkSize = chunkSize
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse and set buffer size globally for rclone
|
|
||||||
if rcloneOpt.BufferSize != "" {
|
|
||||||
var bufferSize fs.SizeSuffix
|
|
||||||
if err := bufferSize.Set(rcloneOpt.BufferSize); err == nil {
|
|
||||||
fs.GetConfig(ctx).BufferSize = bufferSize
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fs.GetConfig(ctx).UseMmap = true
|
|
||||||
|
|
||||||
if rcloneOpt.VfsCacheMaxSize != "" {
|
|
||||||
var cacheMaxSize fs.SizeSuffix
|
|
||||||
if err := cacheMaxSize.Set(rcloneOpt.VfsCacheMaxSize); err == nil {
|
|
||||||
vfsOpt.CacheMaxSize = cacheMaxSize
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create mount options using global config
|
|
||||||
mountOpt := &mountlib.Options{
|
|
||||||
DebugFUSE: false,
|
|
||||||
AllowNonEmpty: true,
|
|
||||||
AllowOther: true,
|
|
||||||
Daemon: false,
|
|
||||||
AsyncRead: true,
|
|
||||||
DeviceName: fmt.Sprintf("decypharr-%s", m.Provider),
|
|
||||||
VolumeName: fmt.Sprintf("decypharr-%s", m.Provider),
|
|
||||||
}
|
|
||||||
|
|
||||||
if rcloneOpt.AttrTimeout != "" {
|
|
||||||
if attrTimeout, err := time.ParseDuration(rcloneOpt.AttrTimeout); err == nil {
|
|
||||||
mountOpt.AttrTimeout = fs.Duration(attrTimeout)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set cache dir
|
|
||||||
if rcloneOpt.CacheDir != "" {
|
|
||||||
cacheDir := filepath.Join(rcloneOpt.CacheDir, m.Provider)
|
|
||||||
if err := os.MkdirAll(cacheDir, 0755); err != nil {
|
|
||||||
// Log error but continue
|
|
||||||
m.logger.Error().Err(err).Msgf("Failed to create cache directory %s, using default cache", cacheDir)
|
|
||||||
}
|
|
||||||
if err := config.SetCacheDir(cacheDir); err != nil {
|
|
||||||
// Log error but continue
|
|
||||||
m.logger.Error().Err(err).Msgf("Failed to set cache directory %s, using default cache", cacheDir)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Create mount point using rclone's internal mounting
|
|
||||||
m.mountPoint = mountlib.NewMountPoint(mountfn, m.LocalPath, fsrc, mountOpt, vfsOpt)
|
|
||||||
|
|
||||||
// Start the mount
|
|
||||||
_, err = m.mountPoint.Mount()
|
|
||||||
if err != nil {
|
|
||||||
// Cleanup mount point if it failed
|
|
||||||
if m.mountPoint != nil && m.mountPoint.UnmountFn != nil {
|
|
||||||
if unmountErr := m.Unmount(); unmountErr != nil {
|
|
||||||
m.logger.Error().Err(unmountErr).Msgf("Failed to cleanup mount point %s after mount failure", m.LocalPath)
|
|
||||||
} else {
|
|
||||||
m.logger.Info().Msgf("Successfully cleaned up mount point %s after mount failure", m.LocalPath)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return fmt.Errorf("failed to mount %s at %s: %w", m.Provider, m.LocalPath, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Mount) Unmount() error {
|
|
||||||
if !m.mounted.Load() {
|
|
||||||
m.logger.Info().Msgf("Mount %s is not mounted, skipping unmount", m.Provider)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
m.mounted.Store(false)
|
|
||||||
|
|
||||||
m.logger.Debug().Msgf("Shutting down VFS for provider %s", m.Provider)
|
|
||||||
m.mountPoint.VFS.Shutdown()
|
|
||||||
if m.mountPoint == nil || m.mountPoint.UnmountFn == nil {
|
|
||||||
m.logger.Warn().Msgf("Mount point for provider %s is nil or unmount function is not set, skipping unmount", m.Provider)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := m.mountPoint.Unmount(); err != nil {
|
|
||||||
// Try to force unmount if normal unmount fails
|
|
||||||
if err := m.forceUnmount(); err != nil {
|
|
||||||
m.logger.Error().Err(err).Msgf("Failed to force unmount %s at %s", m.Provider, m.LocalPath)
|
|
||||||
return fmt.Errorf("failed to unmount %s at %s: %w", m.Provider, m.LocalPath, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Mount) forceUnmount() error {
|
|
||||||
switch runtime.GOOS {
|
|
||||||
case "linux", "darwin", "freebsd", "openbsd":
|
|
||||||
if err := m.tryUnmount("umount", m.LocalPath); err == nil {
|
|
||||||
m.logger.Info().Msgf("Successfully unmounted %s", m.LocalPath)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try lazy unmount
|
|
||||||
if err := m.tryUnmount("umount", "-l", m.LocalPath); err == nil {
|
|
||||||
m.logger.Info().Msgf("Successfully lazy unmounted %s", m.LocalPath)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := m.tryUnmount("fusermount", "-uz", m.LocalPath); err == nil {
|
|
||||||
m.logger.Info().Msgf("Successfully unmounted %s using fusermount3", m.LocalPath)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := m.tryUnmount("fusermount3", "-uz", m.LocalPath); err == nil {
|
|
||||||
m.logger.Info().Msgf("Successfully unmounted %s using fusermount3", m.LocalPath)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Errorf("all unmount attempts failed for %s", m.LocalPath)
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("force unmount not supported on %s", runtime.GOOS)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Mount) tryUnmount(command string, args ...string) error {
|
|
||||||
cmd := exec.Command(command, args...)
|
|
||||||
return cmd.Run()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Mount) isMountBusy() bool {
|
|
||||||
switch runtime.GOOS {
|
|
||||||
case "linux", "darwin", "freebsd", "openbsd":
|
|
||||||
// Check if the mount point is listed in /proc/mounts or mount output
|
|
||||||
cmd := exec.Command("mount")
|
|
||||||
output, err := cmd.Output()
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return strings.Contains(string(output), m.LocalPath)
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Mount) IsMounted() bool {
|
|
||||||
return m.mounted.Load() && m.mountPoint != nil && m.mountPoint.VFS != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Mount) RefreshDir(dirs []string) error {
|
|
||||||
if !m.IsMounted() {
|
|
||||||
return fmt.Errorf("provider %s not properly mounted. Skipping refreshes", m.Provider)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use atomic forget-and-refresh to avoid race conditions
|
|
||||||
return m.forceRefreshVFS(dirs)
|
|
||||||
}
|
|
||||||
|
|
||||||
// forceRefreshVFS atomically forgets and refreshes VFS directories to ensure immediate visibility
|
|
||||||
func (m *Mount) forceRefreshVFS(dirs []string) error {
|
|
||||||
vfsInstance := m.mountPoint.VFS
|
|
||||||
root, err := vfsInstance.Root()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to get VFS root for %s: %w", m.Provider, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
getDir := func(path string) (*vfs.Dir, error) {
|
|
||||||
path = strings.Trim(path, "/")
|
|
||||||
if path == "" {
|
|
||||||
return root, nil
|
|
||||||
}
|
|
||||||
segments := strings.Split(path, "/")
|
|
||||||
var node vfs.Node = root
|
|
||||||
for _, s := range segments {
|
|
||||||
if dir, ok := node.(*vfs.Dir); ok {
|
|
||||||
node, err = dir.Stat(s)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if dir, ok := node.(*vfs.Dir); ok {
|
|
||||||
return dir, nil
|
|
||||||
}
|
|
||||||
return nil, vfs.EINVAL
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no specific directories provided, work with root
|
|
||||||
if len(dirs) == 0 {
|
|
||||||
// Atomically forget and refresh root
|
|
||||||
root.ForgetAll()
|
|
||||||
if _, err := root.ReadDirAll(); err != nil {
|
|
||||||
return fmt.Errorf("failed to force-refresh root for %s: %w", m.Provider, err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var errs []error
|
|
||||||
// Process each directory atomically
|
|
||||||
for _, dir := range dirs {
|
|
||||||
if dir != "" {
|
|
||||||
dir = strings.Trim(dir, "/")
|
|
||||||
// Get the directory handle
|
|
||||||
vfsDir, err := getDir(dir)
|
|
||||||
if err != nil {
|
|
||||||
errs = append(errs, fmt.Errorf("failed to find directory '%s' for force-refresh in %s: %w", dir, m.Provider, err))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Atomically forget and refresh this specific directory
|
|
||||||
vfsDir.ForgetAll()
|
|
||||||
if _, err := vfsDir.ReadDirAll(); err != nil {
|
|
||||||
errs = append(errs, fmt.Errorf("failed to force-refresh directory '%s' in %s: %w", dir, m.Provider, err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(errs) > 0 {
|
|
||||||
return errors.Join(errs...)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
413
pkg/rclone/client.go
Normal file
413
pkg/rclone/client.go
Normal file
@@ -0,0 +1,413 @@
|
|||||||
|
package rclone
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/sirrobot01/decypharr/internal/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Mount creates a mount using the rclone RC API with retry logic
|
||||||
|
func (m *Manager) Mount(provider, webdavURL string) error {
|
||||||
|
return m.mountWithRetry(provider, webdavURL, 3)
|
||||||
|
}
|
||||||
|
|
||||||
|
// mountWithRetry attempts to mount with retry logic
|
||||||
|
func (m *Manager) mountWithRetry(provider, webdavURL string, maxRetries int) error {
|
||||||
|
if !m.IsReady() {
|
||||||
|
if err := m.WaitForReady(30 * time.Second); err != nil {
|
||||||
|
return fmt.Errorf("rclone RC server not ready: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for attempt := 0; attempt <= maxRetries; attempt++ {
|
||||||
|
if attempt > 0 {
|
||||||
|
// Wait before retry
|
||||||
|
wait := time.Duration(attempt*2) * time.Second
|
||||||
|
m.logger.Debug().
|
||||||
|
Int("attempt", attempt).
|
||||||
|
Str("provider", provider).
|
||||||
|
Msg("Retrying mount operation")
|
||||||
|
time.Sleep(wait)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := m.performMount(provider, webdavURL); err != nil {
|
||||||
|
m.logger.Error().
|
||||||
|
Err(err).
|
||||||
|
Str("provider", provider).
|
||||||
|
Int("attempt", attempt+1).
|
||||||
|
Msg("Mount attempt failed")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil // Success
|
||||||
|
}
|
||||||
|
return fmt.Errorf("mount failed for %s", provider)
|
||||||
|
}
|
||||||
|
|
||||||
|
// performMount performs a single mount attempt
|
||||||
|
func (m *Manager) performMount(provider, webdavURL string) error {
|
||||||
|
cfg := config.Get()
|
||||||
|
mountPath := filepath.Join(cfg.Rclone.MountPath, provider)
|
||||||
|
cacheDir := ""
|
||||||
|
if cfg.Rclone.CacheDir != "" {
|
||||||
|
cacheDir = filepath.Join(cfg.Rclone.CacheDir, provider)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create mount directory
|
||||||
|
if err := os.MkdirAll(mountPath, 0755); err != nil {
|
||||||
|
return fmt.Errorf("failed to create mount directory %s: %w", mountPath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if already mounted
|
||||||
|
m.mountsMutex.RLock()
|
||||||
|
existingMount, exists := m.mounts[provider]
|
||||||
|
m.mountsMutex.RUnlock()
|
||||||
|
|
||||||
|
if exists && existingMount.Mounted {
|
||||||
|
m.logger.Info().Str("provider", provider).Str("path", mountPath).Msg("Already mounted")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up any stale mount first
|
||||||
|
if exists && !existingMount.Mounted {
|
||||||
|
m.forceUnmountPath(mountPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create rclone config for this provider
|
||||||
|
configName := fmt.Sprintf("decypharr-%s", provider)
|
||||||
|
if err := m.createConfig(configName, webdavURL); err != nil {
|
||||||
|
return fmt.Errorf("failed to create rclone config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare mount arguments
|
||||||
|
mountArgs := map[string]interface{}{
|
||||||
|
"fs": fmt.Sprintf("%s:", configName),
|
||||||
|
"mountPoint": mountPath,
|
||||||
|
"mountType": "mount", // Use standard FUSE mount
|
||||||
|
"mountOpt": map[string]interface{}{
|
||||||
|
"AllowNonEmpty": true,
|
||||||
|
"AllowOther": true,
|
||||||
|
"DebugFUSE": false,
|
||||||
|
"DeviceName": fmt.Sprintf("decypharr-%s", provider),
|
||||||
|
"VolumeName": fmt.Sprintf("decypharr-%s", provider),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
configOpts := map[string]interface{}{
|
||||||
|
"BufferSize": cfg.Rclone.BufferSize,
|
||||||
|
}
|
||||||
|
|
||||||
|
if cacheDir != "" {
|
||||||
|
// Create cache directory if specified
|
||||||
|
if err := os.MkdirAll(cacheDir, 0755); err != nil {
|
||||||
|
m.logger.Warn().Str("cacheDir", cacheDir).Msg("Failed to create cache directory")
|
||||||
|
}
|
||||||
|
configOpts["CacheDir"] = cacheDir
|
||||||
|
}
|
||||||
|
|
||||||
|
mountArgs["_config"] = configOpts
|
||||||
|
|
||||||
|
// Add VFS options if caching is enabled
|
||||||
|
if cfg.Rclone.VfsCacheMode != "off" {
|
||||||
|
vfsOpt := map[string]interface{}{
|
||||||
|
"CacheMode": cfg.Rclone.VfsCacheMode,
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.Rclone.VfsCacheMaxAge != "" {
|
||||||
|
vfsOpt["CacheMaxAge"] = cfg.Rclone.VfsCacheMaxAge
|
||||||
|
}
|
||||||
|
if cfg.Rclone.VfsCacheMaxSize != "" {
|
||||||
|
vfsOpt["CacheMaxSize"] = cfg.Rclone.VfsCacheMaxSize
|
||||||
|
}
|
||||||
|
if cfg.Rclone.VfsCachePollInterval != "" {
|
||||||
|
vfsOpt["CachePollInterval"] = cfg.Rclone.VfsCachePollInterval
|
||||||
|
}
|
||||||
|
if cfg.Rclone.VfsReadChunkSize != "" {
|
||||||
|
vfsOpt["ChunkSize"] = cfg.Rclone.VfsReadChunkSize
|
||||||
|
}
|
||||||
|
if cfg.Rclone.VfsReadAhead != "" {
|
||||||
|
vfsOpt["ReadAhead"] = cfg.Rclone.VfsReadAhead
|
||||||
|
}
|
||||||
|
if cfg.Rclone.NoChecksum {
|
||||||
|
vfsOpt["NoChecksum"] = cfg.Rclone.NoChecksum
|
||||||
|
}
|
||||||
|
if cfg.Rclone.NoModTime {
|
||||||
|
vfsOpt["NoModTime"] = cfg.Rclone.NoModTime
|
||||||
|
}
|
||||||
|
|
||||||
|
mountArgs["vfsOpt"] = vfsOpt
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add mount options based on configuration
|
||||||
|
if cfg.Rclone.UID != 0 {
|
||||||
|
mountArgs["mountOpt"].(map[string]interface{})["UID"] = cfg.Rclone.UID
|
||||||
|
}
|
||||||
|
if cfg.Rclone.GID != 0 {
|
||||||
|
mountArgs["mountOpt"].(map[string]interface{})["GID"] = cfg.Rclone.GID
|
||||||
|
}
|
||||||
|
if cfg.Rclone.AttrTimeout != "" {
|
||||||
|
if attrTimeout, err := time.ParseDuration(cfg.Rclone.AttrTimeout); err == nil {
|
||||||
|
mountArgs["mountOpt"].(map[string]interface{})["AttrTimeout"] = attrTimeout.String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Make the mount request
|
||||||
|
req := RCRequest{
|
||||||
|
Command: "mount/mount",
|
||||||
|
Args: mountArgs,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := m.makeRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
// Clean up mount point on failure
|
||||||
|
m.forceUnmountPath(mountPath)
|
||||||
|
return fmt.Errorf("failed to create mount for %s: %w", provider, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store mount info
|
||||||
|
mountInfo := &MountInfo{
|
||||||
|
Provider: provider,
|
||||||
|
LocalPath: mountPath,
|
||||||
|
WebDAVURL: webdavURL,
|
||||||
|
Mounted: true,
|
||||||
|
MountedAt: time.Now().Format(time.RFC3339),
|
||||||
|
ConfigName: configName,
|
||||||
|
}
|
||||||
|
|
||||||
|
m.mountsMutex.Lock()
|
||||||
|
m.mounts[provider] = mountInfo
|
||||||
|
m.mountsMutex.Unlock()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmount unmounts a specific provider
|
||||||
|
func (m *Manager) Unmount(provider string) error {
|
||||||
|
return m.unmount(provider)
|
||||||
|
}
|
||||||
|
|
||||||
|
// unmount is the internal unmount function
|
||||||
|
func (m *Manager) unmount(provider string) error {
|
||||||
|
m.mountsMutex.RLock()
|
||||||
|
mountInfo, exists := m.mounts[provider]
|
||||||
|
m.mountsMutex.RUnlock()
|
||||||
|
|
||||||
|
if !exists || !mountInfo.Mounted {
|
||||||
|
m.logger.Info().Str("provider", provider).Msg("Mount not found or already unmounted")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
m.logger.Info().Str("provider", provider).Str("path", mountInfo.LocalPath).Msg("Unmounting")
|
||||||
|
|
||||||
|
// Try RC unmount first
|
||||||
|
req := RCRequest{
|
||||||
|
Command: "mount/unmount",
|
||||||
|
Args: map[string]interface{}{
|
||||||
|
"mountPoint": mountInfo.LocalPath,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var rcErr error
|
||||||
|
if m.IsReady() {
|
||||||
|
_, rcErr = m.makeRequest(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If RC unmount fails or server is not ready, try force unmount
|
||||||
|
if rcErr != nil {
|
||||||
|
m.logger.Warn().Err(rcErr).Str("provider", provider).Msg("RC unmount failed, trying force unmount")
|
||||||
|
if err := m.forceUnmountPath(mountInfo.LocalPath); err != nil {
|
||||||
|
m.logger.Error().Err(err).Str("provider", provider).Msg("Force unmount failed")
|
||||||
|
// Don't return error here, update the state anyway
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update mount info
|
||||||
|
m.mountsMutex.Lock()
|
||||||
|
if info, exists := m.mounts[provider]; exists {
|
||||||
|
info.Mounted = false
|
||||||
|
info.Error = ""
|
||||||
|
if rcErr != nil {
|
||||||
|
info.Error = rcErr.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m.mountsMutex.Unlock()
|
||||||
|
|
||||||
|
m.logger.Info().Str("provider", provider).Msg("Unmount completed")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmountAll unmounts all mounts
|
||||||
|
func (m *Manager) UnmountAll() error {
|
||||||
|
m.mountsMutex.RLock()
|
||||||
|
providers := make([]string, 0, len(m.mounts))
|
||||||
|
for provider, mount := range m.mounts {
|
||||||
|
if mount.Mounted {
|
||||||
|
providers = append(providers, provider)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m.mountsMutex.RUnlock()
|
||||||
|
|
||||||
|
var lastError error
|
||||||
|
for _, provider := range providers {
|
||||||
|
if err := m.unmount(provider); err != nil {
|
||||||
|
lastError = err
|
||||||
|
m.logger.Error().Err(err).Str("provider", provider).Msg("Failed to unmount")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lastError
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMountInfo returns information about a specific mount
|
||||||
|
func (m *Manager) GetMountInfo(provider string) (*MountInfo, bool) {
|
||||||
|
m.mountsMutex.RLock()
|
||||||
|
defer m.mountsMutex.RUnlock()
|
||||||
|
|
||||||
|
info, exists := m.mounts[provider]
|
||||||
|
if !exists {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a copy to avoid race conditions
|
||||||
|
mountInfo := *info
|
||||||
|
return &mountInfo, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllMounts returns information about all mounts
|
||||||
|
func (m *Manager) GetAllMounts() map[string]*MountInfo {
|
||||||
|
m.mountsMutex.RLock()
|
||||||
|
defer m.mountsMutex.RUnlock()
|
||||||
|
|
||||||
|
result := make(map[string]*MountInfo, len(m.mounts))
|
||||||
|
for provider, info := range m.mounts {
|
||||||
|
// Create a copy to avoid race conditions
|
||||||
|
mountInfo := *info
|
||||||
|
result[provider] = &mountInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsMounted checks if a provider is mounted
|
||||||
|
func (m *Manager) IsMounted(provider string) bool {
|
||||||
|
info, exists := m.GetMountInfo(provider)
|
||||||
|
return exists && info.Mounted
|
||||||
|
}
|
||||||
|
|
||||||
|
// RefreshDir refreshes directories in the VFS cache
|
||||||
|
func (m *Manager) RefreshDir(provider string, dirs []string) error {
|
||||||
|
if !m.IsReady() {
|
||||||
|
return fmt.Errorf("rclone RC server not ready")
|
||||||
|
}
|
||||||
|
|
||||||
|
mountInfo, exists := m.GetMountInfo(provider)
|
||||||
|
if !exists || !mountInfo.Mounted {
|
||||||
|
return fmt.Errorf("provider %s not mounted", provider)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no specific directories provided, refresh root
|
||||||
|
if len(dirs) == 0 {
|
||||||
|
dirs = []string{"/"}
|
||||||
|
}
|
||||||
|
args := map[string]interface{}{
|
||||||
|
"fs": fmt.Sprintf("decypharr-%s:", provider),
|
||||||
|
}
|
||||||
|
for i, dir := range dirs {
|
||||||
|
if dir != "" {
|
||||||
|
if i == 0 {
|
||||||
|
args["dir"] = dir
|
||||||
|
} else {
|
||||||
|
args[fmt.Sprintf("dir%d", i+1)] = dir
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
req := RCRequest{
|
||||||
|
Command: "vfs/forget",
|
||||||
|
Args: args,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := m.makeRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
m.logger.Error().Err(err).
|
||||||
|
Str("provider", provider).
|
||||||
|
Msg("Failed to refresh directory")
|
||||||
|
return fmt.Errorf("failed to refresh directory %s for provider %s: %w", dirs, provider, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req = RCRequest{
|
||||||
|
Command: "vfs/refresh",
|
||||||
|
Args: args,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = m.makeRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
m.logger.Error().Err(err).
|
||||||
|
Str("provider", provider).
|
||||||
|
Msg("Failed to refresh directory")
|
||||||
|
return fmt.Errorf("failed to refresh directory %s for provider %s: %w", dirs, provider, err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// createConfig creates an rclone config entry for the provider
|
||||||
|
func (m *Manager) createConfig(configName, webdavURL string) error {
|
||||||
|
req := RCRequest{
|
||||||
|
Command: "config/create",
|
||||||
|
Args: map[string]interface{}{
|
||||||
|
"name": configName,
|
||||||
|
"type": "webdav",
|
||||||
|
"parameters": map[string]interface{}{
|
||||||
|
"url": webdavURL,
|
||||||
|
"vendor": "other",
|
||||||
|
"pacer_min_sleep": "0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := m.makeRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create config %s: %w", configName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
m.logger.Trace().
|
||||||
|
Str("config_name", configName).
|
||||||
|
Str("webdav_url", webdavURL).
|
||||||
|
Msg("Rclone config created")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// forceUnmountPath attempts to force unmount a path using system commands
|
||||||
|
func (m *Manager) forceUnmountPath(mountPath string) error {
|
||||||
|
methods := [][]string{
|
||||||
|
{"umount", mountPath},
|
||||||
|
{"umount", "-l", mountPath}, // lazy unmount
|
||||||
|
{"fusermount", "-uz", mountPath},
|
||||||
|
{"fusermount3", "-uz", mountPath},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, method := range methods {
|
||||||
|
if err := m.tryUnmountCommand(method...); err == nil {
|
||||||
|
m.logger.Info().
|
||||||
|
Strs("command", method).
|
||||||
|
Str("path", mountPath).
|
||||||
|
Msg("Successfully unmounted using system command")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("all force unmount attempts failed for %s", mountPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// tryUnmountCommand tries to run an unmount command
|
||||||
|
func (m *Manager) tryUnmountCommand(args ...string) error {
|
||||||
|
if len(args) == 0 {
|
||||||
|
return fmt.Errorf("no command provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := exec.CommandContext(m.ctx, args[0], args[1:]...)
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
140
pkg/rclone/health.go
Normal file
140
pkg/rclone/health.go
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
package rclone
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HealthCheck performs comprehensive health checks on the rclone system
|
||||||
|
func (m *Manager) HealthCheck() error {
|
||||||
|
if !m.serverStarted {
|
||||||
|
return fmt.Errorf("rclone RC server is not started")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !m.IsReady() {
|
||||||
|
return fmt.Errorf("rclone RC server is not ready")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we can communicate with the server
|
||||||
|
if !m.pingServer() {
|
||||||
|
return fmt.Errorf("rclone RC server is not responding")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check mounts health
|
||||||
|
m.mountsMutex.RLock()
|
||||||
|
unhealthyMounts := make([]string, 0)
|
||||||
|
for provider, mount := range m.mounts {
|
||||||
|
if mount.Mounted && !m.checkMountHealth(provider) {
|
||||||
|
unhealthyMounts = append(unhealthyMounts, provider)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m.mountsMutex.RUnlock()
|
||||||
|
|
||||||
|
if len(unhealthyMounts) > 0 {
|
||||||
|
return fmt.Errorf("unhealthy mounts detected: %v", unhealthyMounts)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkMountHealth checks if a specific mount is healthy
|
||||||
|
func (m *Manager) checkMountHealth(provider string) bool {
|
||||||
|
// Try to list the root directory of the mount
|
||||||
|
req := RCRequest{
|
||||||
|
Command: "operations/list",
|
||||||
|
Args: map[string]interface{}{
|
||||||
|
"fs": fmt.Sprintf("decypharr-%s:", provider),
|
||||||
|
"remote": "/",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := m.makeRequest(req)
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RecoverMount attempts to recover a failed mount
|
||||||
|
func (m *Manager) RecoverMount(provider string) error {
|
||||||
|
m.mountsMutex.RLock()
|
||||||
|
mountInfo, exists := m.mounts[provider]
|
||||||
|
m.mountsMutex.RUnlock()
|
||||||
|
|
||||||
|
if !exists {
|
||||||
|
return fmt.Errorf("mount for provider %s does not exist", provider)
|
||||||
|
}
|
||||||
|
|
||||||
|
m.logger.Warn().Str("provider", provider).Msg("Attempting to recover mount")
|
||||||
|
|
||||||
|
// First try to unmount cleanly
|
||||||
|
if err := m.unmount(provider); err != nil {
|
||||||
|
m.logger.Error().Err(err).Str("provider", provider).Msg("Failed to unmount during recovery")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait a moment
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
|
||||||
|
// Try to remount
|
||||||
|
if err := m.Mount(provider, mountInfo.WebDAVURL); err != nil {
|
||||||
|
return fmt.Errorf("failed to recover mount for %s: %w", provider, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
m.logger.Info().Str("provider", provider).Msg("Successfully recovered mount")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MonitorMounts continuously monitors mount health and attempts recovery
|
||||||
|
func (m *Manager) MonitorMounts(ctx context.Context) {
|
||||||
|
if !m.serverStarted {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ticker := time.NewTicker(30 * time.Second) // Check every 30 seconds
|
||||||
|
defer ticker.Stop()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
m.logger.Debug().Msg("Mount monitoring stopped")
|
||||||
|
return
|
||||||
|
case <-ticker.C:
|
||||||
|
m.performMountHealthCheck()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// performMountHealthCheck checks and attempts to recover unhealthy mounts
|
||||||
|
func (m *Manager) performMountHealthCheck() {
|
||||||
|
if !m.IsReady() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
m.mountsMutex.RLock()
|
||||||
|
providers := make([]string, 0, len(m.mounts))
|
||||||
|
for provider, mount := range m.mounts {
|
||||||
|
if mount.Mounted {
|
||||||
|
providers = append(providers, provider)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m.mountsMutex.RUnlock()
|
||||||
|
|
||||||
|
for _, provider := range providers {
|
||||||
|
if !m.checkMountHealth(provider) {
|
||||||
|
m.logger.Warn().Str("provider", provider).Msg("Mount health check failed, attempting recovery")
|
||||||
|
|
||||||
|
// Mark mount as unhealthy
|
||||||
|
m.mountsMutex.Lock()
|
||||||
|
if mount, exists := m.mounts[provider]; exists {
|
||||||
|
mount.Error = "Health check failed"
|
||||||
|
mount.Mounted = false
|
||||||
|
}
|
||||||
|
m.mountsMutex.Unlock()
|
||||||
|
|
||||||
|
// Attempt recovery
|
||||||
|
go func(provider string) {
|
||||||
|
if err := m.RecoverMount(provider); err != nil {
|
||||||
|
m.logger.Error().Err(err).Str("provider", provider).Msg("Failed to recover mount")
|
||||||
|
}
|
||||||
|
}(provider)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
43
pkg/rclone/killed_unix.go
Normal file
43
pkg/rclone/killed_unix.go
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
//go:build !windows
|
||||||
|
|
||||||
|
package rclone
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"os/exec"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WasHardTerminated reports true iff the process was ended by SIGKILL or SIGTERM.
|
||||||
|
func WasHardTerminated(err error) bool {
|
||||||
|
var ee *exec.ExitError
|
||||||
|
if !errors.As(err, &ee) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
ws, ok := ee.Sys().(syscall.WaitStatus)
|
||||||
|
if !ok || !ws.Signaled() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
sig := ws.Signal()
|
||||||
|
return sig == syscall.SIGKILL || sig == syscall.SIGTERM
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExitCode returns the numeric exit code when available.
|
||||||
|
func ExitCode(err error) (int, bool) {
|
||||||
|
var ee *exec.ExitError
|
||||||
|
if !errors.As(err, &ee) {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
ws, ok := ee.Sys().(syscall.WaitStatus)
|
||||||
|
if !ok {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
if ws.Exited() {
|
||||||
|
return ws.ExitStatus(), true
|
||||||
|
}
|
||||||
|
// Conventional shell “killed by signal” code is 128 + signal.
|
||||||
|
if ws.Signaled() {
|
||||||
|
return 128 + int(ws.Signal()), true
|
||||||
|
}
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
35
pkg/rclone/killed_windows.go
Normal file
35
pkg/rclone/killed_windows.go
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package rclone
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"os/exec"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
func WasHardTerminated(err error) bool {
|
||||||
|
var ee *exec.ExitError
|
||||||
|
if !errors.As(err, &ee) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
ws, ok := ee.Sys().(syscall.WaitStatus)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// No Signaled() on Windows; consider "hard terminated" if not success.
|
||||||
|
return ws.ExitCode() != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExitCode returns the process exit code when available.
|
||||||
|
func ExitCode(err error) (int, bool) {
|
||||||
|
var ee *exec.ExitError
|
||||||
|
if !errors.As(err, &ee) {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
ws, ok := ee.Sys().(syscall.WaitStatus)
|
||||||
|
if !ok {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
return ws.ExitCode(), true
|
||||||
|
}
|
||||||
377
pkg/rclone/manager.go
Normal file
377
pkg/rclone/manager.go
Normal file
@@ -0,0 +1,377 @@
|
|||||||
|
package rclone
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
"github.com/sirrobot01/decypharr/internal/config"
|
||||||
|
"github.com/sirrobot01/decypharr/internal/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Manager handles the rclone RC server and provides mount operations
|
||||||
|
type Manager struct {
|
||||||
|
cmd *exec.Cmd
|
||||||
|
rcPort string
|
||||||
|
rcUser string
|
||||||
|
rcPass string
|
||||||
|
configDir string
|
||||||
|
mounts map[string]*MountInfo
|
||||||
|
mountsMutex sync.RWMutex
|
||||||
|
logger zerolog.Logger
|
||||||
|
ctx context.Context
|
||||||
|
cancel context.CancelFunc
|
||||||
|
httpClient *http.Client
|
||||||
|
serverReady chan struct{}
|
||||||
|
serverStarted bool
|
||||||
|
mu sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
type MountInfo struct {
|
||||||
|
Provider string `json:"provider"`
|
||||||
|
LocalPath string `json:"local_path"`
|
||||||
|
WebDAVURL string `json:"webdav_url"`
|
||||||
|
Mounted bool `json:"mounted"`
|
||||||
|
MountedAt string `json:"mounted_at,omitempty"`
|
||||||
|
ConfigName string `json:"config_name"`
|
||||||
|
Error string `json:"error,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RCRequest struct {
|
||||||
|
Command string `json:"command"`
|
||||||
|
Args map[string]interface{} `json:"args,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RCResponse struct {
|
||||||
|
Result interface{} `json:"result,omitempty"`
|
||||||
|
Error string `json:"error,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CoreStatsResponse struct {
|
||||||
|
TransferStats map[string]interface{} `json:"transferStats"`
|
||||||
|
CoreStats map[string]interface{} `json:"coreStats"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewManager creates a new rclone RC manager
|
||||||
|
func NewManager() *Manager {
|
||||||
|
cfg := config.Get()
|
||||||
|
|
||||||
|
rcPort := "5572"
|
||||||
|
configDir := filepath.Join(cfg.Path, "rclone")
|
||||||
|
|
||||||
|
// Ensure config directory exists
|
||||||
|
if err := os.MkdirAll(configDir, 0755); err != nil {
|
||||||
|
_logger := logger.New("rclone")
|
||||||
|
_logger.Error().Err(err).Msg("Failed to create rclone config directory")
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
|
return &Manager{
|
||||||
|
rcPort: rcPort,
|
||||||
|
configDir: configDir,
|
||||||
|
mounts: make(map[string]*MountInfo),
|
||||||
|
logger: logger.New("rclone"),
|
||||||
|
ctx: ctx,
|
||||||
|
cancel: cancel,
|
||||||
|
httpClient: &http.Client{Timeout: 30 * time.Second},
|
||||||
|
serverReady: make(chan struct{}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start starts the rclone RC server
|
||||||
|
func (m *Manager) Start(ctx context.Context) error {
|
||||||
|
m.mu.Lock()
|
||||||
|
defer m.mu.Unlock()
|
||||||
|
|
||||||
|
if m.serverStarted {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := config.Get()
|
||||||
|
if !cfg.Rclone.Enabled {
|
||||||
|
m.logger.Info().Msg("Rclone is disabled, skipping RC server startup")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
args := []string{
|
||||||
|
"rcd",
|
||||||
|
"--rc-addr", ":" + m.rcPort,
|
||||||
|
"--rc-no-auth", // We'll handle auth at the application level
|
||||||
|
"--config", filepath.Join(m.configDir, "rclone.conf"),
|
||||||
|
"--log-level", "INFO",
|
||||||
|
}
|
||||||
|
m.cmd = exec.CommandContext(ctx, "rclone", args...)
|
||||||
|
m.cmd.Dir = m.configDir
|
||||||
|
|
||||||
|
// Capture output for debugging
|
||||||
|
var stdout, stderr bytes.Buffer
|
||||||
|
m.cmd.Stdout = &stdout
|
||||||
|
m.cmd.Stderr = &stderr
|
||||||
|
|
||||||
|
if err := m.cmd.Start(); err != nil {
|
||||||
|
return fmt.Errorf("failed to start rclone RC server: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
m.serverStarted = true
|
||||||
|
|
||||||
|
// Wait for server to be ready in a goroutine
|
||||||
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
m.logger.Error().Interface("panic", r).Msg("Panic in rclone RC server monitor")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
m.waitForServer()
|
||||||
|
close(m.serverReady)
|
||||||
|
|
||||||
|
// Start mount monitoring once server is ready
|
||||||
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
m.logger.Error().Interface("panic", r).Msg("Panic in mount monitor")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
m.MonitorMounts(ctx)
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Wait for command to finish and log output
|
||||||
|
err := m.cmd.Wait()
|
||||||
|
switch {
|
||||||
|
case err == nil:
|
||||||
|
m.logger.Info().Msg("Rclone RC server exited normally")
|
||||||
|
|
||||||
|
case errors.Is(err, context.Canceled):
|
||||||
|
m.logger.Info().Msg("Rclone RC server terminated: context canceled")
|
||||||
|
|
||||||
|
case WasHardTerminated(err): // SIGKILL on *nix; non-zero exit on Windows
|
||||||
|
m.logger.Info().Msg("Rclone RC server hard-terminated")
|
||||||
|
|
||||||
|
default:
|
||||||
|
if code, ok := ExitCode(err); ok {
|
||||||
|
m.logger.Debug().Int("exit_code", code).Err(err).
|
||||||
|
Msg("Rclone RC server error")
|
||||||
|
} else {
|
||||||
|
m.logger.Debug().Err(err).Msg("Rclone RC server error (no exit code)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop stops the rclone RC server and unmounts all mounts
|
||||||
|
func (m *Manager) Stop() error {
|
||||||
|
m.mu.Lock()
|
||||||
|
defer m.mu.Unlock()
|
||||||
|
|
||||||
|
if !m.serverStarted {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
m.logger.Info().Msg("Stopping rclone RC server")
|
||||||
|
|
||||||
|
// Unmount all mounts first
|
||||||
|
m.mountsMutex.RLock()
|
||||||
|
mountList := make([]*MountInfo, 0, len(m.mounts))
|
||||||
|
for _, mount := range m.mounts {
|
||||||
|
if mount.Mounted {
|
||||||
|
mountList = append(mountList, mount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m.mountsMutex.RUnlock()
|
||||||
|
|
||||||
|
// Unmount in parallel
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
for _, mount := range mountList {
|
||||||
|
wg.Add(1)
|
||||||
|
go func(mount *MountInfo) {
|
||||||
|
defer wg.Done()
|
||||||
|
if err := m.unmount(mount.Provider); err != nil {
|
||||||
|
m.logger.Error().Err(err).Str("provider", mount.Provider).Msg("Failed to unmount during shutdown")
|
||||||
|
}
|
||||||
|
}(mount)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for unmounts with timeout
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
wg.Wait()
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
m.logger.Info().Msg("All mounts unmounted successfully")
|
||||||
|
case <-time.After(30 * time.Second):
|
||||||
|
m.logger.Warn().Msg("Timeout waiting for mounts to unmount, proceeding with shutdown")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cancel context and stop process
|
||||||
|
m.cancel()
|
||||||
|
|
||||||
|
if m.cmd != nil && m.cmd.Process != nil {
|
||||||
|
// Try graceful shutdown first
|
||||||
|
if err := m.cmd.Process.Signal(os.Interrupt); err != nil {
|
||||||
|
m.logger.Warn().Err(err).Msg("Failed to send interrupt signal, using kill")
|
||||||
|
if killErr := m.cmd.Process.Kill(); killErr != nil {
|
||||||
|
m.logger.Error().Err(killErr).Msg("Failed to kill rclone process")
|
||||||
|
return killErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for process to exit with timeout
|
||||||
|
done := make(chan error, 1)
|
||||||
|
go func() {
|
||||||
|
done <- m.cmd.Wait()
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case err := <-done:
|
||||||
|
if err != nil && !errors.Is(err, context.Canceled) && !WasHardTerminated(err) {
|
||||||
|
m.logger.Warn().Err(err).Msg("Rclone process exited with error")
|
||||||
|
}
|
||||||
|
case <-time.After(10 * time.Second):
|
||||||
|
m.logger.Warn().Msg("Timeout waiting for rclone to exit, force killing")
|
||||||
|
if err := m.cmd.Process.Kill(); err != nil {
|
||||||
|
m.logger.Error().Err(err).Msg("Failed to force kill rclone process")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Wait a bit more for the kill to take effect
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
m.logger.Info().Msg("Rclone process killed successfully")
|
||||||
|
case <-time.After(5 * time.Second):
|
||||||
|
m.logger.Error().Msg("Process may still be running after kill")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up any remaining mount directories
|
||||||
|
cfg := config.Get()
|
||||||
|
if cfg.Rclone.MountPath != "" {
|
||||||
|
m.cleanupMountDirectories(cfg.Rclone.MountPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
m.serverStarted = false
|
||||||
|
m.logger.Info().Msg("Rclone RC server stopped")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// cleanupMountDirectories removes empty mount directories
|
||||||
|
func (m *Manager) cleanupMountDirectories(_ string) {
|
||||||
|
m.mountsMutex.RLock()
|
||||||
|
defer m.mountsMutex.RUnlock()
|
||||||
|
|
||||||
|
for _, mount := range m.mounts {
|
||||||
|
if mount.LocalPath != "" {
|
||||||
|
// Try to remove the directory if it's empty
|
||||||
|
if err := os.Remove(mount.LocalPath); err == nil {
|
||||||
|
m.logger.Debug().Str("path", mount.LocalPath).Msg("Removed empty mount directory")
|
||||||
|
}
|
||||||
|
// Don't log errors here as the directory might not be empty, which is fine
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// waitForServer waits for the RC server to become available
|
||||||
|
func (m *Manager) waitForServer() {
|
||||||
|
maxAttempts := 30
|
||||||
|
for i := 0; i < maxAttempts; i++ {
|
||||||
|
if m.ctx.Err() != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.pingServer() {
|
||||||
|
m.logger.Info().Msg("Rclone RC server is ready")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
m.logger.Error().Msg("Rclone RC server not responding - mount operations will be disabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
// pingServer checks if the RC server is responding
|
||||||
|
func (m *Manager) pingServer() bool {
|
||||||
|
req := RCRequest{Command: "core/version"}
|
||||||
|
_, err := m.makeRequest(req)
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// makeRequest makes a request to the rclone RC server
|
||||||
|
func (m *Manager) makeRequest(req RCRequest) (*RCResponse, error) {
|
||||||
|
reqBody, err := json.Marshal(req.Args)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to marshal request: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
url := fmt.Sprintf("http://localhost:%s/%s", m.rcPort, req.Command)
|
||||||
|
httpReq, err := http.NewRequestWithContext(m.ctx, "POST", url, bytes.NewBuffer(reqBody))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create request: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
httpReq.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
resp, err := m.httpClient.Do(httpReq)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to make request: %w", err)
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if err := resp.Body.Close(); err != nil {
|
||||||
|
m.logger.Debug().Err(err).Msg("Failed to close response body")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
var rcResp RCResponse
|
||||||
|
if err := json.NewDecoder(resp.Body).Decode(&rcResp); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to decode response: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rcResp.Error != "" {
|
||||||
|
return nil, fmt.Errorf("rclone error: %s", rcResp.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return nil, fmt.Errorf("unexpected status code: %d - %s", resp.StatusCode, http.StatusText(resp.StatusCode))
|
||||||
|
}
|
||||||
|
|
||||||
|
return &rcResp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsReady returns true if the RC server is ready
|
||||||
|
func (m *Manager) IsReady() bool {
|
||||||
|
select {
|
||||||
|
case <-m.serverReady:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WaitForReady waits for the RC server to be ready
|
||||||
|
func (m *Manager) WaitForReady(timeout time.Duration) error {
|
||||||
|
select {
|
||||||
|
case <-m.serverReady:
|
||||||
|
return nil
|
||||||
|
case <-time.After(timeout):
|
||||||
|
return fmt.Errorf("timeout waiting for rclone RC server to be ready")
|
||||||
|
case <-m.ctx.Done():
|
||||||
|
return m.ctx.Err()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Manager) GetLogger() zerolog.Logger {
|
||||||
|
return m.logger
|
||||||
|
}
|
||||||
120
pkg/rclone/mount.go
Normal file
120
pkg/rclone/mount.go
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
package rclone
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
"github.com/sirrobot01/decypharr/internal/config"
|
||||||
|
"net/url"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Mount represents a mount using the rclone RC client
|
||||||
|
type Mount struct {
|
||||||
|
Provider string
|
||||||
|
LocalPath string
|
||||||
|
WebDAVURL string
|
||||||
|
logger zerolog.Logger
|
||||||
|
rcManager *Manager
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMount creates a new RC-based mount
|
||||||
|
func NewMount(provider, webdavURL string, rcManager *Manager) *Mount {
|
||||||
|
cfg := config.Get()
|
||||||
|
mountPath := filepath.Join(cfg.Rclone.MountPath, provider)
|
||||||
|
|
||||||
|
_url, err := url.JoinPath(webdavURL, provider)
|
||||||
|
if err != nil {
|
||||||
|
_url = fmt.Sprintf("%s/%s", webdavURL, provider)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Mount{
|
||||||
|
Provider: provider,
|
||||||
|
LocalPath: mountPath,
|
||||||
|
WebDAVURL: _url,
|
||||||
|
rcManager: rcManager,
|
||||||
|
logger: rcManager.GetLogger(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mount creates the mount using rclone RC
|
||||||
|
func (m *Mount) Mount(ctx context.Context) error {
|
||||||
|
if m.rcManager == nil {
|
||||||
|
return fmt.Errorf("rclone manager is not available")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if already mounted
|
||||||
|
if m.rcManager.IsMounted(m.Provider) {
|
||||||
|
m.logger.Info().Msgf("Mount %s is already mounted at %s", m.Provider, m.LocalPath)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
m.logger.Info().
|
||||||
|
Str("provider", m.Provider).
|
||||||
|
Str("webdav_url", m.WebDAVURL).
|
||||||
|
Str("mount_path", m.LocalPath).
|
||||||
|
Msg("Creating mount via RC")
|
||||||
|
|
||||||
|
if err := m.rcManager.Mount(m.Provider, m.WebDAVURL); err != nil {
|
||||||
|
m.logger.Error().Str("provider", m.Provider).Msg("Mount operation failed")
|
||||||
|
return fmt.Errorf("mount failed for %s", m.Provider)
|
||||||
|
}
|
||||||
|
|
||||||
|
m.logger.Info().Msgf("Successfully mounted %s WebDAV at %s via RC", m.Provider, m.LocalPath)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmount removes the mount using rclone RC
|
||||||
|
func (m *Mount) Unmount() error {
|
||||||
|
if m.rcManager == nil {
|
||||||
|
m.logger.Warn().Msg("Rclone manager is not available, skipping unmount")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if !m.rcManager.IsMounted(m.Provider) {
|
||||||
|
m.logger.Info().Msgf("Mount %s is not mounted, skipping unmount", m.Provider)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
m.logger.Info().Str("provider", m.Provider).Msg("Unmounting via RC")
|
||||||
|
|
||||||
|
if err := m.rcManager.Unmount(m.Provider); err != nil {
|
||||||
|
return fmt.Errorf("failed to unmount %s via RC: %w", m.Provider, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
m.logger.Info().Msgf("Successfully unmounted %s", m.Provider)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsMounted checks if the mount is active via RC
|
||||||
|
func (m *Mount) IsMounted() bool {
|
||||||
|
if m.rcManager == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return m.rcManager.IsMounted(m.Provider)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RefreshDir refreshes directories in the mount
|
||||||
|
func (m *Mount) RefreshDir(dirs []string) error {
|
||||||
|
if m.rcManager == nil {
|
||||||
|
return fmt.Errorf("rclone manager is not available")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !m.IsMounted() {
|
||||||
|
return fmt.Errorf("provider %s not properly mounted. Skipping refreshes", m.Provider)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := m.rcManager.RefreshDir(m.Provider, dirs); err != nil {
|
||||||
|
return fmt.Errorf("failed to refresh directories for %s: %w", m.Provider, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMountInfo returns mount information
|
||||||
|
func (m *Mount) GetMountInfo() (*MountInfo, bool) {
|
||||||
|
if m.rcManager == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
return m.rcManager.GetMountInfo(m.Provider)
|
||||||
|
}
|
||||||
136
pkg/rclone/stats.go
Normal file
136
pkg/rclone/stats.go
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
package rclone
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Stats represents rclone statistics
|
||||||
|
type Stats struct {
|
||||||
|
CoreStats map[string]interface{} `json:"coreStats"`
|
||||||
|
TransferStats map[string]interface{} `json:"transferStats"`
|
||||||
|
MountStats map[string]*MountInfo `json:"mountStats"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetStats retrieves statistics from the rclone RC server
|
||||||
|
func (m *Manager) GetStats() (*Stats, error) {
|
||||||
|
if !m.IsReady() {
|
||||||
|
return nil, fmt.Errorf("rclone RC server not ready")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get core stats
|
||||||
|
req := RCRequest{
|
||||||
|
Command: "core/stats",
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := m.makeRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get rclone stats: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the response
|
||||||
|
var coreStatsResp CoreStatsResponse
|
||||||
|
if respBytes, err := json.Marshal(resp.Result); err == nil {
|
||||||
|
json.Unmarshal(respBytes, &coreStatsResp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get mount stats
|
||||||
|
mountStats := m.GetAllMounts()
|
||||||
|
|
||||||
|
stats := &Stats{
|
||||||
|
CoreStats: coreStatsResp.CoreStats,
|
||||||
|
TransferStats: coreStatsResp.TransferStats,
|
||||||
|
MountStats: mountStats,
|
||||||
|
}
|
||||||
|
|
||||||
|
return stats, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMemoryUsage returns memory usage statistics
|
||||||
|
func (m *Manager) GetMemoryUsage() (map[string]interface{}, error) {
|
||||||
|
if !m.IsReady() {
|
||||||
|
return nil, fmt.Errorf("rclone RC server not ready")
|
||||||
|
}
|
||||||
|
|
||||||
|
req := RCRequest{
|
||||||
|
Command: "core/memstats",
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := m.makeRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get memory stats: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if memStats, ok := resp.Result.(map[string]interface{}); ok {
|
||||||
|
return memStats, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("invalid memory stats response")
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBandwidthStats returns bandwidth usage for all transfers
|
||||||
|
func (m *Manager) GetBandwidthStats() (map[string]interface{}, error) {
|
||||||
|
if !m.IsReady() {
|
||||||
|
return nil, fmt.Errorf("rclone RC server not ready")
|
||||||
|
}
|
||||||
|
|
||||||
|
req := RCRequest{
|
||||||
|
Command: "core/bwlimit",
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := m.makeRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
// Bandwidth stats might not be available, return empty
|
||||||
|
return map[string]interface{}{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if bwStats, ok := resp.Result.(map[string]interface{}); ok {
|
||||||
|
return bwStats, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]interface{}{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetVersion returns rclone version information
|
||||||
|
func (m *Manager) GetVersion() (map[string]interface{}, error) {
|
||||||
|
if !m.IsReady() {
|
||||||
|
return nil, fmt.Errorf("rclone RC server not ready")
|
||||||
|
}
|
||||||
|
|
||||||
|
req := RCRequest{
|
||||||
|
Command: "core/version",
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := m.makeRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get version: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if version, ok := resp.Result.(map[string]interface{}); ok {
|
||||||
|
return version, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("invalid version response")
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetConfigDump returns the current rclone configuration
|
||||||
|
func (m *Manager) GetConfigDump() (map[string]interface{}, error) {
|
||||||
|
if !m.IsReady() {
|
||||||
|
return nil, fmt.Errorf("rclone RC server not ready")
|
||||||
|
}
|
||||||
|
|
||||||
|
req := RCRequest{
|
||||||
|
Command: "config/dump",
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := m.makeRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get config dump: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if config, ok := resp.Result.(map[string]interface{}); ok {
|
||||||
|
return config, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("invalid config dump response")
|
||||||
|
}
|
||||||
@@ -118,5 +118,45 @@ func (s *Server) handleStats(w http.ResponseWriter, r *http.Request) {
|
|||||||
profiles = append(profiles, profile)
|
profiles = append(profiles, profile)
|
||||||
}
|
}
|
||||||
stats["debrids"] = profiles
|
stats["debrids"] = profiles
|
||||||
|
|
||||||
|
// Add rclone stats if available
|
||||||
|
if rcManager := store.Get().RcloneManager(); rcManager != nil && rcManager.IsReady() {
|
||||||
|
if rcStats, err := rcManager.GetStats(); err == nil {
|
||||||
|
stats["rclone"] = map[string]interface{}{
|
||||||
|
"enabled": true,
|
||||||
|
"server_ready": rcManager.IsReady(),
|
||||||
|
"core_stats": rcStats.CoreStats,
|
||||||
|
"transfer_stats": rcStats.TransferStats,
|
||||||
|
"mount_stats": rcStats.MountStats,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add memory usage
|
||||||
|
if memStats, err := rcManager.GetMemoryUsage(); err == nil {
|
||||||
|
stats["rclone"].(map[string]interface{})["memory_stats"] = memStats
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add version info
|
||||||
|
if version, err := rcManager.GetVersion(); err == nil {
|
||||||
|
stats["rclone"].(map[string]interface{})["version"] = version
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add bandwidth stats
|
||||||
|
if bwStats, err := rcManager.GetBandwidthStats(); err == nil {
|
||||||
|
stats["rclone"].(map[string]interface{})["bandwidth_stats"] = bwStats
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
stats["rclone"] = map[string]interface{}{
|
||||||
|
"enabled": true,
|
||||||
|
"server_ready": rcManager.IsReady(),
|
||||||
|
"error": err.Error(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
stats["rclone"] = map[string]interface{}{
|
||||||
|
"enabled": false,
|
||||||
|
"server_ready": false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
request.JSONResponse(w, stats, http.StatusOK)
|
request.JSONResponse(w, stats, http.StatusOK)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/sirrobot01/decypharr/internal/logger"
|
"github.com/sirrobot01/decypharr/internal/logger"
|
||||||
"github.com/sirrobot01/decypharr/pkg/arr"
|
"github.com/sirrobot01/decypharr/pkg/arr"
|
||||||
"github.com/sirrobot01/decypharr/pkg/debrid"
|
"github.com/sirrobot01/decypharr/pkg/debrid"
|
||||||
|
"github.com/sirrobot01/decypharr/pkg/rclone"
|
||||||
"github.com/sirrobot01/decypharr/pkg/repair"
|
"github.com/sirrobot01/decypharr/pkg/repair"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@@ -17,6 +18,7 @@ type Store struct {
|
|||||||
repair *repair.Repair
|
repair *repair.Repair
|
||||||
arr *arr.Storage
|
arr *arr.Storage
|
||||||
debrid *debrid.Storage
|
debrid *debrid.Storage
|
||||||
|
rcloneManager *rclone.Manager
|
||||||
importsQueue *ImportQueue // Queued import requests(probably from too_many_active_downloads)
|
importsQueue *ImportQueue // Queued import requests(probably from too_many_active_downloads)
|
||||||
torrents *TorrentStorage
|
torrents *TorrentStorage
|
||||||
logger zerolog.Logger
|
logger zerolog.Logger
|
||||||
@@ -34,15 +36,24 @@ var (
|
|||||||
// Get returns the singleton instance
|
// Get returns the singleton instance
|
||||||
func Get() *Store {
|
func Get() *Store {
|
||||||
once.Do(func() {
|
once.Do(func() {
|
||||||
arrs := arr.NewStorage()
|
|
||||||
deb := debrid.NewStorage()
|
|
||||||
cfg := config.Get()
|
cfg := config.Get()
|
||||||
qbitCfg := cfg.QBitTorrent
|
qbitCfg := cfg.QBitTorrent
|
||||||
|
|
||||||
|
// Create rclone manager if enabled
|
||||||
|
var rcManager *rclone.Manager
|
||||||
|
if cfg.Rclone.Enabled {
|
||||||
|
rcManager = rclone.NewManager()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create services with dependencies
|
||||||
|
arrs := arr.NewStorage()
|
||||||
|
deb := debrid.NewStorage(rcManager)
|
||||||
|
|
||||||
instance = &Store{
|
instance = &Store{
|
||||||
repair: repair.New(arrs, deb),
|
repair: repair.New(arrs, deb),
|
||||||
arr: arrs,
|
arr: arrs,
|
||||||
debrid: deb,
|
debrid: deb,
|
||||||
|
rcloneManager: rcManager,
|
||||||
torrents: newTorrentStorage(cfg.TorrentsFile()),
|
torrents: newTorrentStorage(cfg.TorrentsFile()),
|
||||||
logger: logger.Default(), // Use default logger [decypharr]
|
logger: logger.Default(), // Use default logger [decypharr]
|
||||||
refreshInterval: time.Duration(cmp.Or(qbitCfg.RefreshInterval, 10)) * time.Minute,
|
refreshInterval: time.Duration(cmp.Or(qbitCfg.RefreshInterval, 10)) * time.Minute,
|
||||||
@@ -66,6 +77,10 @@ func Reset() {
|
|||||||
instance.debrid.Reset()
|
instance.debrid.Reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if instance.rcloneManager != nil {
|
||||||
|
instance.rcloneManager.Stop()
|
||||||
|
}
|
||||||
|
|
||||||
if instance.importsQueue != nil {
|
if instance.importsQueue != nil {
|
||||||
instance.importsQueue.Close()
|
instance.importsQueue.Close()
|
||||||
}
|
}
|
||||||
@@ -90,3 +105,6 @@ func (s *Store) Repair() *repair.Repair {
|
|||||||
func (s *Store) Torrents() *TorrentStorage {
|
func (s *Store) Torrents() *TorrentStorage {
|
||||||
return s.torrents
|
return s.torrents
|
||||||
}
|
}
|
||||||
|
func (s *Store) RcloneManager() *rclone.Manager {
|
||||||
|
return s.rcloneManager
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user