From aa0affb0191713732b454c37d19047af480d349c Mon Sep 17 00:00:00 2001 From: royalcat Date: Sat, 19 Oct 2024 04:24:14 +0300 Subject: [PATCH] qbittorrent source files --- cmd/tstor/main.go | 14 +- go.mod | 24 +- go.sum | 44 +- graphql/query.graphql | 1 + graphql/sources/qbittorrent_query.graphql | 3 + graphql/sources/qbittorrent_types.graphql | 5 + src/delivery/graphql/generated.go | 1258 +++++++++++++++-- src/delivery/graphql/model/models_gen.go | 10 + src/delivery/graphql/resolver/fs.resolvers.go | 2 +- .../graphql/resolver/mutation.resolvers.go | 4 +- .../resolver/qbittorrent_query.resolvers.go | 38 + .../resolver/qbittorrent_types.resolvers.go | 22 + .../graphql/resolver/query.resolvers.go | 7 +- src/delivery/graphql/resolver/resolver.go | 8 +- .../resolver/subscription.resolvers.go | 4 +- .../resolver/torrent_mutation.resolvers.go | 14 +- .../resolver/torrent_query.resolvers.go | 13 +- .../resolver/torrent_types.resolvers.go | 2 +- src/delivery/http.go | 5 +- src/delivery/router.go | 13 +- src/sources/qbittorrent/api.go | 27 + src/sources/qbittorrent/daemon.go | 30 +- src/sources/qbittorrent/fs.go | 1 + src/sources/storage.go | 4 +- src/sources/torrent/fs.go | 2 +- src/sources/ytdlp/daemon.go | 2 +- src/vfs/archive.go | 6 +- src/vfs/log.go | 2 +- src/vfs/resolver.go | 6 +- ui/lib/api/schema.graphql | 9 + 30 files changed, 1338 insertions(+), 242 deletions(-) create mode 100644 graphql/sources/qbittorrent_query.graphql create mode 100644 graphql/sources/qbittorrent_types.graphql create mode 100644 src/delivery/graphql/resolver/qbittorrent_query.resolvers.go create mode 100644 src/delivery/graphql/resolver/qbittorrent_types.resolvers.go create mode 100644 src/sources/qbittorrent/api.go diff --git a/cmd/tstor/main.go b/cmd/tstor/main.go index 0054e2d..96e922e 100644 --- a/cmd/tstor/main.go +++ b/cmd/tstor/main.go @@ -17,6 +17,7 @@ import ( wnfs "git.kmsign.ru/royalcat/tstor/pkg/go-nfs" "git.kmsign.ru/royalcat/tstor/pkg/rlog" "git.kmsign.ru/royalcat/tstor/src/config" + "git.kmsign.ru/royalcat/tstor/src/delivery" "git.kmsign.ru/royalcat/tstor/src/sources" "git.kmsign.ru/royalcat/tstor/src/sources/qbittorrent" "git.kmsign.ru/royalcat/tstor/src/sources/ytdlp" @@ -103,14 +104,14 @@ func run(configPath string) error { return err } - qtsrv, err := qbittorrent.NewDaemon(conf.Sources.QBittorrent) + qtdaemon, err := qbittorrent.NewDaemon(conf.Sources.QBittorrent) if err != nil { return fmt.Errorf("error creating qbittorrent daemon: %w", err) } sfs := sources.NewHostedFS( vfs.NewCtxBillyFs("/", ctxbilly.WrapFileSystem(sourceFs)), - qtsrv, ytdlpsrv, + qtdaemon, ytdlpsrv, ) sfs, err = vfs.WrapLogFS(sfs) if err != nil { @@ -187,12 +188,19 @@ func run(configPath string) error { } }() + go func() { + err := delivery.Run(nil, qtdaemon, sfs, conf) + if err != nil { + log.Error(ctx, "error initializing HTTP server", rlog.Error(err)) + } + }() + sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) <-sigChan return errors.Join( // tsrv.Close(ctx), - qtsrv.Close(ctx), + qtdaemon.Close(ctx), ) } diff --git a/go.mod b/go.mod index 20e0ac0..71a90d4 100644 --- a/go.mod +++ b/go.mod @@ -1,11 +1,11 @@ module git.kmsign.ru/royalcat/tstor -go 1.22.3 +go 1.23 replace github.com/iceber/iouring-go => github.com/royalcat/iouring-go v0.0.0-20240925200811-286062ac1b23 require ( - github.com/99designs/gqlgen v0.17.49 + github.com/99designs/gqlgen v0.17.55 github.com/agoda-com/opentelemetry-go/otelslog v0.1.1 github.com/agoda-com/opentelemetry-logs-go v0.5.0 github.com/anacrolix/dht/v2 v2.21.1 @@ -45,8 +45,8 @@ require ( github.com/samber/slog-multi v1.0.2 github.com/samber/slog-zerolog v1.0.0 github.com/stretchr/testify v1.9.0 - github.com/urfave/cli/v2 v2.27.2 - github.com/vektah/gqlparser/v2 v2.5.16 + github.com/urfave/cli/v2 v2.27.4 + github.com/vektah/gqlparser/v2 v2.5.17 github.com/willscott/go-nfs-client v0.0.0-20240104095149-b44639837b00 github.com/willscott/memphis v0.0.0-20210922141505-529d4987ab7e go.opentelemetry.io/otel v1.28.0 @@ -58,9 +58,9 @@ require ( go.opentelemetry.io/otel/sdk/metric v1.28.0 go.opentelemetry.io/otel/trace v1.28.0 golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 - golang.org/x/net v0.26.0 - golang.org/x/sync v0.7.0 - golang.org/x/sys v0.22.0 + golang.org/x/net v0.29.0 + golang.org/x/sync v0.8.0 + golang.org/x/sys v0.25.0 ) require ( @@ -171,18 +171,18 @@ require ( github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect github.com/warpfork/go-errcat v0.0.0-20180917083543-335044ffc86e // indirect - github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 // indirect + github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect go.etcd.io/bbolt v1.3.9 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib v1.26.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect go.opentelemetry.io/proto/otlp v1.3.1 // indirect go4.org v0.0.0-20230225012048-214862532bf5 // indirect - golang.org/x/crypto v0.24.0 // indirect - golang.org/x/mod v0.18.0 // indirect - golang.org/x/text v0.16.0 // indirect + golang.org/x/crypto v0.27.0 // indirect + golang.org/x/mod v0.20.0 // indirect + golang.org/x/text v0.18.0 // indirect golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.22.0 // indirect + golang.org/x/tools v0.24.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect google.golang.org/grpc v1.64.0 // indirect diff --git a/go.sum b/go.sum index 6e2ead2..cc08524 100644 --- a/go.sum +++ b/go.sum @@ -19,8 +19,8 @@ crawshaw.io/sqlite v0.3.2/go.mod h1:igAO5JulrQ1DbdZdtVq48mnZUBAPOeFzer7VhDWNtW4= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU= filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= -github.com/99designs/gqlgen v0.17.49 h1:b3hNGexHd33fBSAd4NDT/c3NCcQzcAVkknhN9ym36YQ= -github.com/99designs/gqlgen v0.17.49/go.mod h1:tC8YFVZMed81x7UJ7ORUwXF4Kn6SXuucFqQBhN8+BU0= +github.com/99designs/gqlgen v0.17.55 h1:3vzrNWYyzSZjGDFo68e5j9sSauLxfKvLp+6ioRokVtM= +github.com/99designs/gqlgen v0.17.55/go.mod h1:3Bq768f8hgVPGZxL8aY9MaYmbxa6llPM/qu1IGH1EJo= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= @@ -597,14 +597,14 @@ github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDW github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc= github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/cli/v2 v2.27.2 h1:6e0H+AkS+zDckwPCUrZkKX38mRaau4nL2uipkJpbkcI= -github.com/urfave/cli/v2 v2.27.2/go.mod h1:g0+79LmHHATl7DAcHO99smiR/T7uGLw84w8Y42x+4eM= +github.com/urfave/cli/v2 v2.27.4 h1:o1owoI+02Eb+K107p27wEX9Bb8eqIoZCfLXloLUSWJ8= +github.com/urfave/cli/v2 v2.27.4/go.mod h1:m4QzxcD2qpra4z7WhzEGn74WZLViBnMpb1ToCAKdGRQ= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= -github.com/vektah/gqlparser/v2 v2.5.16 h1:1gcmLTvs3JLKXckwCwlUagVn/IlV2bwqle0vJ0vy5p8= -github.com/vektah/gqlparser/v2 v2.5.16/go.mod h1:1lz1OeCqgQbQepsGxPVywrjdBHW2T08PUS3pJqepRww= +github.com/vektah/gqlparser/v2 v2.5.17 h1:9At7WblLV7/36nulgekUgIaqHZWn5hxqluxrxGUhOmI= +github.com/vektah/gqlparser/v2 v2.5.17/go.mod h1:1lz1OeCqgQbQepsGxPVywrjdBHW2T08PUS3pJqepRww= github.com/warpfork/go-errcat v0.0.0-20180917083543-335044ffc86e h1:FIB2fi7XJGHIdf5rWNsfFQqatIKxutT45G+wNuMQNgs= github.com/warpfork/go-errcat v0.0.0-20180917083543-335044ffc86e/go.mod h1:/qe02xr3jvTUz8u/PV0FHGpP8t96OQNP7U9BJMwMLEw= github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= @@ -616,8 +616,8 @@ github.com/willscott/go-nfs-client v0.0.0-20240104095149-b44639837b00 h1:U0DnHRZ github.com/willscott/go-nfs-client v0.0.0-20240104095149-b44639837b00/go.mod h1:Tq++Lr/FgiS3X48q5FETemXiSLGuYMQT2sPjYNPJSwA= github.com/willscott/memphis v0.0.0-20210922141505-529d4987ab7e h1:1eHCP4w7tMmpfFBdrd5ff+vYU9THtrtA1yM9f0TLlJw= github.com/willscott/memphis v0.0.0-20210922141505-529d4987ab7e/go.mod h1:59vHBW4EpjiL5oiqgCrBp1Tc9JXRzKCNMEOaGmNfSHo= -github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 h1:+qGGcbkzsfDQNPPe9UDgpxAWQrhbbBXOYJFQDq/dtJw= -github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913/go.mod h1:4aEEwZQutDLsQv2Deui4iYQ6DWTxR14g6m8Wv88+Xqk= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= @@ -675,8 +675,8 @@ golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98y golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= -golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= +golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -710,8 +710,8 @@ golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= -golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= +golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -744,8 +744,8 @@ golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= -golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -761,8 +761,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -806,8 +806,8 @@ golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= -golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -830,8 +830,8 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= @@ -867,8 +867,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= -golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= +golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= +golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/graphql/query.graphql b/graphql/query.graphql index 6c7ba45..a04485a 100644 --- a/graphql/query.graphql +++ b/graphql/query.graphql @@ -1,5 +1,6 @@ type Query { torrentDaemon: TorrentDaemonQuery @resolver + qbittorrentDaemon: QBitTorrentDaemonQuery @resolver fsEntry(path: String!): FsEntry } diff --git a/graphql/sources/qbittorrent_query.graphql b/graphql/sources/qbittorrent_query.graphql new file mode 100644 index 0000000..f71a8c8 --- /dev/null +++ b/graphql/sources/qbittorrent_query.graphql @@ -0,0 +1,3 @@ +type QBitTorrentDaemonQuery { + torrents: [QTorrent!]! @resolver +} diff --git a/graphql/sources/qbittorrent_types.graphql b/graphql/sources/qbittorrent_types.graphql new file mode 100644 index 0000000..bde728b --- /dev/null +++ b/graphql/sources/qbittorrent_types.graphql @@ -0,0 +1,5 @@ +type QTorrent { + name: String! + hash: String! + sourceFiles: [String!]! @resolver +} diff --git a/src/delivery/graphql/generated.go b/src/delivery/graphql/generated.go index 412d25b..287fdcc 100644 --- a/src/delivery/graphql/generated.go +++ b/src/delivery/graphql/generated.go @@ -43,6 +43,8 @@ type Config struct { type ResolverRoot interface { ArchiveFS() ArchiveFSResolver Mutation() MutationResolver + QBitTorrentDaemonQuery() QBitTorrentDaemonQueryResolver + QTorrent() QTorrentResolver Query() QueryResolver ResolverFS() ResolverFSResolver SimpleDir() SimpleDirResolver @@ -82,9 +84,20 @@ type ComplexityRoot struct { UploadFile func(childComplexity int, dir string, file graphql.Upload) int } + QBitTorrentDaemonQuery struct { + Torrents func(childComplexity int) int + } + + QTorrent struct { + Hash func(childComplexity int) int + Name func(childComplexity int) int + SourceFiles func(childComplexity int) int + } + Query struct { - FsEntry func(childComplexity int, path string) int - TorrentDaemon func(childComplexity int) int + FsEntry func(childComplexity int, path string) int + QbittorrentDaemon func(childComplexity int) int + TorrentDaemon func(childComplexity int) int } ResolverFS struct { @@ -207,8 +220,15 @@ type MutationResolver interface { UploadFile(ctx context.Context, dir string, file graphql.Upload) (bool, error) DedupeStorage(ctx context.Context) (int64, error) } +type QBitTorrentDaemonQueryResolver interface { + Torrents(ctx context.Context, obj *model.QBitTorrentDaemonQuery) ([]*model.QTorrent, error) +} +type QTorrentResolver interface { + SourceFiles(ctx context.Context, obj *model.QTorrent) ([]string, error) +} type QueryResolver interface { TorrentDaemon(ctx context.Context) (*model.TorrentDaemonQuery, error) + QbittorrentDaemon(ctx context.Context) (*model.QBitTorrentDaemonQuery, error) FsEntry(ctx context.Context, path string) (model.FsEntry, error) } type ResolverFSResolver interface { @@ -332,6 +352,34 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Mutation.UploadFile(childComplexity, args["dir"].(string), args["file"].(graphql.Upload)), true + case "QBitTorrentDaemonQuery.torrents": + if e.complexity.QBitTorrentDaemonQuery.Torrents == nil { + break + } + + return e.complexity.QBitTorrentDaemonQuery.Torrents(childComplexity), true + + case "QTorrent.hash": + if e.complexity.QTorrent.Hash == nil { + break + } + + return e.complexity.QTorrent.Hash(childComplexity), true + + case "QTorrent.name": + if e.complexity.QTorrent.Name == nil { + break + } + + return e.complexity.QTorrent.Name(childComplexity), true + + case "QTorrent.sourceFiles": + if e.complexity.QTorrent.SourceFiles == nil { + break + } + + return e.complexity.QTorrent.SourceFiles(childComplexity), true + case "Query.fsEntry": if e.complexity.Query.FsEntry == nil { break @@ -344,6 +392,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Query.FsEntry(childComplexity, args["path"].(string)), true + case "Query.qbittorrentDaemon": + if e.complexity.Query.QbittorrentDaemon == nil { + break + } + + return e.complexity.Query.QbittorrentDaemon(childComplexity), true + case "Query.torrentDaemon": if e.complexity.Query.TorrentDaemon == nil { break @@ -965,6 +1020,7 @@ type Task { `, BuiltIn: false}, {Name: "../../../graphql/query.graphql", Input: `type Query { torrentDaemon: TorrentDaemonQuery @resolver + qbittorrentDaemon: QBitTorrentDaemonQuery @resolver fsEntry(path: String!): FsEntry } @@ -999,6 +1055,16 @@ interface Progress { current: Int! total: Int! }`, BuiltIn: false}, + {Name: "../../../graphql/sources/qbittorrent_query.graphql", Input: `type QBitTorrentDaemonQuery { + torrents: [QTorrent!]! @resolver +} +`, BuiltIn: false}, + {Name: "../../../graphql/sources/qbittorrent_types.graphql", Input: `type QTorrent { + name: String! + hash: String! + sourceFiles: [String!]! @resolver +} +`, BuiltIn: false}, {Name: "../../../graphql/sources/torrent_mutation.graphql", Input: `type TorrentDaemonMutation { validateTorrent(filter: TorrentFilter!): Boolean! @resolver setTorrentPriority( @@ -1201,212 +1267,489 @@ var parsedSchema = gqlparser.MustLoadSchema(sources...) func (ec *executionContext) field_Mutation_uploadFile_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} - var arg0 string - if tmp, ok := rawArgs["dir"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("dir")) - arg0, err = ec.unmarshalNString2string(ctx, tmp) - if err != nil { - return nil, err - } + arg0, err := ec.field_Mutation_uploadFile_argsDir(ctx, rawArgs) + if err != nil { + return nil, err } args["dir"] = arg0 - var arg1 graphql.Upload - if tmp, ok := rawArgs["file"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("file")) - arg1, err = ec.unmarshalNUpload2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚐUpload(ctx, tmp) - if err != nil { - return nil, err - } + arg1, err := ec.field_Mutation_uploadFile_argsFile(ctx, rawArgs) + if err != nil { + return nil, err } args["file"] = arg1 return args, nil } +func (ec *executionContext) field_Mutation_uploadFile_argsDir( + ctx context.Context, + rawArgs map[string]interface{}, +) (string, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["dir"] + if !ok { + var zeroVal string + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("dir")) + if tmp, ok := rawArgs["dir"]; ok { + return ec.unmarshalNString2string(ctx, tmp) + } + + var zeroVal string + return zeroVal, nil +} + +func (ec *executionContext) field_Mutation_uploadFile_argsFile( + ctx context.Context, + rawArgs map[string]interface{}, +) (graphql.Upload, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["file"] + if !ok { + var zeroVal graphql.Upload + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("file")) + if tmp, ok := rawArgs["file"]; ok { + return ec.unmarshalNUpload2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚐUpload(ctx, tmp) + } + + var zeroVal graphql.Upload + return zeroVal, nil +} func (ec *executionContext) field_Query___type_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} - var arg0 string - if tmp, ok := rawArgs["name"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) - arg0, err = ec.unmarshalNString2string(ctx, tmp) - if err != nil { - return nil, err - } + arg0, err := ec.field_Query___type_argsName(ctx, rawArgs) + if err != nil { + return nil, err } args["name"] = arg0 return args, nil } +func (ec *executionContext) field_Query___type_argsName( + ctx context.Context, + rawArgs map[string]interface{}, +) (string, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["name"] + if !ok { + var zeroVal string + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) + if tmp, ok := rawArgs["name"]; ok { + return ec.unmarshalNString2string(ctx, tmp) + } + + var zeroVal string + return zeroVal, nil +} func (ec *executionContext) field_Query_fsEntry_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} - var arg0 string - if tmp, ok := rawArgs["path"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("path")) - arg0, err = ec.unmarshalNString2string(ctx, tmp) - if err != nil { - return nil, err - } + arg0, err := ec.field_Query_fsEntry_argsPath(ctx, rawArgs) + if err != nil { + return nil, err } args["path"] = arg0 return args, nil } +func (ec *executionContext) field_Query_fsEntry_argsPath( + ctx context.Context, + rawArgs map[string]interface{}, +) (string, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["path"] + if !ok { + var zeroVal string + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("path")) + if tmp, ok := rawArgs["path"]; ok { + return ec.unmarshalNString2string(ctx, tmp) + } + + var zeroVal string + return zeroVal, nil +} func (ec *executionContext) field_Subscription_taskProgress_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} - var arg0 string - if tmp, ok := rawArgs["taskID"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("taskID")) - arg0, err = ec.unmarshalNID2string(ctx, tmp) - if err != nil { - return nil, err - } + arg0, err := ec.field_Subscription_taskProgress_argsTaskID(ctx, rawArgs) + if err != nil { + return nil, err } args["taskID"] = arg0 return args, nil } +func (ec *executionContext) field_Subscription_taskProgress_argsTaskID( + ctx context.Context, + rawArgs map[string]interface{}, +) (string, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["taskID"] + if !ok { + var zeroVal string + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("taskID")) + if tmp, ok := rawArgs["taskID"]; ok { + return ec.unmarshalNID2string(ctx, tmp) + } + + var zeroVal string + return zeroVal, nil +} func (ec *executionContext) field_TorrentDaemonMutation_cleanup_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} - var arg0 *bool - if tmp, ok := rawArgs["files"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("files")) - arg0, err = ec.unmarshalOBoolean2ᚖbool(ctx, tmp) - if err != nil { - return nil, err - } + arg0, err := ec.field_TorrentDaemonMutation_cleanup_argsFiles(ctx, rawArgs) + if err != nil { + return nil, err } args["files"] = arg0 - var arg1 bool - if tmp, ok := rawArgs["dryRun"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("dryRun")) - arg1, err = ec.unmarshalNBoolean2bool(ctx, tmp) - if err != nil { - return nil, err - } + arg1, err := ec.field_TorrentDaemonMutation_cleanup_argsDryRun(ctx, rawArgs) + if err != nil { + return nil, err } args["dryRun"] = arg1 return args, nil } +func (ec *executionContext) field_TorrentDaemonMutation_cleanup_argsFiles( + ctx context.Context, + rawArgs map[string]interface{}, +) (*bool, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["files"] + if !ok { + var zeroVal *bool + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("files")) + if tmp, ok := rawArgs["files"]; ok { + return ec.unmarshalOBoolean2ᚖbool(ctx, tmp) + } + + var zeroVal *bool + return zeroVal, nil +} + +func (ec *executionContext) field_TorrentDaemonMutation_cleanup_argsDryRun( + ctx context.Context, + rawArgs map[string]interface{}, +) (bool, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["dryRun"] + if !ok { + var zeroVal bool + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("dryRun")) + if tmp, ok := rawArgs["dryRun"]; ok { + return ec.unmarshalNBoolean2bool(ctx, tmp) + } + + var zeroVal bool + return zeroVal, nil +} func (ec *executionContext) field_TorrentDaemonMutation_setTorrentPriority_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} - var arg0 string - if tmp, ok := rawArgs["infohash"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("infohash")) - arg0, err = ec.unmarshalNString2string(ctx, tmp) - if err != nil { - return nil, err - } + arg0, err := ec.field_TorrentDaemonMutation_setTorrentPriority_argsInfohash(ctx, rawArgs) + if err != nil { + return nil, err } args["infohash"] = arg0 - var arg1 *string - if tmp, ok := rawArgs["file"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("file")) - arg1, err = ec.unmarshalOString2ᚖstring(ctx, tmp) - if err != nil { - return nil, err - } + arg1, err := ec.field_TorrentDaemonMutation_setTorrentPriority_argsFile(ctx, rawArgs) + if err != nil { + return nil, err } args["file"] = arg1 - var arg2 types.PiecePriority - if tmp, ok := rawArgs["priority"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("priority")) - arg2, err = ec.unmarshalNTorrentPriority2githubᚗcomᚋanacrolixᚋtorrentᚋtypesᚐPiecePriority(ctx, tmp) - if err != nil { - return nil, err - } + arg2, err := ec.field_TorrentDaemonMutation_setTorrentPriority_argsPriority(ctx, rawArgs) + if err != nil { + return nil, err } args["priority"] = arg2 return args, nil } +func (ec *executionContext) field_TorrentDaemonMutation_setTorrentPriority_argsInfohash( + ctx context.Context, + rawArgs map[string]interface{}, +) (string, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["infohash"] + if !ok { + var zeroVal string + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("infohash")) + if tmp, ok := rawArgs["infohash"]; ok { + return ec.unmarshalNString2string(ctx, tmp) + } + + var zeroVal string + return zeroVal, nil +} + +func (ec *executionContext) field_TorrentDaemonMutation_setTorrentPriority_argsFile( + ctx context.Context, + rawArgs map[string]interface{}, +) (*string, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["file"] + if !ok { + var zeroVal *string + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("file")) + if tmp, ok := rawArgs["file"]; ok { + return ec.unmarshalOString2ᚖstring(ctx, tmp) + } + + var zeroVal *string + return zeroVal, nil +} + +func (ec *executionContext) field_TorrentDaemonMutation_setTorrentPriority_argsPriority( + ctx context.Context, + rawArgs map[string]interface{}, +) (types.PiecePriority, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["priority"] + if !ok { + var zeroVal types.PiecePriority + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("priority")) + if tmp, ok := rawArgs["priority"]; ok { + return ec.unmarshalNTorrentPriority2githubᚗcomᚋanacrolixᚋtorrentᚋtypesᚐPiecePriority(ctx, tmp) + } + + var zeroVal types.PiecePriority + return zeroVal, nil +} func (ec *executionContext) field_TorrentDaemonMutation_validateTorrent_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} - var arg0 model.TorrentFilter - if tmp, ok := rawArgs["filter"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("filter")) - arg0, err = ec.unmarshalNTorrentFilter2gitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐTorrentFilter(ctx, tmp) - if err != nil { - return nil, err - } + arg0, err := ec.field_TorrentDaemonMutation_validateTorrent_argsFilter(ctx, rawArgs) + if err != nil { + return nil, err } args["filter"] = arg0 return args, nil } +func (ec *executionContext) field_TorrentDaemonMutation_validateTorrent_argsFilter( + ctx context.Context, + rawArgs map[string]interface{}, +) (model.TorrentFilter, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["filter"] + if !ok { + var zeroVal model.TorrentFilter + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("filter")) + if tmp, ok := rawArgs["filter"]; ok { + return ec.unmarshalNTorrentFilter2gitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐTorrentFilter(ctx, tmp) + } + + var zeroVal model.TorrentFilter + return zeroVal, nil +} func (ec *executionContext) field_TorrentDaemonQuery_statsHistory_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} - var arg0 time.Time - if tmp, ok := rawArgs["since"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("since")) - arg0, err = ec.unmarshalNDateTime2timeᚐTime(ctx, tmp) - if err != nil { - return nil, err - } + arg0, err := ec.field_TorrentDaemonQuery_statsHistory_argsSince(ctx, rawArgs) + if err != nil { + return nil, err } args["since"] = arg0 - var arg1 *string - if tmp, ok := rawArgs["infohash"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("infohash")) - arg1, err = ec.unmarshalOString2ᚖstring(ctx, tmp) - if err != nil { - return nil, err - } + arg1, err := ec.field_TorrentDaemonQuery_statsHistory_argsInfohash(ctx, rawArgs) + if err != nil { + return nil, err } args["infohash"] = arg1 return args, nil } +func (ec *executionContext) field_TorrentDaemonQuery_statsHistory_argsSince( + ctx context.Context, + rawArgs map[string]interface{}, +) (time.Time, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["since"] + if !ok { + var zeroVal time.Time + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("since")) + if tmp, ok := rawArgs["since"]; ok { + return ec.unmarshalNDateTime2timeᚐTime(ctx, tmp) + } + + var zeroVal time.Time + return zeroVal, nil +} + +func (ec *executionContext) field_TorrentDaemonQuery_statsHistory_argsInfohash( + ctx context.Context, + rawArgs map[string]interface{}, +) (*string, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["infohash"] + if !ok { + var zeroVal *string + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("infohash")) + if tmp, ok := rawArgs["infohash"]; ok { + return ec.unmarshalOString2ᚖstring(ctx, tmp) + } + + var zeroVal *string + return zeroVal, nil +} func (ec *executionContext) field_TorrentDaemonQuery_torrents_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} - var arg0 *model.TorrentsFilter - if tmp, ok := rawArgs["filter"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("filter")) - arg0, err = ec.unmarshalOTorrentsFilter2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐTorrentsFilter(ctx, tmp) - if err != nil { - return nil, err - } + arg0, err := ec.field_TorrentDaemonQuery_torrents_argsFilter(ctx, rawArgs) + if err != nil { + return nil, err } args["filter"] = arg0 return args, nil } +func (ec *executionContext) field_TorrentDaemonQuery_torrents_argsFilter( + ctx context.Context, + rawArgs map[string]interface{}, +) (*model.TorrentsFilter, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["filter"] + if !ok { + var zeroVal *model.TorrentsFilter + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("filter")) + if tmp, ok := rawArgs["filter"]; ok { + return ec.unmarshalOTorrentsFilter2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐTorrentsFilter(ctx, tmp) + } + + var zeroVal *model.TorrentsFilter + return zeroVal, nil +} func (ec *executionContext) field___Type_enumValues_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} - var arg0 bool - if tmp, ok := rawArgs["includeDeprecated"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("includeDeprecated")) - arg0, err = ec.unmarshalOBoolean2bool(ctx, tmp) - if err != nil { - return nil, err - } + arg0, err := ec.field___Type_enumValues_argsIncludeDeprecated(ctx, rawArgs) + if err != nil { + return nil, err } args["includeDeprecated"] = arg0 return args, nil } +func (ec *executionContext) field___Type_enumValues_argsIncludeDeprecated( + ctx context.Context, + rawArgs map[string]interface{}, +) (bool, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["includeDeprecated"] + if !ok { + var zeroVal bool + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("includeDeprecated")) + if tmp, ok := rawArgs["includeDeprecated"]; ok { + return ec.unmarshalOBoolean2bool(ctx, tmp) + } + + var zeroVal bool + return zeroVal, nil +} func (ec *executionContext) field___Type_fields_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} - var arg0 bool - if tmp, ok := rawArgs["includeDeprecated"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("includeDeprecated")) - arg0, err = ec.unmarshalOBoolean2bool(ctx, tmp) - if err != nil { - return nil, err - } + arg0, err := ec.field___Type_fields_argsIncludeDeprecated(ctx, rawArgs) + if err != nil { + return nil, err } args["includeDeprecated"] = arg0 return args, nil } +func (ec *executionContext) field___Type_fields_argsIncludeDeprecated( + ctx context.Context, + rawArgs map[string]interface{}, +) (bool, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["includeDeprecated"] + if !ok { + var zeroVal bool + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("includeDeprecated")) + if tmp, ok := rawArgs["includeDeprecated"]; ok { + return ec.unmarshalOBoolean2bool(ctx, tmp) + } + + var zeroVal bool + return zeroVal, nil +} // endregion ***************************** args.gotpl ***************************** @@ -1477,9 +1820,11 @@ func (ec *executionContext) _ArchiveFS_entries(ctx context.Context, field graphq ctx = rctx // use context from middleware stack in children return ec.resolvers.ArchiveFS().Entries(rctx, obj) } + directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.Resolver == nil { - return nil, errors.New("directive resolver is not implemented") + var zeroVal []model.FsEntry + return zeroVal, errors.New("directive resolver is not implemented") } return ec.directives.Resolver(ctx, obj, directive0) } @@ -1718,9 +2063,11 @@ func (ec *executionContext) _Mutation_torrentDaemon(ctx context.Context, field g ctx = rctx // use context from middleware stack in children return ec.resolvers.Mutation().TorrentDaemon(rctx) } + directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.Resolver == nil { - return nil, errors.New("directive resolver is not implemented") + var zeroVal *model.TorrentDaemonMutation + return zeroVal, errors.New("directive resolver is not implemented") } return ec.directives.Resolver(ctx, nil, directive0) } @@ -1869,6 +2216,234 @@ func (ec *executionContext) fieldContext_Mutation_dedupeStorage(_ context.Contex return fc, nil } +func (ec *executionContext) _QBitTorrentDaemonQuery_torrents(ctx context.Context, field graphql.CollectedField, obj *model.QBitTorrentDaemonQuery) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_QBitTorrentDaemonQuery_torrents(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + directive0 := func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.QBitTorrentDaemonQuery().Torrents(rctx, obj) + } + + directive1 := func(ctx context.Context) (interface{}, error) { + if ec.directives.Resolver == nil { + var zeroVal []*model.QTorrent + return zeroVal, errors.New("directive resolver is not implemented") + } + return ec.directives.Resolver(ctx, obj, directive0) + } + + tmp, err := directive1(rctx) + if err != nil { + return nil, graphql.ErrorOnPath(ctx, err) + } + if tmp == nil { + return nil, nil + } + if data, ok := tmp.([]*model.QTorrent); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be []*git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model.QTorrent`, tmp) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]*model.QTorrent) + fc.Result = res + return ec.marshalNQTorrent2ᚕᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐQTorrentᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_QBitTorrentDaemonQuery_torrents(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "QBitTorrentDaemonQuery", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "name": + return ec.fieldContext_QTorrent_name(ctx, field) + case "hash": + return ec.fieldContext_QTorrent_hash(ctx, field) + case "sourceFiles": + return ec.fieldContext_QTorrent_sourceFiles(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type QTorrent", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _QTorrent_name(ctx context.Context, field graphql.CollectedField, obj *model.QTorrent) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_QTorrent_name(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_QTorrent_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "QTorrent", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _QTorrent_hash(ctx context.Context, field graphql.CollectedField, obj *model.QTorrent) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_QTorrent_hash(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Hash, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_QTorrent_hash(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "QTorrent", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _QTorrent_sourceFiles(ctx context.Context, field graphql.CollectedField, obj *model.QTorrent) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_QTorrent_sourceFiles(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + directive0 := func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.QTorrent().SourceFiles(rctx, obj) + } + + directive1 := func(ctx context.Context) (interface{}, error) { + if ec.directives.Resolver == nil { + var zeroVal []string + return zeroVal, errors.New("directive resolver is not implemented") + } + return ec.directives.Resolver(ctx, obj, directive0) + } + + tmp, err := directive1(rctx) + if err != nil { + return nil, graphql.ErrorOnPath(ctx, err) + } + if tmp == nil { + return nil, nil + } + if data, ok := tmp.([]string); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be []string`, tmp) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]string) + fc.Result = res + return ec.marshalNString2ᚕstringᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_QTorrent_sourceFiles(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "QTorrent", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) _Query_torrentDaemon(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Query_torrentDaemon(ctx, field) if err != nil { @@ -1886,9 +2461,11 @@ func (ec *executionContext) _Query_torrentDaemon(ctx context.Context, field grap ctx = rctx // use context from middleware stack in children return ec.resolvers.Query().TorrentDaemon(rctx) } + directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.Resolver == nil { - return nil, errors.New("directive resolver is not implemented") + var zeroVal *model.TorrentDaemonQuery + return zeroVal, errors.New("directive resolver is not implemented") } return ec.directives.Resolver(ctx, nil, directive0) } @@ -1938,6 +2515,73 @@ func (ec *executionContext) fieldContext_Query_torrentDaemon(_ context.Context, return fc, nil } +func (ec *executionContext) _Query_qbittorrentDaemon(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_qbittorrentDaemon(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + directive0 := func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().QbittorrentDaemon(rctx) + } + + directive1 := func(ctx context.Context) (interface{}, error) { + if ec.directives.Resolver == nil { + var zeroVal *model.QBitTorrentDaemonQuery + return zeroVal, errors.New("directive resolver is not implemented") + } + return ec.directives.Resolver(ctx, nil, directive0) + } + + tmp, err := directive1(rctx) + if err != nil { + return nil, graphql.ErrorOnPath(ctx, err) + } + if tmp == nil { + return nil, nil + } + if data, ok := tmp.(*model.QBitTorrentDaemonQuery); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be *git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model.QBitTorrentDaemonQuery`, tmp) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*model.QBitTorrentDaemonQuery) + fc.Result = res + return ec.marshalOQBitTorrentDaemonQuery2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐQBitTorrentDaemonQuery(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_qbittorrentDaemon(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "torrents": + return ec.fieldContext_QBitTorrentDaemonQuery_torrents(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type QBitTorrentDaemonQuery", field.Name) + }, + } + return fc, nil +} + func (ec *executionContext) _Query_fsEntry(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Query_fsEntry(ctx, field) if err != nil { @@ -2180,9 +2824,11 @@ func (ec *executionContext) _ResolverFS_entries(ctx context.Context, field graph ctx = rctx // use context from middleware stack in children return ec.resolvers.ResolverFS().Entries(rctx, obj) } + directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.Resolver == nil { - return nil, errors.New("directive resolver is not implemented") + var zeroVal []model.FsEntry + return zeroVal, errors.New("directive resolver is not implemented") } return ec.directives.Resolver(ctx, obj, directive0) } @@ -2254,6 +2900,8 @@ func (ec *executionContext) fieldContext_Schema_query(_ context.Context, field g switch field.Name { case "torrentDaemon": return ec.fieldContext_Query_torrentDaemon(ctx, field) + case "qbittorrentDaemon": + return ec.fieldContext_Query_qbittorrentDaemon(ctx, field) case "fsEntry": return ec.fieldContext_Query_fsEntry(ctx, field) case "__schema": @@ -2366,9 +3014,11 @@ func (ec *executionContext) _SimpleDir_entries(ctx context.Context, field graphq ctx = rctx // use context from middleware stack in children return ec.resolvers.SimpleDir().Entries(rctx, obj) } + directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.Resolver == nil { - return nil, errors.New("directive resolver is not implemented") + var zeroVal []model.FsEntry + return zeroVal, errors.New("directive resolver is not implemented") } return ec.directives.Resolver(ctx, obj, directive0) } @@ -2691,9 +3341,11 @@ func (ec *executionContext) _Torrent_name(ctx context.Context, field graphql.Col ctx = rctx // use context from middleware stack in children return ec.resolvers.Torrent().Name(rctx, obj) } + directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.Resolver == nil { - return nil, errors.New("directive resolver is not implemented") + var zeroVal string + return zeroVal, errors.New("directive resolver is not implemented") } return ec.directives.Resolver(ctx, obj, directive0) } @@ -2975,9 +3627,11 @@ func (ec *executionContext) _Torrent_files(ctx context.Context, field graphql.Co ctx = rctx // use context from middleware stack in children return ec.resolvers.Torrent().Files(rctx, obj) } + directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.Resolver == nil { - return nil, errors.New("directive resolver is not implemented") + var zeroVal []*model.TorrentFile + return zeroVal, errors.New("directive resolver is not implemented") } return ec.directives.Resolver(ctx, obj, directive0) } @@ -3049,9 +3703,11 @@ func (ec *executionContext) _Torrent_excludedFiles(ctx context.Context, field gr ctx = rctx // use context from middleware stack in children return ec.resolvers.Torrent().ExcludedFiles(rctx, obj) } + directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.Resolver == nil { - return nil, errors.New("directive resolver is not implemented") + var zeroVal []*model.TorrentFile + return zeroVal, errors.New("directive resolver is not implemented") } return ec.directives.Resolver(ctx, obj, directive0) } @@ -3123,9 +3779,11 @@ func (ec *executionContext) _Torrent_peers(ctx context.Context, field graphql.Co ctx = rctx // use context from middleware stack in children return ec.resolvers.Torrent().Peers(rctx, obj) } + directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.Resolver == nil { - return nil, errors.New("directive resolver is not implemented") + var zeroVal []*model.TorrentPeer + return zeroVal, errors.New("directive resolver is not implemented") } return ec.directives.Resolver(ctx, obj, directive0) } @@ -3771,9 +4429,11 @@ func (ec *executionContext) _TorrentDaemonMutation_validateTorrent(ctx context.C ctx = rctx // use context from middleware stack in children return ec.resolvers.TorrentDaemonMutation().ValidateTorrent(rctx, obj, fc.Args["filter"].(model.TorrentFilter)) } + directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.Resolver == nil { - return nil, errors.New("directive resolver is not implemented") + var zeroVal bool + return zeroVal, errors.New("directive resolver is not implemented") } return ec.directives.Resolver(ctx, obj, directive0) } @@ -3846,9 +4506,11 @@ func (ec *executionContext) _TorrentDaemonMutation_setTorrentPriority(ctx contex ctx = rctx // use context from middleware stack in children return ec.resolvers.TorrentDaemonMutation().SetTorrentPriority(rctx, obj, fc.Args["infohash"].(string), fc.Args["file"].(*string), fc.Args["priority"].(types.PiecePriority)) } + directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.Resolver == nil { - return nil, errors.New("directive resolver is not implemented") + var zeroVal bool + return zeroVal, errors.New("directive resolver is not implemented") } return ec.directives.Resolver(ctx, obj, directive0) } @@ -3921,9 +4583,11 @@ func (ec *executionContext) _TorrentDaemonMutation_cleanup(ctx context.Context, ctx = rctx // use context from middleware stack in children return ec.resolvers.TorrentDaemonMutation().Cleanup(rctx, obj, fc.Args["files"].(*bool), fc.Args["dryRun"].(bool)) } + directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.Resolver == nil { - return nil, errors.New("directive resolver is not implemented") + var zeroVal *model.CleanupResponse + return zeroVal, errors.New("directive resolver is not implemented") } return ec.directives.Resolver(ctx, obj, directive0) } @@ -4002,9 +4666,11 @@ func (ec *executionContext) _TorrentDaemonQuery_torrents(ctx context.Context, fi ctx = rctx // use context from middleware stack in children return ec.resolvers.TorrentDaemonQuery().Torrents(rctx, obj, fc.Args["filter"].(*model.TorrentsFilter)) } + directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.Resolver == nil { - return nil, errors.New("directive resolver is not implemented") + var zeroVal []*model.Torrent + return zeroVal, errors.New("directive resolver is not implemented") } return ec.directives.Resolver(ctx, obj, directive0) } @@ -4097,9 +4763,11 @@ func (ec *executionContext) _TorrentDaemonQuery_clientStats(ctx context.Context, ctx = rctx // use context from middleware stack in children return ec.resolvers.TorrentDaemonQuery().ClientStats(rctx, obj) } + directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.Resolver == nil { - return nil, errors.New("directive resolver is not implemented") + var zeroVal *model.TorrentClientStats + return zeroVal, errors.New("directive resolver is not implemented") } return ec.directives.Resolver(ctx, obj, directive0) } @@ -4189,9 +4857,11 @@ func (ec *executionContext) _TorrentDaemonQuery_statsHistory(ctx context.Context ctx = rctx // use context from middleware stack in children return ec.resolvers.TorrentDaemonQuery().StatsHistory(rctx, obj, fc.Args["since"].(time.Time), fc.Args["infohash"].(*string)) } + directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.Resolver == nil { - return nil, errors.New("directive resolver is not implemented") + var zeroVal []*model.TorrentStats + return zeroVal, errors.New("directive resolver is not implemented") } return ec.directives.Resolver(ctx, obj, directive0) } @@ -4386,9 +5056,11 @@ func (ec *executionContext) _TorrentFS_entries(ctx context.Context, field graphq ctx = rctx // use context from middleware stack in children return ec.resolvers.TorrentFS().Entries(rctx, obj) } + directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.Resolver == nil { - return nil, errors.New("directive resolver is not implemented") + var zeroVal []model.FsEntry + return zeroVal, errors.New("directive resolver is not implemented") } return ec.directives.Resolver(ctx, obj, directive0) } @@ -4582,9 +5254,11 @@ func (ec *executionContext) _TorrentFile_priority(ctx context.Context, field gra ctx = rctx // use context from middleware stack in children return ec.resolvers.TorrentFile().Priority(rctx, obj) } + directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.Resolver == nil { - return nil, errors.New("directive resolver is not implemented") + var zeroVal types.PiecePriority + return zeroVal, errors.New("directive resolver is not implemented") } return ec.directives.Resolver(ctx, obj, directive0) } @@ -7207,9 +7881,11 @@ func (ec *executionContext) unmarshalInputBooleanFilter(ctx context.Context, obj case "eq": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("eq")) directive0 := func(ctx context.Context) (interface{}, error) { return ec.unmarshalOBoolean2ᚖbool(ctx, v) } + directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.OneOf == nil { - return nil, errors.New("directive oneOf is not implemented") + var zeroVal *bool + return zeroVal, errors.New("directive oneOf is not implemented") } return ec.directives.OneOf(ctx, obj, directive0) } @@ -7249,9 +7925,11 @@ func (ec *executionContext) unmarshalInputDateTimeFilter(ctx context.Context, ob case "eq": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("eq")) directive0 := func(ctx context.Context) (interface{}, error) { return ec.unmarshalODateTime2ᚖtimeᚐTime(ctx, v) } + directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.OneOf == nil { - return nil, errors.New("directive oneOf is not implemented") + var zeroVal *time.Time + return zeroVal, errors.New("directive oneOf is not implemented") } return ec.directives.OneOf(ctx, obj, directive0) } @@ -7271,9 +7949,11 @@ func (ec *executionContext) unmarshalInputDateTimeFilter(ctx context.Context, ob case "gt": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("gt")) directive0 := func(ctx context.Context) (interface{}, error) { return ec.unmarshalODateTime2ᚖtimeᚐTime(ctx, v) } + directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.OneOf == nil { - return nil, errors.New("directive oneOf is not implemented") + var zeroVal *time.Time + return zeroVal, errors.New("directive oneOf is not implemented") } return ec.directives.OneOf(ctx, obj, directive0) } @@ -7293,9 +7973,11 @@ func (ec *executionContext) unmarshalInputDateTimeFilter(ctx context.Context, ob case "lt": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("lt")) directive0 := func(ctx context.Context) (interface{}, error) { return ec.unmarshalODateTime2ᚖtimeᚐTime(ctx, v) } + directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.OneOf == nil { - return nil, errors.New("directive oneOf is not implemented") + var zeroVal *time.Time + return zeroVal, errors.New("directive oneOf is not implemented") } return ec.directives.OneOf(ctx, obj, directive0) } @@ -7315,9 +7997,11 @@ func (ec *executionContext) unmarshalInputDateTimeFilter(ctx context.Context, ob case "gte": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("gte")) directive0 := func(ctx context.Context) (interface{}, error) { return ec.unmarshalODateTime2ᚖtimeᚐTime(ctx, v) } + directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.OneOf == nil { - return nil, errors.New("directive oneOf is not implemented") + var zeroVal *time.Time + return zeroVal, errors.New("directive oneOf is not implemented") } return ec.directives.OneOf(ctx, obj, directive0) } @@ -7337,9 +8021,11 @@ func (ec *executionContext) unmarshalInputDateTimeFilter(ctx context.Context, ob case "lte": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("lte")) directive0 := func(ctx context.Context) (interface{}, error) { return ec.unmarshalODateTime2ᚖtimeᚐTime(ctx, v) } + directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.OneOf == nil { - return nil, errors.New("directive oneOf is not implemented") + var zeroVal *time.Time + return zeroVal, errors.New("directive oneOf is not implemented") } return ec.directives.OneOf(ctx, obj, directive0) } @@ -7379,9 +8065,11 @@ func (ec *executionContext) unmarshalInputIntFilter(ctx context.Context, obj int case "eq": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("eq")) directive0 := func(ctx context.Context) (interface{}, error) { return ec.unmarshalOInt2ᚖint64(ctx, v) } + directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.OneOf == nil { - return nil, errors.New("directive oneOf is not implemented") + var zeroVal *int64 + return zeroVal, errors.New("directive oneOf is not implemented") } return ec.directives.OneOf(ctx, obj, directive0) } @@ -7401,9 +8089,11 @@ func (ec *executionContext) unmarshalInputIntFilter(ctx context.Context, obj int case "gt": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("gt")) directive0 := func(ctx context.Context) (interface{}, error) { return ec.unmarshalOInt2ᚖint64(ctx, v) } + directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.OneOf == nil { - return nil, errors.New("directive oneOf is not implemented") + var zeroVal *int64 + return zeroVal, errors.New("directive oneOf is not implemented") } return ec.directives.OneOf(ctx, obj, directive0) } @@ -7423,9 +8113,11 @@ func (ec *executionContext) unmarshalInputIntFilter(ctx context.Context, obj int case "lt": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("lt")) directive0 := func(ctx context.Context) (interface{}, error) { return ec.unmarshalOInt2ᚖint64(ctx, v) } + directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.OneOf == nil { - return nil, errors.New("directive oneOf is not implemented") + var zeroVal *int64 + return zeroVal, errors.New("directive oneOf is not implemented") } return ec.directives.OneOf(ctx, obj, directive0) } @@ -7445,9 +8137,11 @@ func (ec *executionContext) unmarshalInputIntFilter(ctx context.Context, obj int case "gte": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("gte")) directive0 := func(ctx context.Context) (interface{}, error) { return ec.unmarshalOInt2ᚖint64(ctx, v) } + directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.OneOf == nil { - return nil, errors.New("directive oneOf is not implemented") + var zeroVal *int64 + return zeroVal, errors.New("directive oneOf is not implemented") } return ec.directives.OneOf(ctx, obj, directive0) } @@ -7467,9 +8161,11 @@ func (ec *executionContext) unmarshalInputIntFilter(ctx context.Context, obj int case "lte": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("lte")) directive0 := func(ctx context.Context) (interface{}, error) { return ec.unmarshalOInt2ᚖint64(ctx, v) } + directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.OneOf == nil { - return nil, errors.New("directive oneOf is not implemented") + var zeroVal *int64 + return zeroVal, errors.New("directive oneOf is not implemented") } return ec.directives.OneOf(ctx, obj, directive0) } @@ -7489,9 +8185,11 @@ func (ec *executionContext) unmarshalInputIntFilter(ctx context.Context, obj int case "in": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("in")) directive0 := func(ctx context.Context) (interface{}, error) { return ec.unmarshalOInt2ᚕint64ᚄ(ctx, v) } + directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.OneOf == nil { - return nil, errors.New("directive oneOf is not implemented") + var zeroVal []int64 + return zeroVal, errors.New("directive oneOf is not implemented") } return ec.directives.OneOf(ctx, obj, directive0) } @@ -7565,9 +8263,11 @@ func (ec *executionContext) unmarshalInputStringFilter(ctx context.Context, obj case "eq": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("eq")) directive0 := func(ctx context.Context) (interface{}, error) { return ec.unmarshalOString2ᚖstring(ctx, v) } + directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.OneOf == nil { - return nil, errors.New("directive oneOf is not implemented") + var zeroVal *string + return zeroVal, errors.New("directive oneOf is not implemented") } return ec.directives.OneOf(ctx, obj, directive0) } @@ -7587,9 +8287,11 @@ func (ec *executionContext) unmarshalInputStringFilter(ctx context.Context, obj case "substr": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("substr")) directive0 := func(ctx context.Context) (interface{}, error) { return ec.unmarshalOString2ᚖstring(ctx, v) } + directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.OneOf == nil { - return nil, errors.New("directive oneOf is not implemented") + var zeroVal *string + return zeroVal, errors.New("directive oneOf is not implemented") } return ec.directives.OneOf(ctx, obj, directive0) } @@ -7609,9 +8311,11 @@ func (ec *executionContext) unmarshalInputStringFilter(ctx context.Context, obj case "in": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("in")) directive0 := func(ctx context.Context) (interface{}, error) { return ec.unmarshalOString2ᚕstringᚄ(ctx, v) } + directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.OneOf == nil { - return nil, errors.New("directive oneOf is not implemented") + var zeroVal []string + return zeroVal, errors.New("directive oneOf is not implemented") } return ec.directives.OneOf(ctx, obj, directive0) } @@ -7651,9 +8355,11 @@ func (ec *executionContext) unmarshalInputTorrentFilter(ctx context.Context, obj case "everything": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("everything")) directive0 := func(ctx context.Context) (interface{}, error) { return ec.unmarshalOBoolean2ᚖbool(ctx, v) } + directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.OneOf == nil { - return nil, errors.New("directive oneOf is not implemented") + var zeroVal *bool + return zeroVal, errors.New("directive oneOf is not implemented") } return ec.directives.OneOf(ctx, obj, directive0) } @@ -7673,9 +8379,11 @@ func (ec *executionContext) unmarshalInputTorrentFilter(ctx context.Context, obj case "infohash": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("infohash")) directive0 := func(ctx context.Context) (interface{}, error) { return ec.unmarshalOString2ᚖstring(ctx, v) } + directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.OneOf == nil { - return nil, errors.New("directive oneOf is not implemented") + var zeroVal *string + return zeroVal, errors.New("directive oneOf is not implemented") } return ec.directives.OneOf(ctx, obj, directive0) } @@ -7717,9 +8425,11 @@ func (ec *executionContext) unmarshalInputTorrentPriorityFilter(ctx context.Cont directive0 := func(ctx context.Context) (interface{}, error) { return ec.unmarshalOTorrentPriority2ᚖgithubᚗcomᚋanacrolixᚋtorrentᚋtypesᚐPiecePriority(ctx, v) } + directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.OneOf == nil { - return nil, errors.New("directive oneOf is not implemented") + var zeroVal *types.PiecePriority + return zeroVal, errors.New("directive oneOf is not implemented") } return ec.directives.OneOf(ctx, obj, directive0) } @@ -7741,9 +8451,11 @@ func (ec *executionContext) unmarshalInputTorrentPriorityFilter(ctx context.Cont directive0 := func(ctx context.Context) (interface{}, error) { return ec.unmarshalOTorrentPriority2ᚖgithubᚗcomᚋanacrolixᚋtorrentᚋtypesᚐPiecePriority(ctx, v) } + directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.OneOf == nil { - return nil, errors.New("directive oneOf is not implemented") + var zeroVal *types.PiecePriority + return zeroVal, errors.New("directive oneOf is not implemented") } return ec.directives.OneOf(ctx, obj, directive0) } @@ -7765,9 +8477,11 @@ func (ec *executionContext) unmarshalInputTorrentPriorityFilter(ctx context.Cont directive0 := func(ctx context.Context) (interface{}, error) { return ec.unmarshalOTorrentPriority2ᚖgithubᚗcomᚋanacrolixᚋtorrentᚋtypesᚐPiecePriority(ctx, v) } + directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.OneOf == nil { - return nil, errors.New("directive oneOf is not implemented") + var zeroVal *types.PiecePriority + return zeroVal, errors.New("directive oneOf is not implemented") } return ec.directives.OneOf(ctx, obj, directive0) } @@ -7789,9 +8503,11 @@ func (ec *executionContext) unmarshalInputTorrentPriorityFilter(ctx context.Cont directive0 := func(ctx context.Context) (interface{}, error) { return ec.unmarshalOTorrentPriority2ᚖgithubᚗcomᚋanacrolixᚋtorrentᚋtypesᚐPiecePriority(ctx, v) } + directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.OneOf == nil { - return nil, errors.New("directive oneOf is not implemented") + var zeroVal *types.PiecePriority + return zeroVal, errors.New("directive oneOf is not implemented") } return ec.directives.OneOf(ctx, obj, directive0) } @@ -7813,9 +8529,11 @@ func (ec *executionContext) unmarshalInputTorrentPriorityFilter(ctx context.Cont directive0 := func(ctx context.Context) (interface{}, error) { return ec.unmarshalOTorrentPriority2ᚖgithubᚗcomᚋanacrolixᚋtorrentᚋtypesᚐPiecePriority(ctx, v) } + directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.OneOf == nil { - return nil, errors.New("directive oneOf is not implemented") + var zeroVal *types.PiecePriority + return zeroVal, errors.New("directive oneOf is not implemented") } return ec.directives.OneOf(ctx, obj, directive0) } @@ -7837,9 +8555,11 @@ func (ec *executionContext) unmarshalInputTorrentPriorityFilter(ctx context.Cont directive0 := func(ctx context.Context) (interface{}, error) { return ec.unmarshalOTorrentPriority2ᚕgithubᚗcomᚋanacrolixᚋtorrentᚋtypesᚐPiecePriorityᚄ(ctx, v) } + directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.OneOf == nil { - return nil, errors.New("directive oneOf is not implemented") + var zeroVal []types.PiecePriority + return zeroVal, errors.New("directive oneOf is not implemented") } return ec.directives.OneOf(ctx, obj, directive0) } @@ -8289,6 +9009,156 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) return out } +var qBitTorrentDaemonQueryImplementors = []string{"QBitTorrentDaemonQuery"} + +func (ec *executionContext) _QBitTorrentDaemonQuery(ctx context.Context, sel ast.SelectionSet, obj *model.QBitTorrentDaemonQuery) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, qBitTorrentDaemonQueryImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("QBitTorrentDaemonQuery") + case "torrents": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._QBitTorrentDaemonQuery_torrents(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + return res + } + + if field.Deferrable != nil { + dfs, ok := deferred[field.Deferrable.Label] + di := 0 + if ok { + dfs.AddField(field) + di = len(dfs.Values) - 1 + } else { + dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) + deferred[field.Deferrable.Label] = dfs + } + dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { + return innerFunc(ctx, dfs) + }) + + // don't run the out.Concurrently() call below + out.Values[i] = graphql.Null + continue + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var qTorrentImplementors = []string{"QTorrent"} + +func (ec *executionContext) _QTorrent(ctx context.Context, sel ast.SelectionSet, obj *model.QTorrent) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, qTorrentImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("QTorrent") + case "name": + out.Values[i] = ec._QTorrent_name(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&out.Invalids, 1) + } + case "hash": + out.Values[i] = ec._QTorrent_hash(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&out.Invalids, 1) + } + case "sourceFiles": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._QTorrent_sourceFiles(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + return res + } + + if field.Deferrable != nil { + dfs, ok := deferred[field.Deferrable.Label] + di := 0 + if ok { + dfs.AddField(field) + di = len(dfs.Values) - 1 + } else { + dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) + deferred[field.Deferrable.Label] = dfs + } + dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { + return innerFunc(ctx, dfs) + }) + + // don't run the out.Concurrently() call below + out.Values[i] = graphql.Null + continue + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + var queryImplementors = []string{"Query"} func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) graphql.Marshaler { @@ -8326,6 +9196,25 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "qbittorrentDaemon": + field := field + + innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_qbittorrentDaemon(ctx, field) + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, + func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + } + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "fsEntry": field := field @@ -10107,6 +10996,60 @@ func (ec *executionContext) marshalNInt2int64(ctx context.Context, sel ast.Selec return res } +func (ec *executionContext) marshalNQTorrent2ᚕᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐQTorrentᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.QTorrent) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNQTorrent2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐQTorrent(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalNQTorrent2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐQTorrent(ctx context.Context, sel ast.SelectionSet, v *model.QTorrent) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._QTorrent(ctx, sel, v) +} + func (ec *executionContext) unmarshalNString2string(ctx context.Context, v interface{}) (string, error) { res, err := graphql.UnmarshalString(v) return res, graphql.ErrorOnPath(ctx, err) @@ -10826,6 +11769,13 @@ func (ec *executionContext) marshalOProgress2gitᚗkmsignᚗruᚋroyalcatᚋtsto return ec._Progress(ctx, sel, v) } +func (ec *executionContext) marshalOQBitTorrentDaemonQuery2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐQBitTorrentDaemonQuery(ctx context.Context, sel ast.SelectionSet, v *model.QBitTorrentDaemonQuery) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._QBitTorrentDaemonQuery(ctx, sel, v) +} + func (ec *executionContext) marshalOQuery2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐQuery(ctx context.Context, sel ast.SelectionSet, v *model.Query) graphql.Marshaler { if v == nil { return graphql.Null diff --git a/src/delivery/graphql/model/models_gen.go b/src/delivery/graphql/model/models_gen.go index 7a6e02f..af24549 100644 --- a/src/delivery/graphql/model/models_gen.go +++ b/src/delivery/graphql/model/models_gen.go @@ -96,6 +96,16 @@ type Pagination struct { Limit int64 `json:"limit"` } +type QBitTorrentDaemonQuery struct { + Torrents []*QTorrent `json:"torrents"` +} + +type QTorrent struct { + Name string `json:"name"` + Hash string `json:"hash"` + SourceFiles []string `json:"sourceFiles"` +} + type Query struct { } diff --git a/src/delivery/graphql/resolver/fs.resolvers.go b/src/delivery/graphql/resolver/fs.resolvers.go index 4c79912..ce0c150 100644 --- a/src/delivery/graphql/resolver/fs.resolvers.go +++ b/src/delivery/graphql/resolver/fs.resolvers.go @@ -2,7 +2,7 @@ package resolver // This file will be automatically regenerated based on the schema, any resolver implementations // will be copied through when generating and any unknown code will be moved to the end. -// Code generated by github.com/99designs/gqlgen version v0.17.49 +// Code generated by github.com/99designs/gqlgen version v0.17.55 import ( "context" diff --git a/src/delivery/graphql/resolver/mutation.resolvers.go b/src/delivery/graphql/resolver/mutation.resolvers.go index dae361d..92c8a6e 100644 --- a/src/delivery/graphql/resolver/mutation.resolvers.go +++ b/src/delivery/graphql/resolver/mutation.resolvers.go @@ -2,7 +2,7 @@ package resolver // This file will be automatically regenerated based on the schema, any resolver implementations // will be copied through when generating and any unknown code will be moved to the end. -// Code generated by github.com/99designs/gqlgen version v0.17.49 +// Code generated by github.com/99designs/gqlgen version v0.17.55 import ( "context" @@ -49,7 +49,7 @@ func (r *mutationResolver) UploadFile(ctx context.Context, dir string, file grap // DedupeStorage is the resolver for the dedupeStorage field. func (r *mutationResolver) DedupeStorage(ctx context.Context) (int64, error) { - deduped, err := r.Service.Storage.Dedupe(ctx) + deduped, err := r.ATorrentDaemon.Storage.Dedupe(ctx) if err != nil { return 0, err } diff --git a/src/delivery/graphql/resolver/qbittorrent_query.resolvers.go b/src/delivery/graphql/resolver/qbittorrent_query.resolvers.go new file mode 100644 index 0000000..11b0e45 --- /dev/null +++ b/src/delivery/graphql/resolver/qbittorrent_query.resolvers.go @@ -0,0 +1,38 @@ +package resolver + +// This file will be automatically regenerated based on the schema, any resolver implementations +// will be copied through when generating and any unknown code will be moved to the end. +// Code generated by github.com/99designs/gqlgen version v0.17.55 + +import ( + "context" + "fmt" + + graph "git.kmsign.ru/royalcat/tstor/src/delivery/graphql" + "git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model" +) + +// Torrents is the resolver for the torrents field. +func (r *qBitTorrentDaemonQueryResolver) Torrents(ctx context.Context, obj *model.QBitTorrentDaemonQuery) ([]*model.QTorrent, error) { + info, err := r.QBitTorrentDaemon.ListTorrents(ctx) + if err != nil { + return nil, fmt.Errorf("error listing torrents: %w", err) + } + + out := make([]*model.QTorrent, len(info)) + for i, v := range info { + out[i] = &model.QTorrent{ + Name: v.Name, + Hash: v.Hash, + } + } + + return out, nil +} + +// QBitTorrentDaemonQuery returns graph.QBitTorrentDaemonQueryResolver implementation. +func (r *Resolver) QBitTorrentDaemonQuery() graph.QBitTorrentDaemonQueryResolver { + return &qBitTorrentDaemonQueryResolver{r} +} + +type qBitTorrentDaemonQueryResolver struct{ *Resolver } diff --git a/src/delivery/graphql/resolver/qbittorrent_types.resolvers.go b/src/delivery/graphql/resolver/qbittorrent_types.resolvers.go new file mode 100644 index 0000000..fb92cde --- /dev/null +++ b/src/delivery/graphql/resolver/qbittorrent_types.resolvers.go @@ -0,0 +1,22 @@ +package resolver + +// This file will be automatically regenerated based on the schema, any resolver implementations +// will be copied through when generating and any unknown code will be moved to the end. +// Code generated by github.com/99designs/gqlgen version v0.17.55 + +import ( + "context" + + graph "git.kmsign.ru/royalcat/tstor/src/delivery/graphql" + "git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model" +) + +// SourceFiles is the resolver for the sourceFiles field. +func (r *qTorrentResolver) SourceFiles(ctx context.Context, obj *model.QTorrent) ([]string, error) { + return r.QBitTorrentDaemon.SourceFiles(ctx, obj.Hash) +} + +// QTorrent returns graph.QTorrentResolver implementation. +func (r *Resolver) QTorrent() graph.QTorrentResolver { return &qTorrentResolver{r} } + +type qTorrentResolver struct{ *Resolver } diff --git a/src/delivery/graphql/resolver/query.resolvers.go b/src/delivery/graphql/resolver/query.resolvers.go index 686969e..3292c92 100644 --- a/src/delivery/graphql/resolver/query.resolvers.go +++ b/src/delivery/graphql/resolver/query.resolvers.go @@ -2,7 +2,7 @@ package resolver // This file will be automatically regenerated based on the schema, any resolver implementations // will be copied through when generating and any unknown code will be moved to the end. -// Code generated by github.com/99designs/gqlgen version v0.17.49 +// Code generated by github.com/99designs/gqlgen version v0.17.55 import ( "context" @@ -16,6 +16,11 @@ func (r *queryResolver) TorrentDaemon(ctx context.Context) (*model.TorrentDaemon return &model.TorrentDaemonQuery{}, nil } +// QbittorrentDaemon is the resolver for the qbittorrentDaemon field. +func (r *queryResolver) QbittorrentDaemon(ctx context.Context) (*model.QBitTorrentDaemonQuery, error) { + return &model.QBitTorrentDaemonQuery{}, nil +} + // FsEntry is the resolver for the fsEntry field. func (r *queryResolver) FsEntry(ctx context.Context, path string) (model.FsEntry, error) { entry, err := r.VFS.Stat(ctx, path) diff --git a/src/delivery/graphql/resolver/resolver.go b/src/delivery/graphql/resolver/resolver.go index a5a031f..afb2ce6 100644 --- a/src/delivery/graphql/resolver/resolver.go +++ b/src/delivery/graphql/resolver/resolver.go @@ -1,6 +1,7 @@ package resolver import ( + "git.kmsign.ru/royalcat/tstor/src/sources/qbittorrent" "git.kmsign.ru/royalcat/tstor/src/sources/torrent" "git.kmsign.ru/royalcat/tstor/src/vfs" "github.com/go-git/go-billy/v5" @@ -11,7 +12,8 @@ import ( // It serves as dependency injection for your app, add any dependencies you require here. type Resolver struct { - Service *torrent.Daemon - VFS vfs.Filesystem - SourceFS billy.Filesystem + ATorrentDaemon *torrent.Daemon + QBitTorrentDaemon *qbittorrent.Daemon + VFS vfs.Filesystem + SourceFS billy.Filesystem } diff --git a/src/delivery/graphql/resolver/subscription.resolvers.go b/src/delivery/graphql/resolver/subscription.resolvers.go index af5a31d..dfc549d 100644 --- a/src/delivery/graphql/resolver/subscription.resolvers.go +++ b/src/delivery/graphql/resolver/subscription.resolvers.go @@ -2,7 +2,7 @@ package resolver // This file will be automatically regenerated based on the schema, any resolver implementations // will be copied through when generating and any unknown code will be moved to the end. -// Code generated by github.com/99designs/gqlgen version v0.17.49 +// Code generated by github.com/99designs/gqlgen version v0.17.55 import ( "context" @@ -20,7 +20,7 @@ func (r *subscriptionResolver) TaskProgress(ctx context.Context, taskID string) // TorrentDownloadUpdates is the resolver for the torrentDownloadUpdates field. func (r *subscriptionResolver) TorrentDownloadUpdates(ctx context.Context) (<-chan *model.TorrentProgress, error) { out := make(chan *model.TorrentProgress) - progress, err := r.Service.DownloadProgress(ctx) + progress, err := r.ATorrentDaemon.DownloadProgress(ctx) if err != nil { return nil, err } diff --git a/src/delivery/graphql/resolver/torrent_mutation.resolvers.go b/src/delivery/graphql/resolver/torrent_mutation.resolvers.go index bf79feb..51ba680 100644 --- a/src/delivery/graphql/resolver/torrent_mutation.resolvers.go +++ b/src/delivery/graphql/resolver/torrent_mutation.resolvers.go @@ -2,7 +2,7 @@ package resolver // This file will be automatically regenerated based on the schema, any resolver implementations // will be copied through when generating and any unknown code will be moved to the end. -// Code generated by github.com/99designs/gqlgen version v0.17.49 +// Code generated by github.com/99designs/gqlgen version v0.17.55 import ( "context" @@ -15,7 +15,7 @@ import ( // ValidateTorrent is the resolver for the validateTorrent field. func (r *torrentDaemonMutationResolver) ValidateTorrent(ctx context.Context, obj *model.TorrentDaemonMutation, filter model.TorrentFilter) (bool, error) { if filter.Infohash != nil { - t, err := r.Resolver.Service.GetTorrent(*filter.Infohash) + t, err := r.Resolver.ATorrentDaemon.GetTorrent(*filter.Infohash) if err != nil { return false, err } @@ -28,7 +28,7 @@ func (r *torrentDaemonMutationResolver) ValidateTorrent(ctx context.Context, obj } if filter.Everything != nil && *filter.Everything { - torrents, err := r.Resolver.Service.ListTorrents(ctx) + torrents, err := r.Resolver.ATorrentDaemon.ListTorrents(ctx) if err != nil { return false, err } @@ -45,7 +45,7 @@ func (r *torrentDaemonMutationResolver) ValidateTorrent(ctx context.Context, obj // SetTorrentPriority is the resolver for the setTorrentPriority field. func (r *torrentDaemonMutationResolver) SetTorrentPriority(ctx context.Context, obj *model.TorrentDaemonMutation, infohash string, file *string, priority types.PiecePriority) (bool, error) { - t, err := r.Resolver.Service.GetTorrent(infohash) + t, err := r.Resolver.ATorrentDaemon.GetTorrent(infohash) if err != nil { return false, err } @@ -74,19 +74,19 @@ func (r *torrentDaemonMutationResolver) SetTorrentPriority(ctx context.Context, // Cleanup is the resolver for the cleanup field. func (r *torrentDaemonMutationResolver) Cleanup(ctx context.Context, obj *model.TorrentDaemonMutation, files *bool, dryRun bool) (*model.CleanupResponse, error) { - torrents, err := r.Service.ListTorrents(ctx) + torrents, err := r.ATorrentDaemon.ListTorrents(ctx) if err != nil { return nil, err } if files != nil && *files { - r, err := r.Service.Storage.CleanupFiles(ctx, torrents, dryRun) + r, err := r.ATorrentDaemon.Storage.CleanupFiles(ctx, torrents, dryRun) return &model.CleanupResponse{ Count: int64(len(r)), List: r, }, err } else { - r, err := r.Service.Storage.CleanupDirs(ctx, torrents, dryRun) + r, err := r.ATorrentDaemon.Storage.CleanupDirs(ctx, torrents, dryRun) return &model.CleanupResponse{ Count: int64(len(r)), List: r, diff --git a/src/delivery/graphql/resolver/torrent_query.resolvers.go b/src/delivery/graphql/resolver/torrent_query.resolvers.go index 081b45b..718db0e 100644 --- a/src/delivery/graphql/resolver/torrent_query.resolvers.go +++ b/src/delivery/graphql/resolver/torrent_query.resolvers.go @@ -2,7 +2,7 @@ package resolver // This file will be automatically regenerated based on the schema, any resolver implementations // will be copied through when generating and any unknown code will be moved to the end. -// Code generated by github.com/99designs/gqlgen version v0.17.49 +// Code generated by github.com/99designs/gqlgen version v0.17.55 import ( "context" @@ -13,13 +13,12 @@ import ( graph "git.kmsign.ru/royalcat/tstor/src/delivery/graphql" "git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model" "git.kmsign.ru/royalcat/tstor/src/sources/torrent" - tinfohash "github.com/anacrolix/torrent/types/infohash" ) // Torrents is the resolver for the torrents field. func (r *torrentDaemonQueryResolver) Torrents(ctx context.Context, obj *model.TorrentDaemonQuery, filter *model.TorrentsFilter) ([]*model.Torrent, error) { - torrents, err := r.Service.ListTorrents(ctx) + torrents, err := r.ATorrentDaemon.ListTorrents(ctx) if err != nil { return nil, err } @@ -91,7 +90,7 @@ func (r *torrentDaemonQueryResolver) Torrents(ctx context.Context, obj *model.To // ClientStats is the resolver for the clientStats field. func (r *torrentDaemonQueryResolver) ClientStats(ctx context.Context, obj *model.TorrentDaemonQuery) (*model.TorrentClientStats, error) { - stats := r.Service.Stats() + stats := r.ATorrentDaemon.Stats() return &model.TorrentClientStats{ BytesWritten: stats.BytesWritten.Int64(), BytesRead: stats.BytesRead.Int64(), @@ -113,21 +112,21 @@ func (r *torrentDaemonQueryResolver) ClientStats(ctx context.Context, obj *model func (r *torrentDaemonQueryResolver) StatsHistory(ctx context.Context, obj *model.TorrentDaemonQuery, since time.Time, infohash *string) ([]*model.TorrentStats, error) { var stats []torrent.TorrentStats if infohash == nil { - stats, err := r.Service.StatsHistory(ctx, since) + stats, err := r.ATorrentDaemon.StatsHistory(ctx, since) if err != nil { return nil, err } return model.Apply(stats, model.MapTorrentStats), nil } else if *infohash == "total" { var err error - stats, err = r.Service.TotalStatsHistory(ctx, since) + stats, err = r.ATorrentDaemon.TotalStatsHistory(ctx, since) if err != nil { return nil, err } } else { ih := tinfohash.FromHexString(*infohash) var err error - stats, err = r.Service.TorrentStatsHistory(ctx, since, ih) + stats, err = r.ATorrentDaemon.TorrentStatsHistory(ctx, since, ih) if err != nil { return nil, err } diff --git a/src/delivery/graphql/resolver/torrent_types.resolvers.go b/src/delivery/graphql/resolver/torrent_types.resolvers.go index 106c7ed..b8ff637 100644 --- a/src/delivery/graphql/resolver/torrent_types.resolvers.go +++ b/src/delivery/graphql/resolver/torrent_types.resolvers.go @@ -2,7 +2,7 @@ package resolver // This file will be automatically regenerated based on the schema, any resolver implementations // will be copied through when generating and any unknown code will be moved to the end. -// Code generated by github.com/99designs/gqlgen version v0.17.49 +// Code generated by github.com/99designs/gqlgen version v0.17.55 import ( "context" diff --git a/src/delivery/http.go b/src/delivery/http.go index 1dea77e..b8bd96f 100644 --- a/src/delivery/http.go +++ b/src/delivery/http.go @@ -7,6 +7,7 @@ import ( "git.kmsign.ru/royalcat/tstor/pkg/rlog" "git.kmsign.ru/royalcat/tstor/src/config" + "git.kmsign.ru/royalcat/tstor/src/sources/qbittorrent" "git.kmsign.ru/royalcat/tstor/src/sources/torrent" "git.kmsign.ru/royalcat/tstor/src/vfs" echopprof "github.com/labstack/echo-contrib/pprof" @@ -15,7 +16,7 @@ import ( "github.com/prometheus/client_golang/prometheus/promhttp" ) -func Run(s *torrent.Daemon, vfs vfs.Filesystem, logPath string, cfg *config.Settings) error { +func Run(torrentdaemon *torrent.Daemon, qbitdaemon *qbittorrent.Daemon, vfs vfs.Filesystem, cfg *config.Settings) error { log := slog.With() r := echo.New() @@ -28,7 +29,7 @@ func Run(s *torrent.Daemon, vfs vfs.Filesystem, logPath string, cfg *config.Sett echopprof.Register(r) - r.Any("/graphql", echo.WrapHandler((GraphQLHandler(s, vfs)))) + r.Any("/graphql", echo.WrapHandler((GraphQLHandler(torrentdaemon, qbitdaemon, vfs)))) r.GET("/metrics", echo.WrapHandler(promhttp.Handler())) log.Info("starting webserver", "host", fmt.Sprintf("%s:%d", cfg.WebUi.IP, cfg.WebUi.Port)) diff --git a/src/delivery/router.go b/src/delivery/router.go index 59f8e7e..6fa5f82 100644 --- a/src/delivery/router.go +++ b/src/delivery/router.go @@ -6,6 +6,7 @@ import ( graph "git.kmsign.ru/royalcat/tstor/src/delivery/graphql" "git.kmsign.ru/royalcat/tstor/src/delivery/graphql/resolver" + "git.kmsign.ru/royalcat/tstor/src/sources/qbittorrent" "git.kmsign.ru/royalcat/tstor/src/sources/torrent" "git.kmsign.ru/royalcat/tstor/src/vfs" "github.com/99designs/gqlgen/graphql" @@ -20,11 +21,15 @@ func noopDirective(ctx context.Context, obj interface{}, next graphql.Resolver) return next(ctx) } -func GraphQLHandler(service *torrent.Daemon, vfs vfs.Filesystem) http.Handler { +func GraphQLHandler(service *torrent.Daemon, qbitdaemon *qbittorrent.Daemon, vfs vfs.Filesystem) http.Handler { graphqlHandler := handler.NewDefaultServer( graph.NewExecutableSchema( graph.Config{ - Resolvers: &resolver.Resolver{Service: service, VFS: vfs}, + Resolvers: &resolver.Resolver{ + ATorrentDaemon: service, + QBitTorrentDaemon: qbitdaemon, + VFS: vfs, + }, Directives: graph.DirectiveRoot{ OneOf: graph.OneOf, Resolver: noopDirective, @@ -46,9 +51,9 @@ func GraphQLHandler(service *torrent.Daemon, vfs vfs.Filesystem) http.Handler { graphqlHandler.AddTransport(&transport.Websocket{}) graphqlHandler.AddTransport(&transport.SSE{}) graphqlHandler.AddTransport(&transport.UrlEncodedForm{}) - graphqlHandler.SetQueryCache(lru.New(1000)) + // graphqlHandler.SetQueryCache(lru.New[*ast.QueryDocument](1000)) graphqlHandler.Use(extension.Introspection{}) - graphqlHandler.Use(extension.AutomaticPersistedQuery{Cache: lru.New(100)}) + graphqlHandler.Use(extension.AutomaticPersistedQuery{Cache: lru.New[string](100)}) graphqlHandler.Use(otelgqlgen.Middleware( otelgqlgen.WithCreateSpanFromFields(func(ctx *graphql.FieldContext) bool { return ctx.Field.Directives.ForName("link") != nil diff --git a/src/sources/qbittorrent/api.go b/src/sources/qbittorrent/api.go new file mode 100644 index 0000000..3fb1ee9 --- /dev/null +++ b/src/sources/qbittorrent/api.go @@ -0,0 +1,27 @@ +package qbittorrent + +import ( + "context" + + "git.kmsign.ru/royalcat/tstor/pkg/qbittorrent" +) + +func (d *Daemon) ListTorrents(ctx context.Context) ([]*qbittorrent.TorrentInfo, error) { + return d.client.qb.Torrent().GetTorrents(ctx, &qbittorrent.TorrentOption{}) +} + +func (d *Daemon) SourceFiles(ctx context.Context, hash string) ([]string, error) { + d.sourceFilesMu.Lock() + defer d.sourceFilesMu.Unlock() + + out := make([]string, 0, 1) + for k, h := range d.sourceFiles { + if h != hash { + continue + } + + out = append(out, k) + } + + return out, nil +} diff --git a/src/sources/qbittorrent/daemon.go b/src/sources/qbittorrent/daemon.go index 3302b50..38e870d 100644 --- a/src/sources/qbittorrent/daemon.go +++ b/src/sources/qbittorrent/daemon.go @@ -9,6 +9,7 @@ import ( "os" "path" "path/filepath" + "sync" "time" "git.kmsign.ru/royalcat/tstor/pkg/qbittorrent" @@ -27,9 +28,13 @@ import ( var trace = otel.Tracer("git.kmsign.ru/royalcat/tstor/src/sources/qbittorrent") type Daemon struct { - proc *os.Process - qb qbittorrent.Client - client *cacheClient + proc *os.Process + qb qbittorrent.Client + client *cacheClient + + sourceFilesMu sync.Mutex + sourceFiles map[string]string // [sourcePath]infohash + dataDir string ur *iouring.IOURing log *rlog.Logger @@ -119,12 +124,13 @@ func NewDaemon(conf config.QBittorrent) (*Daemon, error) { } return &Daemon{ - qb: qb, - proc: proc, - dataDir: conf.DataFolder, - ur: ur, - client: wrapClient(qb), - log: rlog.Component("qbittorrent"), + qb: qb, + proc: proc, + dataDir: conf.DataFolder, + ur: ur, + sourceFiles: make(map[string]string), + client: wrapClient(qb), + log: rlog.Component("qbittorrent"), }, nil } @@ -146,7 +152,7 @@ func torrentDataPath(dataDir string, ih string) (string, error) { return filepath.Abs(path.Join(dataDir, ih)) } -func (fs *Daemon) GetTorrentFS(ctx context.Context, file vfs.File) (vfs.Filesystem, error) { +func (fs *Daemon) GetTorrentFS(ctx context.Context, sourcePath string, file vfs.File) (vfs.Filesystem, error) { ctx, span := trace.Start(ctx, "GetTorrentFS") defer span.End() @@ -171,6 +177,10 @@ func (fs *Daemon) GetTorrentFS(ctx context.Context, file vfs.File) (vfs.Filesyst return nil, fmt.Errorf("error syncing torrent state: %w", err) } + fs.sourceFilesMu.Lock() + fs.sourceFiles[sourcePath] = ih.HexString() + fs.sourceFilesMu.Unlock() + return newTorrentFS(ctx, fs.ur, fs.client, file.Name(), ih.HexString(), torrentPath) } diff --git a/src/sources/qbittorrent/fs.go b/src/sources/qbittorrent/fs.go index db91a4e..6f035e1 100644 --- a/src/sources/qbittorrent/fs.go +++ b/src/sources/qbittorrent/fs.go @@ -203,6 +203,7 @@ func openFile(ctx context.Context, ur *iouring.IOURing, client *cacheClient, tor return nil, err } + // FIXME error when file not started downloading file, err := os.OpenFile(path.Join(torrentDir, content.Name), os.O_RDONLY, 0) if err != nil { return nil, err diff --git a/src/sources/storage.go b/src/sources/storage.go index fe3b780..ca97548 100644 --- a/src/sources/storage.go +++ b/src/sources/storage.go @@ -10,8 +10,8 @@ import ( func NewHostedFS(sourceFS vfs.Filesystem, tsrv *qbittorrent.Daemon, ytdlpsrv *ytdlp.Daemon) vfs.Filesystem { factories := map[string]vfs.FsFactory{ - ".torrent": func(ctx context.Context, f vfs.File) (vfs.Filesystem, error) { - tfs, err := tsrv.GetTorrentFS(ctx, f) + ".torrent": func(ctx context.Context, sourcePath string, f vfs.File) (vfs.Filesystem, error) { + tfs, err := tsrv.GetTorrentFS(ctx, sourcePath, f) if err != nil { return nil, err } diff --git a/src/sources/torrent/fs.go b/src/sources/torrent/fs.go index 856e00b..388083c 100644 --- a/src/sources/torrent/fs.go +++ b/src/sources/torrent/fs.go @@ -39,7 +39,7 @@ var _ vfs.Filesystem = (*TorrentFS)(nil) const shortTimeout = time.Millisecond const lowTimeout = time.Second * 5 -func (s *Daemon) NewTorrentFs(ctx context.Context, f vfs.File) (vfs.Filesystem, error) { +func (s *Daemon) NewTorrentFs(ctx context.Context, _ string, f vfs.File) (vfs.Filesystem, error) { c, err := s.loadTorrent(ctx, f) if err != nil { return nil, err diff --git a/src/sources/ytdlp/daemon.go b/src/sources/ytdlp/daemon.go index 6666532..49d1e71 100644 --- a/src/sources/ytdlp/daemon.go +++ b/src/sources/ytdlp/daemon.go @@ -51,7 +51,7 @@ func (c *Daemon) sourceDir(s Source) string { return path.Join(c.dataDir, s.Name()) } -func (c *Daemon) BuildFS(ctx context.Context, f vfs.File) (vfs.Filesystem, error) { +func (c *Daemon) BuildFS(ctx context.Context, sourcePath string, f vfs.File) (vfs.Filesystem, error) { data, err := ctxio.ReadAll(ctx, f) if err != nil { return nil, fmt.Errorf("failed to read source file: %w", err) diff --git a/src/vfs/archive.go b/src/vfs/archive.go index 28a9490..c1eacc1 100644 --- a/src/vfs/archive.go +++ b/src/vfs/archive.go @@ -19,21 +19,21 @@ import ( ) var ArchiveFactories = map[string]FsFactory{ - ".zip": func(ctx context.Context, f File) (Filesystem, error) { + ".zip": func(ctx context.Context, _ string, f File) (Filesystem, error) { stat, err := f.Info() if err != nil { return nil, err } return NewArchive(ctx, stat.Name(), f, stat.Size(), ZipLoader) }, - ".rar": func(ctx context.Context, f File) (Filesystem, error) { + ".rar": func(ctx context.Context, _ string, f File) (Filesystem, error) { stat, err := f.Info() if err != nil { return nil, err } return NewArchive(ctx, stat.Name(), f, stat.Size(), RarLoader) }, - ".7z": func(ctx context.Context, f File) (Filesystem, error) { + ".7z": func(ctx context.Context, _ string, f File) (Filesystem, error) { stat, err := f.Info() if err != nil { return nil, err diff --git a/src/vfs/log.go b/src/vfs/log.go index bdaff99..70ae1d4 100644 --- a/src/vfs/log.go +++ b/src/vfs/log.go @@ -51,7 +51,7 @@ func WrapLogFS(vfs Filesystem) (*LogFS, error) { fs: vfs, log: rlog.Component("logfs"), tel: &fsTelemetry{openedFiles: openedFiles}, - timeout: time.Minute * 3, + timeout: time.Minute * 5, readTimeout: time.Minute, }, nil } diff --git a/src/vfs/resolver.go b/src/vfs/resolver.go index 09cd6aa..9d4850e 100644 --- a/src/vfs/resolver.go +++ b/src/vfs/resolver.go @@ -223,7 +223,7 @@ func (r *ResolverFS) Type() fs.FileMode { var _ Filesystem = &ResolverFS{} // It factory responsobility to close file -type FsFactory func(ctx context.Context, f File) (Filesystem, error) +type FsFactory func(ctx context.Context, sourcePath string, f File) (Filesystem, error) func NewResolver(factories map[string]FsFactory) *Resolver { return &Resolver{ @@ -272,7 +272,7 @@ func (r *Resolver) nestedFs(ctx context.Context, fsPath string, file File) (File continue } - nestedFs, err := nestFactory(ctx, file) + nestedFs, err := nestFactory(ctx, fsPath, file) if err != nil { return nil, fmt.Errorf("error calling nest factory: %s with error: %w", fsPath, err) } @@ -348,7 +348,7 @@ PARTS_LOOP: } // it is factory responsibility to close file handler then needed - nestedFs, err := nestFactory(ctx, fsFile) + nestedFs, err := nestFactory(ctx, name, fsFile) if err != nil { return "", nil, "", fmt.Errorf("error creating filesystem from file: %s with error: %w", fsPath, err) } diff --git a/ui/lib/api/schema.graphql b/ui/lib/api/schema.graphql index 7992756..6173d43 100644 --- a/ui/lib/api/schema.graphql +++ b/ui/lib/api/schema.graphql @@ -56,8 +56,17 @@ interface Progress { current: Int! total: Int! } +type QBitTorrentDaemonQuery { + torrents: [QTorrent!]! @resolver +} +type QTorrent { + name: String! + hash: String! + sourceFiles: [String!]! @resolver +} type Query { torrentDaemon: TorrentDaemonQuery @resolver + qbittorrentDaemon: QBitTorrentDaemonQuery @resolver fsEntry(path: String!): FsEntry } type ResolverFS implements Dir & FsEntry {