This commit is contained in:
parent
63e63c1c37
commit
aa0affb019
30 changed files with 1338 additions and 242 deletions
|
@ -17,6 +17,7 @@ import (
|
||||||
wnfs "git.kmsign.ru/royalcat/tstor/pkg/go-nfs"
|
wnfs "git.kmsign.ru/royalcat/tstor/pkg/go-nfs"
|
||||||
"git.kmsign.ru/royalcat/tstor/pkg/rlog"
|
"git.kmsign.ru/royalcat/tstor/pkg/rlog"
|
||||||
"git.kmsign.ru/royalcat/tstor/src/config"
|
"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"
|
||||||
"git.kmsign.ru/royalcat/tstor/src/sources/qbittorrent"
|
"git.kmsign.ru/royalcat/tstor/src/sources/qbittorrent"
|
||||||
"git.kmsign.ru/royalcat/tstor/src/sources/ytdlp"
|
"git.kmsign.ru/royalcat/tstor/src/sources/ytdlp"
|
||||||
|
@ -103,14 +104,14 @@ func run(configPath string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
qtsrv, err := qbittorrent.NewDaemon(conf.Sources.QBittorrent)
|
qtdaemon, err := qbittorrent.NewDaemon(conf.Sources.QBittorrent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error creating qbittorrent daemon: %w", err)
|
return fmt.Errorf("error creating qbittorrent daemon: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
sfs := sources.NewHostedFS(
|
sfs := sources.NewHostedFS(
|
||||||
vfs.NewCtxBillyFs("/", ctxbilly.WrapFileSystem(sourceFs)),
|
vfs.NewCtxBillyFs("/", ctxbilly.WrapFileSystem(sourceFs)),
|
||||||
qtsrv, ytdlpsrv,
|
qtdaemon, ytdlpsrv,
|
||||||
)
|
)
|
||||||
sfs, err = vfs.WrapLogFS(sfs)
|
sfs, err = vfs.WrapLogFS(sfs)
|
||||||
if err != nil {
|
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)
|
sigChan := make(chan os.Signal, 1)
|
||||||
signal.Notify(sigChan, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
|
signal.Notify(sigChan, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
|
||||||
<-sigChan
|
<-sigChan
|
||||||
|
|
||||||
return errors.Join(
|
return errors.Join(
|
||||||
// tsrv.Close(ctx),
|
// tsrv.Close(ctx),
|
||||||
qtsrv.Close(ctx),
|
qtdaemon.Close(ctx),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
24
go.mod
24
go.mod
|
@ -1,11 +1,11 @@
|
||||||
module git.kmsign.ru/royalcat/tstor
|
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
|
replace github.com/iceber/iouring-go => github.com/royalcat/iouring-go v0.0.0-20240925200811-286062ac1b23
|
||||||
|
|
||||||
require (
|
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-go/otelslog v0.1.1
|
||||||
github.com/agoda-com/opentelemetry-logs-go v0.5.0
|
github.com/agoda-com/opentelemetry-logs-go v0.5.0
|
||||||
github.com/anacrolix/dht/v2 v2.21.1
|
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-multi v1.0.2
|
||||||
github.com/samber/slog-zerolog v1.0.0
|
github.com/samber/slog-zerolog v1.0.0
|
||||||
github.com/stretchr/testify v1.9.0
|
github.com/stretchr/testify v1.9.0
|
||||||
github.com/urfave/cli/v2 v2.27.2
|
github.com/urfave/cli/v2 v2.27.4
|
||||||
github.com/vektah/gqlparser/v2 v2.5.16
|
github.com/vektah/gqlparser/v2 v2.5.17
|
||||||
github.com/willscott/go-nfs-client v0.0.0-20240104095149-b44639837b00
|
github.com/willscott/go-nfs-client v0.0.0-20240104095149-b44639837b00
|
||||||
github.com/willscott/memphis v0.0.0-20210922141505-529d4987ab7e
|
github.com/willscott/memphis v0.0.0-20210922141505-529d4987ab7e
|
||||||
go.opentelemetry.io/otel v1.28.0
|
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/sdk/metric v1.28.0
|
||||||
go.opentelemetry.io/otel/trace v1.28.0
|
go.opentelemetry.io/otel/trace v1.28.0
|
||||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842
|
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842
|
||||||
golang.org/x/net v0.26.0
|
golang.org/x/net v0.29.0
|
||||||
golang.org/x/sync v0.7.0
|
golang.org/x/sync v0.8.0
|
||||||
golang.org/x/sys v0.22.0
|
golang.org/x/sys v0.25.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
@ -171,18 +171,18 @@ require (
|
||||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
github.com/valyala/fasttemplate v1.2.2 // indirect
|
github.com/valyala/fasttemplate v1.2.2 // indirect
|
||||||
github.com/warpfork/go-errcat v0.0.0-20180917083543-335044ffc86e // 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.etcd.io/bbolt v1.3.9 // indirect
|
||||||
go.opencensus.io v0.24.0 // indirect
|
go.opencensus.io v0.24.0 // indirect
|
||||||
go.opentelemetry.io/contrib v1.26.0 // indirect
|
go.opentelemetry.io/contrib v1.26.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect
|
||||||
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
|
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
|
||||||
go4.org v0.0.0-20230225012048-214862532bf5 // indirect
|
go4.org v0.0.0-20230225012048-214862532bf5 // indirect
|
||||||
golang.org/x/crypto v0.24.0 // indirect
|
golang.org/x/crypto v0.27.0 // indirect
|
||||||
golang.org/x/mod v0.18.0 // indirect
|
golang.org/x/mod v0.20.0 // indirect
|
||||||
golang.org/x/text v0.16.0 // indirect
|
golang.org/x/text v0.18.0 // indirect
|
||||||
golang.org/x/time v0.5.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/api v0.0.0-20240701130421-f6361c86f094 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc 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
|
google.golang.org/grpc v1.64.0 // indirect
|
||||||
|
|
44
go.sum
44
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=
|
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 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU=
|
||||||
filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
|
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.55 h1:3vzrNWYyzSZjGDFo68e5j9sSauLxfKvLp+6ioRokVtM=
|
||||||
github.com/99designs/gqlgen v0.17.49/go.mod h1:tC8YFVZMed81x7UJ7ORUwXF4Kn6SXuucFqQBhN8+BU0=
|
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/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/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||||
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
|
github.com/OneOfOne/xxhash v1.2.2 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 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc=
|
||||||
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
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 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.4 h1:o1owoI+02Eb+K107p27wEX9Bb8eqIoZCfLXloLUSWJ8=
|
||||||
github.com/urfave/cli/v2 v2.27.2/go.mod h1:g0+79LmHHATl7DAcHO99smiR/T7uGLw84w8Y42x+4eM=
|
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 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
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 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
|
||||||
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
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.17 h1:9At7WblLV7/36nulgekUgIaqHZWn5hxqluxrxGUhOmI=
|
||||||
github.com/vektah/gqlparser/v2 v2.5.16/go.mod h1:1lz1OeCqgQbQepsGxPVywrjdBHW2T08PUS3pJqepRww=
|
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 h1:FIB2fi7XJGHIdf5rWNsfFQqatIKxutT45G+wNuMQNgs=
|
||||||
github.com/warpfork/go-errcat v0.0.0-20180917083543-335044ffc86e/go.mod h1:/qe02xr3jvTUz8u/PV0FHGpP8t96OQNP7U9BJMwMLEw=
|
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=
|
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/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 h1:1eHCP4w7tMmpfFBdrd5ff+vYU9THtrtA1yM9f0TLlJw=
|
||||||
github.com/willscott/memphis v0.0.0-20210922141505-529d4987ab7e/go.mod h1:59vHBW4EpjiL5oiqgCrBp1Tc9JXRzKCNMEOaGmNfSHo=
|
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-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
|
||||||
github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913/go.mod h1:4aEEwZQutDLsQv2Deui4iYQ6DWTxR14g6m8Wv88+Xqk=
|
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.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/yuin/goldmark v1.4.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.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.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.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||||
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
|
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
|
||||||
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
|
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-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-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
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.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
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.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
|
||||||
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
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-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
@ -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.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
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.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||||
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
|
golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
|
||||||
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
|
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-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/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-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.1.0/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.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
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-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
@ -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.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.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.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
|
||||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
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-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
|
@ -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.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.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.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
|
||||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
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-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
golang.org/x/time v0.5.0 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.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
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.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
|
||||||
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
|
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-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
type Query {
|
type Query {
|
||||||
torrentDaemon: TorrentDaemonQuery @resolver
|
torrentDaemon: TorrentDaemonQuery @resolver
|
||||||
|
qbittorrentDaemon: QBitTorrentDaemonQuery @resolver
|
||||||
|
|
||||||
fsEntry(path: String!): FsEntry
|
fsEntry(path: String!): FsEntry
|
||||||
}
|
}
|
||||||
|
|
3
graphql/sources/qbittorrent_query.graphql
Normal file
3
graphql/sources/qbittorrent_query.graphql
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
type QBitTorrentDaemonQuery {
|
||||||
|
torrents: [QTorrent!]! @resolver
|
||||||
|
}
|
5
graphql/sources/qbittorrent_types.graphql
Normal file
5
graphql/sources/qbittorrent_types.graphql
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
type QTorrent {
|
||||||
|
name: String!
|
||||||
|
hash: String!
|
||||||
|
sourceFiles: [String!]! @resolver
|
||||||
|
}
|
File diff suppressed because it is too large
Load diff
|
@ -96,6 +96,16 @@ type Pagination struct {
|
||||||
Limit int64 `json:"limit"`
|
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 {
|
type Query struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ package resolver
|
||||||
|
|
||||||
// This file will be automatically regenerated based on the schema, any resolver implementations
|
// 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.
|
// 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 (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
|
@ -2,7 +2,7 @@ package resolver
|
||||||
|
|
||||||
// This file will be automatically regenerated based on the schema, any resolver implementations
|
// 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.
|
// 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 (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -49,7 +49,7 @@ func (r *mutationResolver) UploadFile(ctx context.Context, dir string, file grap
|
||||||
|
|
||||||
// DedupeStorage is the resolver for the dedupeStorage field.
|
// DedupeStorage is the resolver for the dedupeStorage field.
|
||||||
func (r *mutationResolver) DedupeStorage(ctx context.Context) (int64, error) {
|
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 {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
38
src/delivery/graphql/resolver/qbittorrent_query.resolvers.go
Normal file
38
src/delivery/graphql/resolver/qbittorrent_query.resolvers.go
Normal file
|
@ -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 }
|
22
src/delivery/graphql/resolver/qbittorrent_types.resolvers.go
Normal file
22
src/delivery/graphql/resolver/qbittorrent_types.resolvers.go
Normal file
|
@ -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 }
|
|
@ -2,7 +2,7 @@ package resolver
|
||||||
|
|
||||||
// This file will be automatically regenerated based on the schema, any resolver implementations
|
// 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.
|
// 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 (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -16,6 +16,11 @@ func (r *queryResolver) TorrentDaemon(ctx context.Context) (*model.TorrentDaemon
|
||||||
return &model.TorrentDaemonQuery{}, nil
|
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.
|
// FsEntry is the resolver for the fsEntry field.
|
||||||
func (r *queryResolver) FsEntry(ctx context.Context, path string) (model.FsEntry, error) {
|
func (r *queryResolver) FsEntry(ctx context.Context, path string) (model.FsEntry, error) {
|
||||||
entry, err := r.VFS.Stat(ctx, path)
|
entry, err := r.VFS.Stat(ctx, path)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package resolver
|
package resolver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"git.kmsign.ru/royalcat/tstor/src/sources/qbittorrent"
|
||||||
"git.kmsign.ru/royalcat/tstor/src/sources/torrent"
|
"git.kmsign.ru/royalcat/tstor/src/sources/torrent"
|
||||||
"git.kmsign.ru/royalcat/tstor/src/vfs"
|
"git.kmsign.ru/royalcat/tstor/src/vfs"
|
||||||
"github.com/go-git/go-billy/v5"
|
"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.
|
// It serves as dependency injection for your app, add any dependencies you require here.
|
||||||
|
|
||||||
type Resolver struct {
|
type Resolver struct {
|
||||||
Service *torrent.Daemon
|
ATorrentDaemon *torrent.Daemon
|
||||||
VFS vfs.Filesystem
|
QBitTorrentDaemon *qbittorrent.Daemon
|
||||||
SourceFS billy.Filesystem
|
VFS vfs.Filesystem
|
||||||
|
SourceFS billy.Filesystem
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ package resolver
|
||||||
|
|
||||||
// This file will be automatically regenerated based on the schema, any resolver implementations
|
// 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.
|
// 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 (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -20,7 +20,7 @@ func (r *subscriptionResolver) TaskProgress(ctx context.Context, taskID string)
|
||||||
// TorrentDownloadUpdates is the resolver for the torrentDownloadUpdates field.
|
// TorrentDownloadUpdates is the resolver for the torrentDownloadUpdates field.
|
||||||
func (r *subscriptionResolver) TorrentDownloadUpdates(ctx context.Context) (<-chan *model.TorrentProgress, error) {
|
func (r *subscriptionResolver) TorrentDownloadUpdates(ctx context.Context) (<-chan *model.TorrentProgress, error) {
|
||||||
out := make(chan *model.TorrentProgress)
|
out := make(chan *model.TorrentProgress)
|
||||||
progress, err := r.Service.DownloadProgress(ctx)
|
progress, err := r.ATorrentDaemon.DownloadProgress(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ package resolver
|
||||||
|
|
||||||
// This file will be automatically regenerated based on the schema, any resolver implementations
|
// 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.
|
// 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 (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -15,7 +15,7 @@ import (
|
||||||
// ValidateTorrent is the resolver for the validateTorrent field.
|
// ValidateTorrent is the resolver for the validateTorrent field.
|
||||||
func (r *torrentDaemonMutationResolver) ValidateTorrent(ctx context.Context, obj *model.TorrentDaemonMutation, filter model.TorrentFilter) (bool, error) {
|
func (r *torrentDaemonMutationResolver) ValidateTorrent(ctx context.Context, obj *model.TorrentDaemonMutation, filter model.TorrentFilter) (bool, error) {
|
||||||
if filter.Infohash != nil {
|
if filter.Infohash != nil {
|
||||||
t, err := r.Resolver.Service.GetTorrent(*filter.Infohash)
|
t, err := r.Resolver.ATorrentDaemon.GetTorrent(*filter.Infohash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ func (r *torrentDaemonMutationResolver) ValidateTorrent(ctx context.Context, obj
|
||||||
}
|
}
|
||||||
|
|
||||||
if filter.Everything != nil && *filter.Everything {
|
if filter.Everything != nil && *filter.Everything {
|
||||||
torrents, err := r.Resolver.Service.ListTorrents(ctx)
|
torrents, err := r.Resolver.ATorrentDaemon.ListTorrents(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ func (r *torrentDaemonMutationResolver) ValidateTorrent(ctx context.Context, obj
|
||||||
|
|
||||||
// SetTorrentPriority is the resolver for the setTorrentPriority field.
|
// 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) {
|
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 {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
@ -74,19 +74,19 @@ func (r *torrentDaemonMutationResolver) SetTorrentPriority(ctx context.Context,
|
||||||
|
|
||||||
// Cleanup is the resolver for the cleanup field.
|
// 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) {
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if files != nil && *files {
|
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{
|
return &model.CleanupResponse{
|
||||||
Count: int64(len(r)),
|
Count: int64(len(r)),
|
||||||
List: r,
|
List: r,
|
||||||
}, err
|
}, err
|
||||||
} else {
|
} else {
|
||||||
r, err := r.Service.Storage.CleanupDirs(ctx, torrents, dryRun)
|
r, err := r.ATorrentDaemon.Storage.CleanupDirs(ctx, torrents, dryRun)
|
||||||
return &model.CleanupResponse{
|
return &model.CleanupResponse{
|
||||||
Count: int64(len(r)),
|
Count: int64(len(r)),
|
||||||
List: r,
|
List: r,
|
||||||
|
|
|
@ -2,7 +2,7 @@ package resolver
|
||||||
|
|
||||||
// This file will be automatically regenerated based on the schema, any resolver implementations
|
// 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.
|
// 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 (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -13,13 +13,12 @@ import (
|
||||||
graph "git.kmsign.ru/royalcat/tstor/src/delivery/graphql"
|
graph "git.kmsign.ru/royalcat/tstor/src/delivery/graphql"
|
||||||
"git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model"
|
"git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model"
|
||||||
"git.kmsign.ru/royalcat/tstor/src/sources/torrent"
|
"git.kmsign.ru/royalcat/tstor/src/sources/torrent"
|
||||||
|
|
||||||
tinfohash "github.com/anacrolix/torrent/types/infohash"
|
tinfohash "github.com/anacrolix/torrent/types/infohash"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Torrents is the resolver for the torrents field.
|
// Torrents is the resolver for the torrents field.
|
||||||
func (r *torrentDaemonQueryResolver) Torrents(ctx context.Context, obj *model.TorrentDaemonQuery, filter *model.TorrentsFilter) ([]*model.Torrent, error) {
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
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.
|
// ClientStats is the resolver for the clientStats field.
|
||||||
func (r *torrentDaemonQueryResolver) ClientStats(ctx context.Context, obj *model.TorrentDaemonQuery) (*model.TorrentClientStats, error) {
|
func (r *torrentDaemonQueryResolver) ClientStats(ctx context.Context, obj *model.TorrentDaemonQuery) (*model.TorrentClientStats, error) {
|
||||||
stats := r.Service.Stats()
|
stats := r.ATorrentDaemon.Stats()
|
||||||
return &model.TorrentClientStats{
|
return &model.TorrentClientStats{
|
||||||
BytesWritten: stats.BytesWritten.Int64(),
|
BytesWritten: stats.BytesWritten.Int64(),
|
||||||
BytesRead: stats.BytesRead.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) {
|
func (r *torrentDaemonQueryResolver) StatsHistory(ctx context.Context, obj *model.TorrentDaemonQuery, since time.Time, infohash *string) ([]*model.TorrentStats, error) {
|
||||||
var stats []torrent.TorrentStats
|
var stats []torrent.TorrentStats
|
||||||
if infohash == nil {
|
if infohash == nil {
|
||||||
stats, err := r.Service.StatsHistory(ctx, since)
|
stats, err := r.ATorrentDaemon.StatsHistory(ctx, since)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return model.Apply(stats, model.MapTorrentStats), nil
|
return model.Apply(stats, model.MapTorrentStats), nil
|
||||||
} else if *infohash == "total" {
|
} else if *infohash == "total" {
|
||||||
var err error
|
var err error
|
||||||
stats, err = r.Service.TotalStatsHistory(ctx, since)
|
stats, err = r.ATorrentDaemon.TotalStatsHistory(ctx, since)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ih := tinfohash.FromHexString(*infohash)
|
ih := tinfohash.FromHexString(*infohash)
|
||||||
var err error
|
var err error
|
||||||
stats, err = r.Service.TorrentStatsHistory(ctx, since, ih)
|
stats, err = r.ATorrentDaemon.TorrentStatsHistory(ctx, since, ih)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ package resolver
|
||||||
|
|
||||||
// This file will be automatically regenerated based on the schema, any resolver implementations
|
// 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.
|
// 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 (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
|
|
||||||
"git.kmsign.ru/royalcat/tstor/pkg/rlog"
|
"git.kmsign.ru/royalcat/tstor/pkg/rlog"
|
||||||
"git.kmsign.ru/royalcat/tstor/src/config"
|
"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/sources/torrent"
|
||||||
"git.kmsign.ru/royalcat/tstor/src/vfs"
|
"git.kmsign.ru/royalcat/tstor/src/vfs"
|
||||||
echopprof "github.com/labstack/echo-contrib/pprof"
|
echopprof "github.com/labstack/echo-contrib/pprof"
|
||||||
|
@ -15,7 +16,7 @@ import (
|
||||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
"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()
|
log := slog.With()
|
||||||
|
|
||||||
r := echo.New()
|
r := echo.New()
|
||||||
|
@ -28,7 +29,7 @@ func Run(s *torrent.Daemon, vfs vfs.Filesystem, logPath string, cfg *config.Sett
|
||||||
|
|
||||||
echopprof.Register(r)
|
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()))
|
r.GET("/metrics", echo.WrapHandler(promhttp.Handler()))
|
||||||
|
|
||||||
log.Info("starting webserver", "host", fmt.Sprintf("%s:%d", cfg.WebUi.IP, cfg.WebUi.Port))
|
log.Info("starting webserver", "host", fmt.Sprintf("%s:%d", cfg.WebUi.IP, cfg.WebUi.Port))
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
|
|
||||||
graph "git.kmsign.ru/royalcat/tstor/src/delivery/graphql"
|
graph "git.kmsign.ru/royalcat/tstor/src/delivery/graphql"
|
||||||
"git.kmsign.ru/royalcat/tstor/src/delivery/graphql/resolver"
|
"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/sources/torrent"
|
||||||
"git.kmsign.ru/royalcat/tstor/src/vfs"
|
"git.kmsign.ru/royalcat/tstor/src/vfs"
|
||||||
"github.com/99designs/gqlgen/graphql"
|
"github.com/99designs/gqlgen/graphql"
|
||||||
|
@ -20,11 +21,15 @@ func noopDirective(ctx context.Context, obj interface{}, next graphql.Resolver)
|
||||||
return next(ctx)
|
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(
|
graphqlHandler := handler.NewDefaultServer(
|
||||||
graph.NewExecutableSchema(
|
graph.NewExecutableSchema(
|
||||||
graph.Config{
|
graph.Config{
|
||||||
Resolvers: &resolver.Resolver{Service: service, VFS: vfs},
|
Resolvers: &resolver.Resolver{
|
||||||
|
ATorrentDaemon: service,
|
||||||
|
QBitTorrentDaemon: qbitdaemon,
|
||||||
|
VFS: vfs,
|
||||||
|
},
|
||||||
Directives: graph.DirectiveRoot{
|
Directives: graph.DirectiveRoot{
|
||||||
OneOf: graph.OneOf,
|
OneOf: graph.OneOf,
|
||||||
Resolver: noopDirective,
|
Resolver: noopDirective,
|
||||||
|
@ -46,9 +51,9 @@ func GraphQLHandler(service *torrent.Daemon, vfs vfs.Filesystem) http.Handler {
|
||||||
graphqlHandler.AddTransport(&transport.Websocket{})
|
graphqlHandler.AddTransport(&transport.Websocket{})
|
||||||
graphqlHandler.AddTransport(&transport.SSE{})
|
graphqlHandler.AddTransport(&transport.SSE{})
|
||||||
graphqlHandler.AddTransport(&transport.UrlEncodedForm{})
|
graphqlHandler.AddTransport(&transport.UrlEncodedForm{})
|
||||||
graphqlHandler.SetQueryCache(lru.New(1000))
|
// graphqlHandler.SetQueryCache(lru.New[*ast.QueryDocument](1000))
|
||||||
graphqlHandler.Use(extension.Introspection{})
|
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(
|
graphqlHandler.Use(otelgqlgen.Middleware(
|
||||||
otelgqlgen.WithCreateSpanFromFields(func(ctx *graphql.FieldContext) bool {
|
otelgqlgen.WithCreateSpanFromFields(func(ctx *graphql.FieldContext) bool {
|
||||||
return ctx.Field.Directives.ForName("link") != nil
|
return ctx.Field.Directives.ForName("link") != nil
|
||||||
|
|
27
src/sources/qbittorrent/api.go
Normal file
27
src/sources/qbittorrent/api.go
Normal file
|
@ -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
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.kmsign.ru/royalcat/tstor/pkg/qbittorrent"
|
"git.kmsign.ru/royalcat/tstor/pkg/qbittorrent"
|
||||||
|
@ -27,9 +28,13 @@ import (
|
||||||
var trace = otel.Tracer("git.kmsign.ru/royalcat/tstor/src/sources/qbittorrent")
|
var trace = otel.Tracer("git.kmsign.ru/royalcat/tstor/src/sources/qbittorrent")
|
||||||
|
|
||||||
type Daemon struct {
|
type Daemon struct {
|
||||||
proc *os.Process
|
proc *os.Process
|
||||||
qb qbittorrent.Client
|
qb qbittorrent.Client
|
||||||
client *cacheClient
|
client *cacheClient
|
||||||
|
|
||||||
|
sourceFilesMu sync.Mutex
|
||||||
|
sourceFiles map[string]string // [sourcePath]infohash
|
||||||
|
|
||||||
dataDir string
|
dataDir string
|
||||||
ur *iouring.IOURing
|
ur *iouring.IOURing
|
||||||
log *rlog.Logger
|
log *rlog.Logger
|
||||||
|
@ -119,12 +124,13 @@ func NewDaemon(conf config.QBittorrent) (*Daemon, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Daemon{
|
return &Daemon{
|
||||||
qb: qb,
|
qb: qb,
|
||||||
proc: proc,
|
proc: proc,
|
||||||
dataDir: conf.DataFolder,
|
dataDir: conf.DataFolder,
|
||||||
ur: ur,
|
ur: ur,
|
||||||
client: wrapClient(qb),
|
sourceFiles: make(map[string]string),
|
||||||
log: rlog.Component("qbittorrent"),
|
client: wrapClient(qb),
|
||||||
|
log: rlog.Component("qbittorrent"),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,7 +152,7 @@ func torrentDataPath(dataDir string, ih string) (string, error) {
|
||||||
return filepath.Abs(path.Join(dataDir, ih))
|
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")
|
ctx, span := trace.Start(ctx, "GetTorrentFS")
|
||||||
defer span.End()
|
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)
|
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)
|
return newTorrentFS(ctx, fs.ur, fs.client, file.Name(), ih.HexString(), torrentPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -203,6 +203,7 @@ func openFile(ctx context.Context, ur *iouring.IOURing, client *cacheClient, tor
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME error when file not started downloading
|
||||||
file, err := os.OpenFile(path.Join(torrentDir, content.Name), os.O_RDONLY, 0)
|
file, err := os.OpenFile(path.Join(torrentDir, content.Name), os.O_RDONLY, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -10,8 +10,8 @@ import (
|
||||||
|
|
||||||
func NewHostedFS(sourceFS vfs.Filesystem, tsrv *qbittorrent.Daemon, ytdlpsrv *ytdlp.Daemon) vfs.Filesystem {
|
func NewHostedFS(sourceFS vfs.Filesystem, tsrv *qbittorrent.Daemon, ytdlpsrv *ytdlp.Daemon) vfs.Filesystem {
|
||||||
factories := map[string]vfs.FsFactory{
|
factories := map[string]vfs.FsFactory{
|
||||||
".torrent": func(ctx context.Context, f vfs.File) (vfs.Filesystem, error) {
|
".torrent": func(ctx context.Context, sourcePath string, f vfs.File) (vfs.Filesystem, error) {
|
||||||
tfs, err := tsrv.GetTorrentFS(ctx, f)
|
tfs, err := tsrv.GetTorrentFS(ctx, sourcePath, f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ var _ vfs.Filesystem = (*TorrentFS)(nil)
|
||||||
const shortTimeout = time.Millisecond
|
const shortTimeout = time.Millisecond
|
||||||
const lowTimeout = time.Second * 5
|
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)
|
c, err := s.loadTorrent(ctx, f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -51,7 +51,7 @@ func (c *Daemon) sourceDir(s Source) string {
|
||||||
return path.Join(c.dataDir, s.Name())
|
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)
|
data, err := ctxio.ReadAll(ctx, f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to read source file: %w", err)
|
return nil, fmt.Errorf("failed to read source file: %w", err)
|
||||||
|
|
|
@ -19,21 +19,21 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var ArchiveFactories = map[string]FsFactory{
|
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()
|
stat, err := f.Info()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return NewArchive(ctx, stat.Name(), f, stat.Size(), ZipLoader)
|
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()
|
stat, err := f.Info()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return NewArchive(ctx, stat.Name(), f, stat.Size(), RarLoader)
|
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()
|
stat, err := f.Info()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -51,7 +51,7 @@ func WrapLogFS(vfs Filesystem) (*LogFS, error) {
|
||||||
fs: vfs,
|
fs: vfs,
|
||||||
log: rlog.Component("logfs"),
|
log: rlog.Component("logfs"),
|
||||||
tel: &fsTelemetry{openedFiles: openedFiles},
|
tel: &fsTelemetry{openedFiles: openedFiles},
|
||||||
timeout: time.Minute * 3,
|
timeout: time.Minute * 5,
|
||||||
readTimeout: time.Minute,
|
readTimeout: time.Minute,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -223,7 +223,7 @@ func (r *ResolverFS) Type() fs.FileMode {
|
||||||
var _ Filesystem = &ResolverFS{}
|
var _ Filesystem = &ResolverFS{}
|
||||||
|
|
||||||
// It factory responsobility to close file
|
// 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 {
|
func NewResolver(factories map[string]FsFactory) *Resolver {
|
||||||
return &Resolver{
|
return &Resolver{
|
||||||
|
@ -272,7 +272,7 @@ func (r *Resolver) nestedFs(ctx context.Context, fsPath string, file File) (File
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
nestedFs, err := nestFactory(ctx, file)
|
nestedFs, err := nestFactory(ctx, fsPath, file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error calling nest factory: %s with error: %w", fsPath, err)
|
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
|
// it is factory responsibility to close file handler then needed
|
||||||
|
|
||||||
nestedFs, err := nestFactory(ctx, fsFile)
|
nestedFs, err := nestFactory(ctx, name, fsFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, "", fmt.Errorf("error creating filesystem from file: %s with error: %w", fsPath, err)
|
return "", nil, "", fmt.Errorf("error creating filesystem from file: %s with error: %w", fsPath, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,8 +56,17 @@ interface Progress {
|
||||||
current: Int!
|
current: Int!
|
||||||
total: Int!
|
total: Int!
|
||||||
}
|
}
|
||||||
|
type QBitTorrentDaemonQuery {
|
||||||
|
torrents: [QTorrent!]! @resolver
|
||||||
|
}
|
||||||
|
type QTorrent {
|
||||||
|
name: String!
|
||||||
|
hash: String!
|
||||||
|
sourceFiles: [String!]! @resolver
|
||||||
|
}
|
||||||
type Query {
|
type Query {
|
||||||
torrentDaemon: TorrentDaemonQuery @resolver
|
torrentDaemon: TorrentDaemonQuery @resolver
|
||||||
|
qbittorrentDaemon: QBitTorrentDaemonQuery @resolver
|
||||||
fsEntry(path: String!): FsEntry
|
fsEntry(path: String!): FsEntry
|
||||||
}
|
}
|
||||||
type ResolverFS implements Dir & FsEntry {
|
type ResolverFS implements Dir & FsEntry {
|
||||||
|
|
Loading…
Reference in a new issue