mirror of https://github.com/Xhofe/alist
feat(archive): archive manage (#7817)
* feat(archive): archive management * fix(ftp-server): remove duplicate ReadAtSeeker realization * fix(archive): bad seeking of SeekableStream * fix(archive): split internal and driver extraction api * feat(archive): patch * fix(shutdown): clear decompress upload tasks * chore * feat(archive): support .iso format * chorepull/7851/head
parent
ab22cf8233
commit
bb40e2e2cd
|
@ -0,0 +1,54 @@
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// KillCmd represents the kill command
|
||||||
|
var KillCmd = &cobra.Command{
|
||||||
|
Use: "kill",
|
||||||
|
Short: "Force kill alist server process by daemon/pid file",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
kill()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func kill() {
|
||||||
|
initDaemon()
|
||||||
|
if pid == -1 {
|
||||||
|
log.Info("Seems not have been started. Try use `alist start` to start server.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
process, err := os.FindProcess(pid)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("failed to find process by pid: %d, reason: %v", pid, process)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = process.Kill()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("failed to kill process %d: %v", pid, err)
|
||||||
|
} else {
|
||||||
|
log.Info("killed process: ", pid)
|
||||||
|
}
|
||||||
|
err = os.Remove(pidFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("failed to remove pid file")
|
||||||
|
}
|
||||||
|
pid = -1
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
RootCmd.AddCommand(KillCmd)
|
||||||
|
|
||||||
|
// Here you will define your flags and configuration settings.
|
||||||
|
|
||||||
|
// Cobra supports Persistent Flags which will work for this command
|
||||||
|
// and all subcommands, e.g.:
|
||||||
|
// stopCmd.PersistentFlags().String("foo", "", "A help for foo")
|
||||||
|
|
||||||
|
// Cobra supports local flags which will only run when this command
|
||||||
|
// is called directly, e.g.:
|
||||||
|
// stopCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ import (
|
||||||
|
|
||||||
"github.com/alist-org/alist/v3/cmd/flags"
|
"github.com/alist-org/alist/v3/cmd/flags"
|
||||||
_ "github.com/alist-org/alist/v3/drivers"
|
_ "github.com/alist-org/alist/v3/drivers"
|
||||||
|
_ "github.com/alist-org/alist/v3/internal/archive"
|
||||||
_ "github.com/alist-org/alist/v3/internal/offline_download"
|
_ "github.com/alist-org/alist/v3/internal/offline_download"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
ftpserver "github.com/KirCute/ftpserverlib-pasvportmap"
|
ftpserver "github.com/KirCute/ftpserverlib-pasvportmap"
|
||||||
"github.com/KirCute/sftpd-alist"
|
"github.com/KirCute/sftpd-alist"
|
||||||
|
"github.com/alist-org/alist/v3/internal/fs"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
@ -159,6 +160,7 @@ the address is defined in config file`,
|
||||||
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
||||||
<-quit
|
<-quit
|
||||||
utils.Log.Println("Shutdown server...")
|
utils.Log.Println("Shutdown server...")
|
||||||
|
fs.ArchiveContentUploadTaskManager.RemoveAll()
|
||||||
Release()
|
Release()
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
//go:build !windows
|
||||||
Copyright © 2022 NAME HERE <EMAIL ADDRESS>
|
|
||||||
*/
|
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
@ -30,11 +30,11 @@ func stop() {
|
||||||
log.Errorf("failed to find process by pid: %d, reason: %v", pid, process)
|
log.Errorf("failed to find process by pid: %d, reason: %v", pid, process)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = process.Kill()
|
err = process.Signal(syscall.SIGTERM)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failed to kill process %d: %v", pid, err)
|
log.Errorf("failed to terminate process %d: %v", pid, err)
|
||||||
} else {
|
} else {
|
||||||
log.Info("killed process: ", pid)
|
log.Info("terminated process: ", pid)
|
||||||
}
|
}
|
||||||
err = os.Remove(pidFile)
|
err = os.Remove(pidFile)
|
||||||
if err != nil {
|
if err != nil {
|
|
@ -0,0 +1,34 @@
|
||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StopCmd represents the stop command
|
||||||
|
var StopCmd = &cobra.Command{
|
||||||
|
Use: "stop",
|
||||||
|
Short: "Same as the kill command",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
stop()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func stop() {
|
||||||
|
kill()
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
RootCmd.AddCommand(StopCmd)
|
||||||
|
|
||||||
|
// Here you will define your flags and configuration settings.
|
||||||
|
|
||||||
|
// Cobra supports Persistent Flags which will work for this command
|
||||||
|
// and all subcommands, e.g.:
|
||||||
|
// stopCmd.PersistentFlags().String("foo", "", "A help for foo")
|
||||||
|
|
||||||
|
// Cobra supports local flags which will only run when this command
|
||||||
|
// is called directly, e.g.:
|
||||||
|
// stopCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
|
||||||
|
}
|
33
go.mod
33
go.mod
|
@ -1,6 +1,8 @@
|
||||||
module github.com/alist-org/alist/v3
|
module github.com/alist-org/alist/v3
|
||||||
|
|
||||||
go 1.22.4
|
go 1.23
|
||||||
|
|
||||||
|
toolchain go1.23.1
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/KirCute/ftpserverlib-pasvportmap v1.25.0
|
github.com/KirCute/ftpserverlib-pasvportmap v1.25.0
|
||||||
|
@ -40,17 +42,20 @@ require (
|
||||||
github.com/ipfs/go-ipfs-api v0.7.0
|
github.com/ipfs/go-ipfs-api v0.7.0
|
||||||
github.com/jlaffaye/ftp v0.2.0
|
github.com/jlaffaye/ftp v0.2.0
|
||||||
github.com/json-iterator/go v1.1.12
|
github.com/json-iterator/go v1.1.12
|
||||||
|
github.com/kdomanski/iso9660 v0.4.0
|
||||||
github.com/larksuite/oapi-sdk-go/v3 v3.3.1
|
github.com/larksuite/oapi-sdk-go/v3 v3.3.1
|
||||||
github.com/maruel/natural v1.1.1
|
github.com/maruel/natural v1.1.1
|
||||||
github.com/meilisearch/meilisearch-go v0.27.2
|
github.com/meilisearch/meilisearch-go v0.27.2
|
||||||
|
github.com/mholt/archives v0.1.0
|
||||||
github.com/minio/sio v0.4.0
|
github.com/minio/sio v0.4.0
|
||||||
github.com/natefinch/lumberjack v2.0.0+incompatible
|
github.com/natefinch/lumberjack v2.0.0+incompatible
|
||||||
github.com/ncw/swift/v2 v2.0.3
|
github.com/ncw/swift/v2 v2.0.3
|
||||||
github.com/orzogc/fake115uploader v0.3.3-0.20230715111618-58f9eb76f831
|
github.com/orzogc/fake115uploader v0.6.2
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/pkg/sftp v1.13.6
|
github.com/pkg/sftp v1.13.6
|
||||||
github.com/pquerna/otp v1.4.0
|
github.com/pquerna/otp v1.4.0
|
||||||
github.com/rclone/rclone v1.67.0
|
github.com/rclone/rclone v1.67.0
|
||||||
|
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d
|
||||||
github.com/sirupsen/logrus v1.9.3
|
github.com/sirupsen/logrus v1.9.3
|
||||||
github.com/spf13/afero v1.11.0
|
github.com/spf13/afero v1.11.0
|
||||||
github.com/spf13/cobra v1.8.1
|
github.com/spf13/cobra v1.8.1
|
||||||
|
@ -61,6 +66,7 @@ require (
|
||||||
github.com/winfsp/cgofuse v1.5.1-0.20230130140708-f87f5db493b5
|
github.com/winfsp/cgofuse v1.5.1-0.20230130140708-f87f5db493b5
|
||||||
github.com/xhofe/tache v0.1.3
|
github.com/xhofe/tache v0.1.3
|
||||||
github.com/xhofe/wopan-sdk-go v0.1.3
|
github.com/xhofe/wopan-sdk-go v0.1.3
|
||||||
|
github.com/yeka/zip v0.0.0-20231116150916-03d6312748a9
|
||||||
github.com/zzzhr1990/go-common-entity v0.0.0-20221216044934-fd1c571e3a22
|
github.com/zzzhr1990/go-common-entity v0.0.0-20221216044934-fd1c571e3a22
|
||||||
golang.org/x/crypto v0.31.0
|
golang.org/x/crypto v0.31.0
|
||||||
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e
|
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e
|
||||||
|
@ -77,21 +83,32 @@ require (
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/BurntSushi/toml v0.3.1 // indirect
|
github.com/STARRY-S/zip v0.2.1 // indirect
|
||||||
github.com/blevesearch/go-faiss v1.0.20 // indirect
|
github.com/blevesearch/go-faiss v1.0.20 // indirect
|
||||||
github.com/blevesearch/zapx/v16 v16.1.5 // indirect
|
github.com/blevesearch/zapx/v16 v16.1.5 // indirect
|
||||||
|
github.com/bodgit/plumbing v1.3.0 // indirect
|
||||||
|
github.com/bodgit/sevenzip v1.6.0 // indirect
|
||||||
|
github.com/bodgit/windows v1.0.1 // indirect
|
||||||
github.com/bytedance/sonic/loader v0.1.1 // indirect
|
github.com/bytedance/sonic/loader v0.1.1 // indirect
|
||||||
github.com/charmbracelet/x/ansi v0.2.3 // indirect
|
github.com/charmbracelet/x/ansi v0.2.3 // indirect
|
||||||
github.com/charmbracelet/x/term v0.2.0 // indirect
|
github.com/charmbracelet/x/term v0.2.0 // indirect
|
||||||
github.com/cloudwego/base64x v0.1.4 // indirect
|
github.com/cloudwego/base64x v0.1.4 // indirect
|
||||||
github.com/cloudwego/iasm v0.2.0 // indirect
|
github.com/cloudwego/iasm v0.2.0 // indirect
|
||||||
|
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 // indirect
|
||||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
|
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
|
||||||
github.com/fclairamb/go-log v0.5.0 // indirect
|
github.com/fclairamb/go-log v0.5.0 // indirect
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||||
|
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||||
github.com/hekmon/cunits/v2 v2.1.0 // indirect
|
github.com/hekmon/cunits/v2 v2.1.0 // indirect
|
||||||
github.com/ipfs/boxo v0.12.0 // indirect
|
github.com/ipfs/boxo v0.12.0 // indirect
|
||||||
github.com/jackc/puddle/v2 v2.2.1 // indirect
|
github.com/jackc/puddle/v2 v2.2.1 // indirect
|
||||||
|
github.com/klauspost/pgzip v1.2.6 // indirect
|
||||||
|
github.com/nwaples/rardecode/v2 v2.0.0-beta.4.0.20241112120701-034e449c6e78 // indirect
|
||||||
|
github.com/sorairolake/lzip-go v0.3.5 // indirect
|
||||||
github.com/taruti/bytepool v0.0.0-20160310082835-5e3a9ea56543 // indirect
|
github.com/taruti/bytepool v0.0.0-20160310082835-5e3a9ea56543 // indirect
|
||||||
|
github.com/therootcompany/xz v1.0.1 // indirect
|
||||||
|
github.com/ulikunitz/xz v0.5.12 // indirect
|
||||||
|
go4.org v0.0.0-20230225012048-214862532bf5 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
@ -99,8 +116,8 @@ require (
|
||||||
github.com/RoaringBitmap/roaring v1.9.3 // indirect
|
github.com/RoaringBitmap/roaring v1.9.3 // indirect
|
||||||
github.com/abbot/go-http-auth v0.4.0 // indirect
|
github.com/abbot/go-http-auth v0.4.0 // indirect
|
||||||
github.com/aead/ecdh v0.2.0 // indirect
|
github.com/aead/ecdh v0.2.0 // indirect
|
||||||
github.com/andreburgaud/crypt2go v1.2.0 // indirect
|
github.com/andreburgaud/crypt2go v1.8.0 // indirect
|
||||||
github.com/andybalholm/brotli v1.0.4 // indirect
|
github.com/andybalholm/brotli v1.1.1 // indirect
|
||||||
github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394
|
github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394
|
||||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||||
github.com/benbjohnson/clock v1.3.0 // indirect
|
github.com/benbjohnson/clock v1.3.0 // indirect
|
||||||
|
@ -161,7 +178,7 @@ require (
|
||||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/jzelinskie/whirlpool v0.0.0-20201016144138-0675e54bb004 // indirect
|
github.com/jzelinskie/whirlpool v0.0.0-20201016144138-0675e54bb004 // indirect
|
||||||
github.com/klauspost/compress v1.17.8 // indirect
|
github.com/klauspost/compress v1.17.11 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
||||||
github.com/kr/fs v0.1.0 // indirect
|
github.com/kr/fs v0.1.0 // indirect
|
||||||
github.com/leodido/go-urn v1.4.0 // indirect
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
|
@ -196,7 +213,7 @@ require (
|
||||||
github.com/multiformats/go-varint v0.0.7 // indirect
|
github.com/multiformats/go-varint v0.0.7 // indirect
|
||||||
github.com/otiai10/copy v1.14.0
|
github.com/otiai10/copy v1.14.0
|
||||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||||
github.com/pierrec/lz4/v4 v4.1.18 // indirect
|
github.com/pierrec/lz4/v4 v4.1.21 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||||
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect
|
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect
|
||||||
github.com/pquerna/cachecontrol v0.1.0 // indirect
|
github.com/pquerna/cachecontrol v0.1.0 // indirect
|
||||||
|
@ -228,7 +245,7 @@ require (
|
||||||
golang.org/x/sync v0.10.0 // indirect
|
golang.org/x/sync v0.10.0 // indirect
|
||||||
golang.org/x/sys v0.28.0 // indirect
|
golang.org/x/sys v0.28.0 // indirect
|
||||||
golang.org/x/term v0.27.0 // indirect
|
golang.org/x/term v0.27.0 // indirect
|
||||||
golang.org/x/text v0.21.0 // indirect
|
golang.org/x/text v0.21.0
|
||||||
golang.org/x/tools v0.24.0 // indirect
|
golang.org/x/tools v0.24.0 // indirect
|
||||||
google.golang.org/api v0.169.0 // indirect
|
google.golang.org/api v0.169.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 // indirect
|
||||||
|
|
244
go.sum
244
go.sum
|
@ -1,9 +1,27 @@
|
||||||
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||||
|
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||||
|
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||||
|
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||||
|
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||||
|
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||||
|
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
||||||
cloud.google.com/go v0.110.10 h1:LXy9GEO+timppncPIAZoOj3l58LIU9k+kn48AN7IO3Y=
|
cloud.google.com/go v0.110.10 h1:LXy9GEO+timppncPIAZoOj3l58LIU9k+kn48AN7IO3Y=
|
||||||
|
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||||
|
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||||
cloud.google.com/go/compute v1.23.4 h1:EBT9Nw4q3zyE7G45Wvv3MzolIrCJEuHys5muLY0wvAw=
|
cloud.google.com/go/compute v1.23.4 h1:EBT9Nw4q3zyE7G45Wvv3MzolIrCJEuHys5muLY0wvAw=
|
||||||
cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc=
|
cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc=
|
||||||
cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
|
cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
|
||||||
|
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||||
|
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||||
|
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||||
|
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||||
|
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||||
|
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||||
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/KirCute/ftpserverlib-pasvportmap v1.25.0 h1:ikwCzeqoqN6wvBHOB9OI6dde/jbV7EoTMpUcxtYl5Po=
|
github.com/KirCute/ftpserverlib-pasvportmap v1.25.0 h1:ikwCzeqoqN6wvBHOB9OI6dde/jbV7EoTMpUcxtYl5Po=
|
||||||
github.com/KirCute/ftpserverlib-pasvportmap v1.25.0/go.mod h1:v0NgMtKDDi/6CM6r4P+daCljCW3eO9yS+Z+pZDTKo1E=
|
github.com/KirCute/ftpserverlib-pasvportmap v1.25.0/go.mod h1:v0NgMtKDDi/6CM6r4P+daCljCW3eO9yS+Z+pZDTKo1E=
|
||||||
github.com/KirCute/sftpd-alist v0.0.12 h1:GNVM5QLbQLAfXP4wGUlXFA2IO6fVek0n0IsGnOuISdg=
|
github.com/KirCute/sftpd-alist v0.0.12 h1:GNVM5QLbQLAfXP4wGUlXFA2IO6fVek0n0IsGnOuISdg=
|
||||||
|
@ -12,6 +30,8 @@ github.com/Max-Sum/base32768 v0.0.0-20230304063302-18e6ce5945fd h1:nzE1YQBdx1bq9
|
||||||
github.com/Max-Sum/base32768 v0.0.0-20230304063302-18e6ce5945fd/go.mod h1:C8yoIfvESpM3GD07OCHU7fqI7lhwyZ2Td1rbNbTAhnc=
|
github.com/Max-Sum/base32768 v0.0.0-20230304063302-18e6ce5945fd/go.mod h1:C8yoIfvESpM3GD07OCHU7fqI7lhwyZ2Td1rbNbTAhnc=
|
||||||
github.com/RoaringBitmap/roaring v1.9.3 h1:t4EbC5qQwnisr5PrP9nt0IRhRTb9gMUgQF4t4S2OByM=
|
github.com/RoaringBitmap/roaring v1.9.3 h1:t4EbC5qQwnisr5PrP9nt0IRhRTb9gMUgQF4t4S2OByM=
|
||||||
github.com/RoaringBitmap/roaring v1.9.3/go.mod h1:6AXUsoIEzDTFFQCe1RbGA6uFONMhvejWj5rqITANK90=
|
github.com/RoaringBitmap/roaring v1.9.3/go.mod h1:6AXUsoIEzDTFFQCe1RbGA6uFONMhvejWj5rqITANK90=
|
||||||
|
github.com/STARRY-S/zip v0.2.1 h1:pWBd4tuSGm3wtpoqRZZ2EAwOmcHK6XFf7bU9qcJXyFg=
|
||||||
|
github.com/STARRY-S/zip v0.2.1/go.mod h1:xNvshLODWtC4EJ702g7cTYn13G53o1+X9BWnPFpcWV4=
|
||||||
github.com/SheltonZhu/115driver v1.0.32 h1:Taw1bnfcPJZW0xTdhDvEbBS1tccif7J7DslRp2NkDyQ=
|
github.com/SheltonZhu/115driver v1.0.32 h1:Taw1bnfcPJZW0xTdhDvEbBS1tccif7J7DslRp2NkDyQ=
|
||||||
github.com/SheltonZhu/115driver v1.0.32/go.mod h1:XXFi23pyhAgzUE8dUEKdGvIdUQKi3wv6zR7C1Do40D8=
|
github.com/SheltonZhu/115driver v1.0.32/go.mod h1:XXFi23pyhAgzUE8dUEKdGvIdUQKi3wv6zR7C1Do40D8=
|
||||||
github.com/Unknwon/goconfig v1.0.0 h1:9IAu/BYbSLQi8puFjUQApZTxIHqSwrj5d8vpP8vTq4A=
|
github.com/Unknwon/goconfig v1.0.0 h1:9IAu/BYbSLQi8puFjUQApZTxIHqSwrj5d8vpP8vTq4A=
|
||||||
|
@ -30,10 +50,11 @@ github.com/alist-org/times v0.0.0-20240721124654-efa0c7d3ad92 h1:pIEI87zhv8ZzQcu
|
||||||
github.com/alist-org/times v0.0.0-20240721124654-efa0c7d3ad92/go.mod h1:oPJwGY3sLmGgcJamGumz//0A35f4BwQRacyqLNcJTOU=
|
github.com/alist-org/times v0.0.0-20240721124654-efa0c7d3ad92/go.mod h1:oPJwGY3sLmGgcJamGumz//0A35f4BwQRacyqLNcJTOU=
|
||||||
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible h1:8psS8a+wKfiLt1iVDX79F7Y6wUM49Lcha2FMXt4UM8g=
|
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible h1:8psS8a+wKfiLt1iVDX79F7Y6wUM49Lcha2FMXt4UM8g=
|
||||||
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
|
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
|
||||||
github.com/andreburgaud/crypt2go v1.2.0 h1:oly/ENAodeqTYpUafgd4r3v+VKLQnmOKUyfpj+TxHbE=
|
github.com/andreburgaud/crypt2go v1.8.0 h1:J73vGTb1P6XL69SSuumbKs0DWn3ulbl9L92ZXBjw6pc=
|
||||||
github.com/andreburgaud/crypt2go v1.2.0/go.mod h1:kKRqlrX/3Q9Ki7HdUsoh0cX1Urq14/Hcta4l4VrIXrI=
|
github.com/andreburgaud/crypt2go v1.8.0/go.mod h1:L5nfShQ91W78hOWhUH2tlGRPO+POAPJAF5fKOLB9SXg=
|
||||||
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
|
|
||||||
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||||
|
github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
|
||||||
|
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
|
||||||
github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0=
|
github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0=
|
||||||
github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY=
|
github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY=
|
||||||
github.com/aws/aws-sdk-go v1.38.20/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
github.com/aws/aws-sdk-go v1.38.20/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
||||||
|
@ -91,6 +112,12 @@ github.com/blevesearch/zapx/v16 v16.1.5 h1:b0sMcarqNFxuXvjoXsF8WtwVahnxyhEvBSRJi
|
||||||
github.com/blevesearch/zapx/v16 v16.1.5/go.mod h1:J4mSF39w1QELc11EWRSBFkPeZuO7r/NPKkHzDCoiaI8=
|
github.com/blevesearch/zapx/v16 v16.1.5/go.mod h1:J4mSF39w1QELc11EWRSBFkPeZuO7r/NPKkHzDCoiaI8=
|
||||||
github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw=
|
github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw=
|
||||||
github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0=
|
github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0=
|
||||||
|
github.com/bodgit/plumbing v1.3.0 h1:pf9Itz1JOQgn7vEOE7v7nlEfBykYqvUYioC61TwWCFU=
|
||||||
|
github.com/bodgit/plumbing v1.3.0/go.mod h1:JOTb4XiRu5xfnmdnDJo6GmSbSbtSyufrsyZFByMtKEs=
|
||||||
|
github.com/bodgit/sevenzip v1.6.0 h1:a4R0Wu6/P1o1pP/3VV++aEOcyeBxeO/xE2Y9NSTrr6A=
|
||||||
|
github.com/bodgit/sevenzip v1.6.0/go.mod h1:zOBh9nJUof7tcrlqJFv1koWRrhz3LbDbUNngkuZxLMc=
|
||||||
|
github.com/bodgit/windows v1.0.1 h1:tF7K6KOluPYygXa3Z2594zxlkbKPAOvqr97etrGNIz4=
|
||||||
|
github.com/bodgit/windows v1.0.1/go.mod h1:a6JLwrB4KrTR5hBpp8FI9/9W9jJfeQ2h4XDXU74ZCdM=
|
||||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI=
|
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI=
|
||||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||||
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
|
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
|
||||||
|
@ -99,6 +126,7 @@ github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3z
|
||||||
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||||
github.com/caarlos0/env/v9 v9.0.0 h1:SI6JNsOA+y5gj9njpgybykATIylrRMklbs5ch6wO6pc=
|
github.com/caarlos0/env/v9 v9.0.0 h1:SI6JNsOA+y5gj9njpgybykATIylrRMklbs5ch6wO6pc=
|
||||||
github.com/caarlos0/env/v9 v9.0.0/go.mod h1:ye5mlCVMYh6tZ+vCgrs/B95sj88cg5Tlnc0XIzgZ020=
|
github.com/caarlos0/env/v9 v9.0.0/go.mod h1:ye5mlCVMYh6tZ+vCgrs/B95sj88cg5Tlnc0XIzgZ020=
|
||||||
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/charmbracelet/bubbles v0.20.0 h1:jSZu6qD8cRQ6k9OMfR1WlM+ruM8fkPWkHvQWD9LIutE=
|
github.com/charmbracelet/bubbles v0.20.0 h1:jSZu6qD8cRQ6k9OMfR1WlM+ruM8fkPWkHvQWD9LIutE=
|
||||||
|
@ -115,8 +143,12 @@ github.com/charmbracelet/x/term v0.2.0 h1:cNB9Ot9q8I711MyZ7myUR5HFWL/lc3OpU8jZ4h
|
||||||
github.com/charmbracelet/x/term v0.2.0/go.mod h1:GVxgxAbjUrmpvIINHIQnJJKpMlHiZ4cktEQCN6GWyF0=
|
github.com/charmbracelet/x/term v0.2.0/go.mod h1:GVxgxAbjUrmpvIINHIQnJJKpMlHiZ4cktEQCN6GWyF0=
|
||||||
github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927 h1:SKI1/fuSdodxmNNyVBR8d7X/HuLnRpvvFO0AgyQk764=
|
github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927 h1:SKI1/fuSdodxmNNyVBR8d7X/HuLnRpvvFO0AgyQk764=
|
||||||
github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U=
|
github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U=
|
||||||
|
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||||
|
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||||
|
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||||
github.com/city404/v6-public-rpc-proto/go v0.0.0-20240817070657-90f8e24b653e h1:GLC8iDDcbt1H8+RkNao2nRGjyNTIo81e1rAJT9/uWYA=
|
github.com/city404/v6-public-rpc-proto/go v0.0.0-20240817070657-90f8e24b653e h1:GLC8iDDcbt1H8+RkNao2nRGjyNTIo81e1rAJT9/uWYA=
|
||||||
github.com/city404/v6-public-rpc-proto/go v0.0.0-20240817070657-90f8e24b653e/go.mod h1:ln9Whp+wVY/FTbn2SK0ag+SKD2fC0yQCF/Lqowc1LmU=
|
github.com/city404/v6-public-rpc-proto/go v0.0.0-20240817070657-90f8e24b653e/go.mod h1:ln9Whp+wVY/FTbn2SK0ag+SKD2fC0yQCF/Lqowc1LmU=
|
||||||
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
|
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
|
||||||
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
||||||
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
|
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
|
||||||
|
@ -145,8 +177,13 @@ github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1
|
||||||
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
||||||
github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo=
|
github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo=
|
||||||
github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||||
|
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 h1:2tV76y6Q9BB+NEBasnqvs7e49aEBFI8ejC89PSnWH+4=
|
||||||
|
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s=
|
||||||
|
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
|
||||||
github.com/dustinxie/ecc v0.0.0-20210511000915-959544187564 h1:I6KUy4CI6hHjqnyJLNCEi7YHVMkwwtfSr2k9splgdSM=
|
github.com/dustinxie/ecc v0.0.0-20210511000915-959544187564 h1:I6KUy4CI6hHjqnyJLNCEi7YHVMkwwtfSr2k9splgdSM=
|
||||||
github.com/dustinxie/ecc v0.0.0-20210511000915-959544187564/go.mod h1:yekO+3ZShy19S+bsmnERmznGy9Rfg6dWWWpiGJjNAz8=
|
github.com/dustinxie/ecc v0.0.0-20210511000915-959544187564/go.mod h1:yekO+3ZShy19S+bsmnERmznGy9Rfg6dWWWpiGJjNAz8=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
|
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
|
||||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
|
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
|
||||||
github.com/fclairamb/go-log v0.5.0 h1:Gz9wSamEaA6lta4IU2cjJc2xSq5sV5VYSB5w/SUHhVc=
|
github.com/fclairamb/go-log v0.5.0 h1:Gz9wSamEaA6lta4IU2cjJc2xSq5sV5VYSB5w/SUHhVc=
|
||||||
|
@ -175,6 +212,8 @@ github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
|
||||||
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
|
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
|
||||||
github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s=
|
github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s=
|
||||||
github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||||
|
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||||
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||||
github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
|
github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
|
||||||
github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
|
github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
|
||||||
github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA=
|
github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA=
|
||||||
|
@ -220,14 +259,32 @@ github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17w
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||||
github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 h1:gtexQ/VGyN+VVFRXSFiguSNcXmS6rkKT+X7FdIrTtfo=
|
github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 h1:gtexQ/VGyN+VVFRXSFiguSNcXmS6rkKT+X7FdIrTtfo=
|
||||||
github.com/golang/geo v0.0.0-20210211234256-740aa86cb551/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
|
github.com/golang/geo v0.0.0-20210211234256-740aa86cb551/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
|
||||||
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
|
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||||
|
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||||
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
|
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
@ -236,6 +293,11 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
|
||||||
github.com/google/go-tpm v0.9.1 h1:0pGc4X//bAlmZzMKf8iz6IsDo1nYTbYJ6FZN/rg4zdM=
|
github.com/google/go-tpm v0.9.1 h1:0pGc4X//bAlmZzMKf8iz6IsDo1nYTbYJ6FZN/rg4zdM=
|
||||||
github.com/google/go-tpm v0.9.1/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY=
|
github.com/google/go-tpm v0.9.1/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||||
|
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
|
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
|
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
|
github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
|
||||||
github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
|
github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
|
||||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
@ -243,6 +305,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs=
|
github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs=
|
||||||
github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
|
github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||||
github.com/googleapis/gax-go/v2 v2.12.2 h1:mhN09QQW1jEWeMF74zGR81R30z4VJzjZsfkUhuHF+DA=
|
github.com/googleapis/gax-go/v2 v2.12.2 h1:mhN09QQW1jEWeMF74zGR81R30z4VJzjZsfkUhuHF+DA=
|
||||||
github.com/googleapis/gax-go/v2 v2.12.2/go.mod h1:61M8vcyyXR2kqKFxKrfA22jaA8JGF7Dc8App1U3H6jc=
|
github.com/googleapis/gax-go/v2 v2.12.2/go.mod h1:61M8vcyyXR2kqKFxKrfA22jaA8JGF7Dc8App1U3H6jc=
|
||||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
|
@ -257,13 +321,18 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l
|
||||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||||
github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
|
github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
|
||||||
github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||||
|
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
|
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||||
|
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
||||||
|
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||||
github.com/hekmon/cunits/v2 v2.1.0 h1:k6wIjc4PlacNOHwKEMBgWV2/c8jyD4eRMs5mR1BBhI0=
|
github.com/hekmon/cunits/v2 v2.1.0 h1:k6wIjc4PlacNOHwKEMBgWV2/c8jyD4eRMs5mR1BBhI0=
|
||||||
github.com/hekmon/cunits/v2 v2.1.0/go.mod h1:9r1TycXYXaTmEWlAIfFV8JT+Xo59U96yUJAYHxzii2M=
|
github.com/hekmon/cunits/v2 v2.1.0/go.mod h1:9r1TycXYXaTmEWlAIfFV8JT+Xo59U96yUJAYHxzii2M=
|
||||||
github.com/hekmon/transmissionrpc/v3 v3.0.0 h1:0Fb11qE0IBh4V4GlOwHNYpqpjcYDp5GouolwrpmcUDQ=
|
github.com/hekmon/transmissionrpc/v3 v3.0.0 h1:0Fb11qE0IBh4V4GlOwHNYpqpjcYDp5GouolwrpmcUDQ=
|
||||||
github.com/hekmon/transmissionrpc/v3 v3.0.0/go.mod h1:38SlNhFzinVUuY87wGj3acOmRxeYZAZfrj6Re7UgCDg=
|
github.com/hekmon/transmissionrpc/v3 v3.0.0/go.mod h1:38SlNhFzinVUuY87wGj3acOmRxeYZAZfrj6Re7UgCDg=
|
||||||
github.com/hirochachacha/go-smb2 v1.1.0 h1:b6hs9qKIql9eVXAiN0M2wSFY5xnhbHAQoCwRKbaRTZI=
|
github.com/hirochachacha/go-smb2 v1.1.0 h1:b6hs9qKIql9eVXAiN0M2wSFY5xnhbHAQoCwRKbaRTZI=
|
||||||
github.com/hirochachacha/go-smb2 v1.1.0/go.mod h1:8F1A4d5EZzrGu5R7PU163UcMRDJQl4FtcxjBfsY8TZE=
|
github.com/hirochachacha/go-smb2 v1.1.0/go.mod h1:8F1A4d5EZzrGu5R7PU163UcMRDJQl4FtcxjBfsY8TZE=
|
||||||
|
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
github.com/ipfs/boxo v0.12.0 h1:AXHg/1ONZdRQHQLgG5JHsSC3XoE4DjCAMgK+asZvUcQ=
|
github.com/ipfs/boxo v0.12.0 h1:AXHg/1ONZdRQHQLgG5JHsSC3XoE4DjCAMgK+asZvUcQ=
|
||||||
|
@ -297,18 +366,26 @@ github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFF
|
||||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
|
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||||
|
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||||
github.com/jzelinskie/whirlpool v0.0.0-20201016144138-0675e54bb004 h1:G+9t9cEtnC9jFiTxyptEKuNIAbiN5ZCQzX2a74lj3xg=
|
github.com/jzelinskie/whirlpool v0.0.0-20201016144138-0675e54bb004 h1:G+9t9cEtnC9jFiTxyptEKuNIAbiN5ZCQzX2a74lj3xg=
|
||||||
github.com/jzelinskie/whirlpool v0.0.0-20201016144138-0675e54bb004/go.mod h1:KmHnJWQrgEvbuy0vcvj00gtMqbvNn1L+3YUZLK/B92c=
|
github.com/jzelinskie/whirlpool v0.0.0-20201016144138-0675e54bb004/go.mod h1:KmHnJWQrgEvbuy0vcvj00gtMqbvNn1L+3YUZLK/B92c=
|
||||||
|
github.com/kdomanski/iso9660 v0.4.0 h1:BPKKdcINz3m0MdjIMwS0wx1nofsOjxOq8TOr45WGHFg=
|
||||||
|
github.com/kdomanski/iso9660 v0.4.0/go.mod h1:OxUSupHsO9ceI8lBLPJKWBTphLemjrCQY8LPXM7qSzU=
|
||||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
|
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||||
github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||||
github.com/klauspost/compress v1.15.6/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
|
github.com/klauspost/compress v1.15.6/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
|
||||||
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
|
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
|
||||||
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
|
||||||
|
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
|
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||||
|
github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU=
|
||||||
|
github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||||
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||||
github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
|
github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
|
||||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||||
|
@ -355,6 +432,8 @@ github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o
|
||||||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||||
github.com/meilisearch/meilisearch-go v0.27.2 h1:3G21dJ5i208shnLPDsIEZ0L0Geg/5oeXABFV7nlK94k=
|
github.com/meilisearch/meilisearch-go v0.27.2 h1:3G21dJ5i208shnLPDsIEZ0L0Geg/5oeXABFV7nlK94k=
|
||||||
github.com/meilisearch/meilisearch-go v0.27.2/go.mod h1:SxuSqDcPBIykjWz1PX+KzsYzArNLSCadQodWs8extS0=
|
github.com/meilisearch/meilisearch-go v0.27.2/go.mod h1:SxuSqDcPBIykjWz1PX+KzsYzArNLSCadQodWs8extS0=
|
||||||
|
github.com/mholt/archives v0.1.0 h1:FacgJyrjiuyomTuNA92X5GyRBRZjE43Y/lrzKIlF35Q=
|
||||||
|
github.com/mholt/archives v0.1.0/go.mod h1:j/Ire/jm42GN7h90F5kzj6hf6ZFzEH66de+hmjEKu+I=
|
||||||
github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM=
|
github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM=
|
||||||
github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8=
|
github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8=
|
||||||
github.com/minio/sio v0.4.0 h1:u4SWVEm5lXSqU42ZWawV0D9I5AZ5YMmo2RXpEQ/kRhc=
|
github.com/minio/sio v0.4.0 h1:u4SWVEm5lXSqU42ZWawV0D9I5AZ5YMmo2RXpEQ/kRhc=
|
||||||
|
@ -400,8 +479,10 @@ github.com/natefinch/lumberjack v2.0.0+incompatible h1:4QJd3OLAMgj7ph+yZTuX13Ld4
|
||||||
github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk=
|
github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk=
|
||||||
github.com/ncw/swift/v2 v2.0.3 h1:8R9dmgFIWs+RiVlisCEfiQiik1hjuR0JnOkLxaP9ihg=
|
github.com/ncw/swift/v2 v2.0.3 h1:8R9dmgFIWs+RiVlisCEfiQiik1hjuR0JnOkLxaP9ihg=
|
||||||
github.com/ncw/swift/v2 v2.0.3/go.mod h1:cbAO76/ZwcFrFlHdXPjaqWZ9R7Hdar7HpjRXBfbjigk=
|
github.com/ncw/swift/v2 v2.0.3/go.mod h1:cbAO76/ZwcFrFlHdXPjaqWZ9R7Hdar7HpjRXBfbjigk=
|
||||||
github.com/orzogc/fake115uploader v0.3.3-0.20230715111618-58f9eb76f831 h1:K3T3eu4h5aYIOzUtLjN08L4Qt4WGaJONMgcaD0ayBJQ=
|
github.com/nwaples/rardecode/v2 v2.0.0-beta.4.0.20241112120701-034e449c6e78 h1:MYzLheyVx1tJVDqfu3YnN4jtnyALNzLvwl+f58TcvQY=
|
||||||
github.com/orzogc/fake115uploader v0.3.3-0.20230715111618-58f9eb76f831/go.mod h1:lSHD4lC4zlMl+zcoysdJcd5KFzsWwOD8BJbyg1Ws9Ng=
|
github.com/nwaples/rardecode/v2 v2.0.0-beta.4.0.20241112120701-034e449c6e78/go.mod h1:yntwv/HfMc/Hbvtq9I19D1n58te3h6KsqCf3GxyfBGY=
|
||||||
|
github.com/orzogc/fake115uploader v0.6.2 h1:f4LzqeeXpmY7DjOMnzmAnnPTPMA/f/BUclq4ecffTvU=
|
||||||
|
github.com/orzogc/fake115uploader v0.6.2/go.mod h1:Mqqwv1+gUEjJhUfIQanco3DCTKp+7lSx8DJ3AoRwMoE=
|
||||||
github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU=
|
github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU=
|
||||||
github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w=
|
github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w=
|
||||||
github.com/otiai10/mint v1.5.1 h1:XaPLeE+9vGbuyEHem1JNk3bYc7KKqyI/na0/mLd/Kks=
|
github.com/otiai10/mint v1.5.1 h1:XaPLeE+9vGbuyEHem1JNk3bYc7KKqyI/na0/mLd/Kks=
|
||||||
|
@ -410,8 +491,8 @@ github.com/panjf2000/ants/v2 v2.4.2/go.mod h1:f6F0NZVFsGCp5A7QW/Zj/m92atWwOkY0OI
|
||||||
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
|
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
|
||||||
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
||||||
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||||
github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ=
|
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
|
||||||
github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
@ -432,6 +513,7 @@ github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg=
|
||||||
github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
|
github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
|
||||||
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
|
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
|
||||||
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
|
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
|
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
|
||||||
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
|
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
|
||||||
github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
|
github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
|
||||||
|
@ -445,13 +527,17 @@ github.com/rfjakob/eme v1.1.2/go.mod h1:cVvpasglm/G3ngEfcfT/Wt0GwhkuO32pf/poW6Ny
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk=
|
||||||
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46 h1:GHRpF1pTW19a8tTFrMLUcfWwyC0pnifVo2ClaLq+hP8=
|
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46 h1:GHRpF1pTW19a8tTFrMLUcfWwyC0pnifVo2ClaLq+hP8=
|
||||||
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5PCi+MFsC7HjREoAz1BU+Mq60+05gifQSsHSDG/8=
|
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5PCi+MFsC7HjREoAz1BU+Mq60+05gifQSsHSDG/8=
|
||||||
|
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d h1:hrujxIzL1woJ7AwssoOcM/tq5JjjG2yYOc8odClEiXA=
|
||||||
|
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU=
|
||||||
github.com/secsy/goftp v0.0.0-20200609142545-aa2de14babf4 h1:PT+ElG/UUFMfqy5HrxJxNzj3QBOf7dZwupeVC+mG1Lo=
|
github.com/secsy/goftp v0.0.0-20200609142545-aa2de14babf4 h1:PT+ElG/UUFMfqy5HrxJxNzj3QBOf7dZwupeVC+mG1Lo=
|
||||||
github.com/secsy/goftp v0.0.0-20200609142545-aa2de14babf4/go.mod h1:MnkX001NG75g3p8bhFycnyIjeQoOjGL6CEIsdE/nKSY=
|
github.com/secsy/goftp v0.0.0-20200609142545-aa2de14babf4/go.mod h1:MnkX001NG75g3p8bhFycnyIjeQoOjGL6CEIsdE/nKSY=
|
||||||
github.com/shabbyrobe/gocovmerge v0.0.0-20230507112040-c3350d9342df h1:S77Pf5fIGMa7oSwp8SQPp7Hb4ZiI38K3RNBKD2LLeEM=
|
github.com/shabbyrobe/gocovmerge v0.0.0-20230507112040-c3350d9342df h1:S77Pf5fIGMa7oSwp8SQPp7Hb4ZiI38K3RNBKD2LLeEM=
|
||||||
|
@ -469,6 +555,8 @@ github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1
|
||||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
|
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
|
||||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA=
|
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA=
|
||||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
|
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
|
||||||
|
github.com/sorairolake/lzip-go v0.3.5 h1:ms5Xri9o1JBIWvOFAorYtUNik6HI3HgBTkISiqu0Cwg=
|
||||||
|
github.com/sorairolake/lzip-go v0.3.5/go.mod h1:N0KYq5iWrMXI0ZEXKXaS9hCyOjZUQdBDEIbXfoUwbdk=
|
||||||
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
||||||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||||
|
@ -501,6 +589,8 @@ github.com/t3rm1n4l/go-mega v0.0.0-20240219080617-d494b6a8ace7 h1:Jtcrb09q0AVWe3
|
||||||
github.com/t3rm1n4l/go-mega v0.0.0-20240219080617-d494b6a8ace7/go.mod h1:suDIky6yrK07NnaBadCB4sS0CqFOvUK91lH7CR+JlDA=
|
github.com/t3rm1n4l/go-mega v0.0.0-20240219080617-d494b6a8ace7/go.mod h1:suDIky6yrK07NnaBadCB4sS0CqFOvUK91lH7CR+JlDA=
|
||||||
github.com/taruti/bytepool v0.0.0-20160310082835-5e3a9ea56543 h1:6Y51mutOvRGRx6KqyMNo//xk8B8o6zW9/RVmy1VamOs=
|
github.com/taruti/bytepool v0.0.0-20160310082835-5e3a9ea56543 h1:6Y51mutOvRGRx6KqyMNo//xk8B8o6zW9/RVmy1VamOs=
|
||||||
github.com/taruti/bytepool v0.0.0-20160310082835-5e3a9ea56543/go.mod h1:jpwqYA8KUVEvSUJHkCXsnBRJCSKP1BMa81QZ6kvRpow=
|
github.com/taruti/bytepool v0.0.0-20160310082835-5e3a9ea56543/go.mod h1:jpwqYA8KUVEvSUJHkCXsnBRJCSKP1BMa81QZ6kvRpow=
|
||||||
|
github.com/therootcompany/xz v1.0.1 h1:CmOtsn1CbtmyYiusbfmhmkpAAETj0wBIH6kCYaX+xzw=
|
||||||
|
github.com/therootcompany/xz v1.0.1/go.mod h1:3K3UH1yCKgBneZYhuQUvJ9HPD19UEXEI0BWbMn8qNMY=
|
||||||
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
|
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
|
||||||
github.com/tklauser/go-sysconf v0.3.13 h1:GBUpcahXSpR2xN01jhkNAbTLRk2Yzgggk8IM08lq3r4=
|
github.com/tklauser/go-sysconf v0.3.13 h1:GBUpcahXSpR2xN01jhkNAbTLRk2Yzgggk8IM08lq3r4=
|
||||||
github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5IJePewFCGVEa0=
|
github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5IJePewFCGVEa0=
|
||||||
|
@ -517,6 +607,9 @@ github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6
|
||||||
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
|
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
|
||||||
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
|
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
|
||||||
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||||
|
github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||||
|
github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc=
|
||||||
|
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||||
github.com/upyun/go-sdk/v3 v3.0.4 h1:2DCJa/Yi7/3ZybT9UCPATSzvU3wpPPxhXinNlb1Hi8Q=
|
github.com/upyun/go-sdk/v3 v3.0.4 h1:2DCJa/Yi7/3ZybT9UCPATSzvU3wpPPxhXinNlb1Hi8Q=
|
||||||
github.com/upyun/go-sdk/v3 v3.0.4/go.mod h1:P/SnuuwhrIgAVRd/ZpzDWqCsBAf/oHg7UggbAxyZa0E=
|
github.com/upyun/go-sdk/v3 v3.0.4/go.mod h1:P/SnuuwhrIgAVRd/ZpzDWqCsBAf/oHg7UggbAxyZa0E=
|
||||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||||
|
@ -536,6 +629,10 @@ github.com/xhofe/tache v0.1.3 h1:MipxzlljYX29E1YI/SLC7hVomVF+51iP1OUzlsuq1wE=
|
||||||
github.com/xhofe/tache v0.1.3/go.mod h1:iKumPFvywf30FRpAHHCt64G0JHLMzT0K+wyGedHsmTQ=
|
github.com/xhofe/tache v0.1.3/go.mod h1:iKumPFvywf30FRpAHHCt64G0JHLMzT0K+wyGedHsmTQ=
|
||||||
github.com/xhofe/wopan-sdk-go v0.1.3 h1:J58X6v+n25ewBZjb05pKOr7AWGohb+Rdll4CThGh6+A=
|
github.com/xhofe/wopan-sdk-go v0.1.3 h1:J58X6v+n25ewBZjb05pKOr7AWGohb+Rdll4CThGh6+A=
|
||||||
github.com/xhofe/wopan-sdk-go v0.1.3/go.mod h1:dcY9yA28fnaoZPnXZiVTFSkcd7GnIPTpTIIlfSI5z5Q=
|
github.com/xhofe/wopan-sdk-go v0.1.3/go.mod h1:dcY9yA28fnaoZPnXZiVTFSkcd7GnIPTpTIIlfSI5z5Q=
|
||||||
|
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
|
||||||
|
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
|
||||||
|
github.com/yeka/zip v0.0.0-20231116150916-03d6312748a9 h1:K8gF0eekWPEX+57l30ixxzGhHH/qscI3JCnuhbN6V4M=
|
||||||
|
github.com/yeka/zip v0.0.0-20231116150916-03d6312748a9/go.mod h1:9BnoKCcgJ/+SLhfAXj15352hTOuVmG5Gzo8xNRINfqI=
|
||||||
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.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
|
@ -545,6 +642,10 @@ github.com/zzzhr1990/go-common-entity v0.0.0-20221216044934-fd1c571e3a22 h1:X+lH
|
||||||
github.com/zzzhr1990/go-common-entity v0.0.0-20221216044934-fd1c571e3a22/go.mod h1:1zGRDJd8zlG6P8azG96+uywfh6udYWwhOmUivw+xsuM=
|
github.com/zzzhr1990/go-common-entity v0.0.0-20221216044934-fd1c571e3a22/go.mod h1:1zGRDJd8zlG6P8azG96+uywfh6udYWwhOmUivw+xsuM=
|
||||||
go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA=
|
go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA=
|
||||||
go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
|
go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
|
||||||
|
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||||
|
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||||
|
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
|
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk=
|
||||||
|
@ -555,12 +656,16 @@ go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGX
|
||||||
go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
|
go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
|
||||||
go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
|
go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
|
||||||
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
|
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
|
||||||
|
go4.org v0.0.0-20230225012048-214862532bf5 h1:nifaUDeh+rPaBCMPMQHZmvJf+QdpLFnuQPwx+LxVmtc=
|
||||||
|
go4.org v0.0.0-20230225012048-214862532bf5/go.mod h1:F57wTi5Lrj6WLyswp5EYV1ncrEbFGHD4hhz6S1ZYeaU=
|
||||||
gocv.io/x/gocv v0.25.0/go.mod h1:Rar2PS6DV+T4FL+PM535EImD/h13hGVaHhnCu1xarBs=
|
gocv.io/x/gocv v0.25.0/go.mod h1:Rar2PS6DV+T4FL+PM535EImD/h13hGVaHhnCu1xarBs=
|
||||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||||
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
|
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
|
||||||
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||||
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
@ -576,11 +681,35 @@ golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v
|
||||||
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
|
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
|
||||||
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
||||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||||
|
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=
|
||||||
|
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||||
|
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||||
|
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||||
|
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||||
|
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||||
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e h1:I88y4caeGeuDQxgdoFPUq097j7kNfw6uvuiNxUBfcBk=
|
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e h1:I88y4caeGeuDQxgdoFPUq097j7kNfw6uvuiNxUBfcBk=
|
||||||
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
|
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
|
||||||
|
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||||
|
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
golang.org/x/image v0.19.0 h1:D9FX4QWkLfkeqaC62SonffIIuYdOk/UE2XKUBgRIBIQ=
|
golang.org/x/image v0.19.0 h1:D9FX4QWkLfkeqaC62SonffIIuYdOk/UE2XKUBgRIBIQ=
|
||||||
golang.org/x/image v0.19.0/go.mod h1:y0zrRqlQRWQ5PXaYCOMLTW2fpsxZ8Qh9I/ohnInJEys=
|
golang.org/x/image v0.19.0/go.mod h1:y0zrRqlQRWQ5PXaYCOMLTW2fpsxZ8Qh9I/ohnInJEys=
|
||||||
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
|
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||||
|
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||||
|
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||||
|
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||||
|
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||||
|
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||||
|
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
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=
|
||||||
|
@ -588,8 +717,19 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/mod v0.17.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-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
|
@ -600,6 +740,7 @@ golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
|
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||||
|
@ -607,8 +748,17 @@ golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
|
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
|
||||||
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
|
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
|
||||||
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
|
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
|
||||||
|
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=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA=
|
golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA=
|
||||||
golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||||
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
@ -619,10 +769,20 @@ golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.10.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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
@ -664,7 +824,9 @@ golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||||
golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
|
golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
|
||||||
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
|
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
|
||||||
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
||||||
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
@ -679,6 +841,7 @@ golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||||
|
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.0.0-20220722155302-e5dcc9cfc0b9/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||||
|
@ -686,8 +849,30 @@ golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg=
|
||||||
golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
|
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
|
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
|
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20190829051458-42f498d34c4d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20190829051458-42f498d34c4d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
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=
|
||||||
|
@ -700,12 +885,45 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
|
||||||
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=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||||
|
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||||
|
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||||
|
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||||
|
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||||
|
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||||
|
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||||
|
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||||
google.golang.org/api v0.169.0 h1:QwWPy71FgMWqJN/l6jVlFHUa29a7dcUy02I8o799nPY=
|
google.golang.org/api v0.169.0 h1:QwWPy71FgMWqJN/l6jVlFHUa29a7dcUy02I8o799nPY=
|
||||||
google.golang.org/api v0.169.0/go.mod h1:gpNOiMA2tZ4mf5R9Iwf4rK/Dcz0fbdIgWYWVoxmsyLg=
|
google.golang.org/api v0.169.0/go.mod h1:gpNOiMA2tZ4mf5R9Iwf4rK/Dcz0fbdIgWYWVoxmsyLg=
|
||||||
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||||
|
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||||
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
|
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
|
||||||
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
|
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
|
||||||
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||||
|
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
|
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
|
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
|
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
|
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 h1:1GBuWVLM/KMVUv1t1En5Gs+gFZCNd360GGb4sSxtrhU=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 h1:1GBuWVLM/KMVUv1t1En5Gs+gFZCNd360GGb4sSxtrhU=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
|
||||||
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
|
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
|
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
|
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
|
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
|
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c=
|
google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c=
|
||||||
google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
|
google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
|
@ -744,8 +962,16 @@ gorm.io/driver/sqlite v1.5.6/go.mod h1:U+J8craQU6Fzkcvu8oLeAQmi50TkwPEhHDEjQZXDa
|
||||||
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
||||||
gorm.io/gorm v1.25.11 h1:/Wfyg1B/je1hnDx3sMkX+gAlxrlZpn6X0BXRlwXlvHg=
|
gorm.io/gorm v1.25.11 h1:/Wfyg1B/je1hnDx3sMkX+gAlxrlZpn6X0BXRlwXlvHg=
|
||||||
gorm.io/gorm v1.25.11/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
|
gorm.io/gorm v1.25.11/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
|
||||||
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||||
lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0=
|
lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0=
|
||||||
lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA=
|
lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA=
|
||||||
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||||
|
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||||
|
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||||
|
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||||
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
package archive
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "github.com/alist-org/alist/v3/internal/archive/archives"
|
||||||
|
_ "github.com/alist-org/alist/v3/internal/archive/iso9660"
|
||||||
|
_ "github.com/alist-org/alist/v3/internal/archive/zip"
|
||||||
|
)
|
|
@ -0,0 +1,126 @@
|
||||||
|
package archives
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/alist-org/alist/v3/internal/archive/tool"
|
||||||
|
"github.com/alist-org/alist/v3/internal/model"
|
||||||
|
"github.com/alist-org/alist/v3/internal/stream"
|
||||||
|
"github.com/alist-org/alist/v3/pkg/utils"
|
||||||
|
"io"
|
||||||
|
"io/fs"
|
||||||
|
"os"
|
||||||
|
stdpath "path"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Archives struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_ *Archives) AcceptedExtensions() []string {
|
||||||
|
return []string{
|
||||||
|
".br", ".bz2", ".gz", ".lz4", ".lz", ".sz", ".s2", ".xz", ".zz", ".zst", ".tar", ".rar", ".7z",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_ *Archives) GetMeta(ss *stream.SeekableStream, args model.ArchiveArgs) (model.ArchiveMeta, error) {
|
||||||
|
fsys, err := getFs(ss, args)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
_, err = fsys.ReadDir(".")
|
||||||
|
if err != nil {
|
||||||
|
return nil, filterPassword(err)
|
||||||
|
}
|
||||||
|
return &model.ArchiveMetaInfo{
|
||||||
|
Comment: "",
|
||||||
|
Encrypted: false,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_ *Archives) List(ss *stream.SeekableStream, args model.ArchiveInnerArgs) ([]model.Obj, error) {
|
||||||
|
fsys, err := getFs(ss, args.ArchiveArgs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
innerPath := strings.TrimPrefix(args.InnerPath, "/")
|
||||||
|
if innerPath == "" {
|
||||||
|
innerPath = "."
|
||||||
|
}
|
||||||
|
obj, err := fsys.ReadDir(innerPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, filterPassword(err)
|
||||||
|
}
|
||||||
|
return utils.SliceConvert(obj, func(src os.DirEntry) (model.Obj, error) {
|
||||||
|
info, err := src.Info()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return toModelObj(info), nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_ *Archives) Extract(ss *stream.SeekableStream, args model.ArchiveInnerArgs) (io.ReadCloser, int64, error) {
|
||||||
|
fsys, err := getFs(ss, args.ArchiveArgs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
file, err := fsys.Open(strings.TrimPrefix(args.InnerPath, "/"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, filterPassword(err)
|
||||||
|
}
|
||||||
|
stat, err := file.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, filterPassword(err)
|
||||||
|
}
|
||||||
|
return file, stat.Size(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_ *Archives) Decompress(ss *stream.SeekableStream, outputPath string, args model.ArchiveInnerArgs, up model.UpdateProgress) error {
|
||||||
|
fsys, err := getFs(ss, args.ArchiveArgs)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
isDir := false
|
||||||
|
path := strings.TrimPrefix(args.InnerPath, "/")
|
||||||
|
if path == "" {
|
||||||
|
isDir = true
|
||||||
|
path = "."
|
||||||
|
} else {
|
||||||
|
stat, err := fsys.Stat(path)
|
||||||
|
if err != nil {
|
||||||
|
return filterPassword(err)
|
||||||
|
}
|
||||||
|
if stat.IsDir() {
|
||||||
|
isDir = true
|
||||||
|
outputPath = stdpath.Join(outputPath, stat.Name())
|
||||||
|
err = os.Mkdir(outputPath, 0700)
|
||||||
|
if err != nil {
|
||||||
|
return filterPassword(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if isDir {
|
||||||
|
err = fs.WalkDir(fsys, path, func(p string, d fs.DirEntry, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
relPath := strings.TrimPrefix(p, path+"/")
|
||||||
|
dstPath := stdpath.Join(outputPath, relPath)
|
||||||
|
if d.IsDir() {
|
||||||
|
err = os.MkdirAll(dstPath, 0700)
|
||||||
|
} else {
|
||||||
|
dir := stdpath.Dir(dstPath)
|
||||||
|
err = decompress(fsys, p, dir, func(_ float64) {})
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
err = decompress(fsys, path, outputPath, up)
|
||||||
|
}
|
||||||
|
return filterPassword(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ tool.Tool = (*Archives)(nil)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
tool.RegisterTool(&Archives{})
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
package archives
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/alist-org/alist/v3/internal/errs"
|
||||||
|
"github.com/alist-org/alist/v3/internal/model"
|
||||||
|
"github.com/alist-org/alist/v3/internal/stream"
|
||||||
|
"github.com/mholt/archives"
|
||||||
|
"io"
|
||||||
|
fs2 "io/fs"
|
||||||
|
"os"
|
||||||
|
stdpath "path"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getFs(ss *stream.SeekableStream, args model.ArchiveArgs) (*archives.ArchiveFS, error) {
|
||||||
|
reader, err := stream.NewReadAtSeeker(ss, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
format, _, err := archives.Identify(ss.Ctx, ss.GetName(), reader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errs.UnknownArchiveFormat
|
||||||
|
}
|
||||||
|
extractor, ok := format.(archives.Extractor)
|
||||||
|
if !ok {
|
||||||
|
return nil, errs.UnknownArchiveFormat
|
||||||
|
}
|
||||||
|
switch f := format.(type) {
|
||||||
|
case archives.SevenZip:
|
||||||
|
f.Password = args.Password
|
||||||
|
case archives.Rar:
|
||||||
|
f.Password = args.Password
|
||||||
|
}
|
||||||
|
return &archives.ArchiveFS{
|
||||||
|
Stream: io.NewSectionReader(reader, 0, ss.GetSize()),
|
||||||
|
Format: extractor,
|
||||||
|
Context: ss.Ctx,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func toModelObj(file os.FileInfo) *model.Object {
|
||||||
|
return &model.Object{
|
||||||
|
Name: file.Name(),
|
||||||
|
Size: file.Size(),
|
||||||
|
Modified: file.ModTime(),
|
||||||
|
IsFolder: file.IsDir(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func filterPassword(err error) error {
|
||||||
|
if err != nil && strings.Contains(err.Error(), "password") {
|
||||||
|
return errs.WrongArchivePassword
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func decompress(fsys fs2.FS, filePath, targetPath string, up model.UpdateProgress) error {
|
||||||
|
rc, err := fsys.Open(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer rc.Close()
|
||||||
|
stat, err := rc.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
f, err := os.OpenFile(stdpath.Join(targetPath, stat.Name()), os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
_, err = io.Copy(f, &stream.ReaderUpdatingProgress{
|
||||||
|
Reader: &stream.SimpleReaderWithSize{
|
||||||
|
Reader: rc,
|
||||||
|
Size: stat.Size(),
|
||||||
|
},
|
||||||
|
UpdateProgress: up,
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
package iso9660
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/alist-org/alist/v3/internal/archive/tool"
|
||||||
|
"github.com/alist-org/alist/v3/internal/errs"
|
||||||
|
"github.com/alist-org/alist/v3/internal/model"
|
||||||
|
"github.com/alist-org/alist/v3/internal/stream"
|
||||||
|
"github.com/kdomanski/iso9660"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
stdpath "path"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ISO9660 struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *ISO9660) AcceptedExtensions() []string {
|
||||||
|
return []string{".iso"}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *ISO9660) GetMeta(ss *stream.SeekableStream, args model.ArchiveArgs) (model.ArchiveMeta, error) {
|
||||||
|
return &model.ArchiveMetaInfo{
|
||||||
|
Comment: "",
|
||||||
|
Encrypted: false,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *ISO9660) List(ss *stream.SeekableStream, args model.ArchiveInnerArgs) ([]model.Obj, error) {
|
||||||
|
img, err := getImage(ss)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dir, err := getObj(img, args.InnerPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !dir.IsDir() {
|
||||||
|
return nil, errs.NotFolder
|
||||||
|
}
|
||||||
|
children, err := dir.GetChildren()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ret := make([]model.Obj, 0, len(children))
|
||||||
|
for _, child := range children {
|
||||||
|
ret = append(ret, toModelObj(child))
|
||||||
|
}
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *ISO9660) Extract(ss *stream.SeekableStream, args model.ArchiveInnerArgs) (io.ReadCloser, int64, error) {
|
||||||
|
img, err := getImage(ss)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
obj, err := getObj(img, args.InnerPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
if obj.IsDir() {
|
||||||
|
return nil, 0, errs.NotFile
|
||||||
|
}
|
||||||
|
return io.NopCloser(obj.Reader()), obj.Size(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *ISO9660) Decompress(ss *stream.SeekableStream, outputPath string, args model.ArchiveInnerArgs, up model.UpdateProgress) error {
|
||||||
|
img, err := getImage(ss)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
obj, err := getObj(img, args.InnerPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if obj.IsDir() {
|
||||||
|
if args.InnerPath != "/" {
|
||||||
|
outputPath = stdpath.Join(outputPath, obj.Name())
|
||||||
|
if err = os.MkdirAll(outputPath, 0700); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var children []*iso9660.File
|
||||||
|
if children, err = obj.GetChildren(); err == nil {
|
||||||
|
err = decompressAll(children, outputPath)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = decompress(obj, outputPath, up)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ tool.Tool = (*ISO9660)(nil)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
tool.RegisterTool(&ISO9660{})
|
||||||
|
}
|
|
@ -0,0 +1,100 @@
|
||||||
|
package iso9660
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/alist-org/alist/v3/internal/errs"
|
||||||
|
"github.com/alist-org/alist/v3/internal/model"
|
||||||
|
"github.com/alist-org/alist/v3/internal/stream"
|
||||||
|
"github.com/kdomanski/iso9660"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
stdpath "path"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getImage(ss *stream.SeekableStream) (*iso9660.Image, error) {
|
||||||
|
reader, err := stream.NewReadAtSeeker(ss, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return iso9660.OpenImage(reader)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getObj(img *iso9660.Image, path string) (*iso9660.File, error) {
|
||||||
|
obj, err := img.RootDir()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if path == "/" {
|
||||||
|
return obj, nil
|
||||||
|
}
|
||||||
|
paths := strings.Split(strings.TrimPrefix(path, "/"), "/")
|
||||||
|
for _, p := range paths {
|
||||||
|
if !obj.IsDir() {
|
||||||
|
return nil, errs.ObjectNotFound
|
||||||
|
}
|
||||||
|
children, err := obj.GetChildren()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
exist := false
|
||||||
|
for _, child := range children {
|
||||||
|
if child.Name() == p {
|
||||||
|
obj = child
|
||||||
|
exist = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !exist {
|
||||||
|
return nil, errs.ObjectNotFound
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return obj, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func toModelObj(file *iso9660.File) model.Obj {
|
||||||
|
return &model.Object{
|
||||||
|
Name: file.Name(),
|
||||||
|
Size: file.Size(),
|
||||||
|
Modified: file.ModTime(),
|
||||||
|
IsFolder: file.IsDir(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func decompress(f *iso9660.File, path string, up model.UpdateProgress) error {
|
||||||
|
file, err := os.OpenFile(stdpath.Join(path, f.Name()), os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
_, err = io.Copy(file, &stream.ReaderUpdatingProgress{
|
||||||
|
Reader: &stream.SimpleReaderWithSize{
|
||||||
|
Reader: f.Reader(),
|
||||||
|
Size: f.Size(),
|
||||||
|
},
|
||||||
|
UpdateProgress: up,
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func decompressAll(children []*iso9660.File, path string) error {
|
||||||
|
for _, child := range children {
|
||||||
|
if child.IsDir() {
|
||||||
|
nextChildren, err := child.GetChildren()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
nextPath := stdpath.Join(path, child.Name())
|
||||||
|
if err = os.MkdirAll(nextPath, 0700); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = decompressAll(nextChildren, nextPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := decompress(child, path, func(_ float64) {}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
package tool
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/alist-org/alist/v3/internal/model"
|
||||||
|
"github.com/alist-org/alist/v3/internal/stream"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Tool interface {
|
||||||
|
AcceptedExtensions() []string
|
||||||
|
GetMeta(ss *stream.SeekableStream, args model.ArchiveArgs) (model.ArchiveMeta, error)
|
||||||
|
List(ss *stream.SeekableStream, args model.ArchiveInnerArgs) ([]model.Obj, error)
|
||||||
|
Extract(ss *stream.SeekableStream, args model.ArchiveInnerArgs) (io.ReadCloser, int64, error)
|
||||||
|
Decompress(ss *stream.SeekableStream, outputPath string, args model.ArchiveInnerArgs, up model.UpdateProgress) error
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package tool
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/alist-org/alist/v3/internal/errs"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
Tools = make(map[string]Tool)
|
||||||
|
)
|
||||||
|
|
||||||
|
func RegisterTool(tool Tool) {
|
||||||
|
for _, ext := range tool.AcceptedExtensions() {
|
||||||
|
Tools[ext] = tool
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetArchiveTool(ext string) (Tool, error) {
|
||||||
|
t, ok := Tools[ext]
|
||||||
|
if !ok {
|
||||||
|
return nil, errs.UnknownArchiveFormat
|
||||||
|
}
|
||||||
|
return t, nil
|
||||||
|
}
|
|
@ -0,0 +1,156 @@
|
||||||
|
package zip
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"github.com/alist-org/alist/v3/internal/errs"
|
||||||
|
"github.com/alist-org/alist/v3/internal/model"
|
||||||
|
"github.com/alist-org/alist/v3/internal/stream"
|
||||||
|
"github.com/saintfish/chardet"
|
||||||
|
"github.com/yeka/zip"
|
||||||
|
"golang.org/x/text/encoding"
|
||||||
|
"golang.org/x/text/encoding/charmap"
|
||||||
|
"golang.org/x/text/encoding/japanese"
|
||||||
|
"golang.org/x/text/encoding/korean"
|
||||||
|
"golang.org/x/text/encoding/simplifiedchinese"
|
||||||
|
"golang.org/x/text/encoding/traditionalchinese"
|
||||||
|
"golang.org/x/text/encoding/unicode"
|
||||||
|
"golang.org/x/text/encoding/unicode/utf32"
|
||||||
|
"golang.org/x/text/transform"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
stdpath "path"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func toModelObj(file os.FileInfo) *model.Object {
|
||||||
|
return &model.Object{
|
||||||
|
Name: decodeName(file.Name()),
|
||||||
|
Size: file.Size(),
|
||||||
|
Modified: file.ModTime(),
|
||||||
|
IsFolder: file.IsDir(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func decompress(file *zip.File, filePath, outputPath, password string) error {
|
||||||
|
targetPath := outputPath
|
||||||
|
dir, base := stdpath.Split(filePath)
|
||||||
|
if dir != "" {
|
||||||
|
targetPath = stdpath.Join(targetPath, dir)
|
||||||
|
err := os.MkdirAll(targetPath, 0700)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if base != "" {
|
||||||
|
err := _decompress(file, targetPath, password, func(_ float64) {})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func _decompress(file *zip.File, targetPath, password string, up model.UpdateProgress) error {
|
||||||
|
if file.IsEncrypted() {
|
||||||
|
file.SetPassword(password)
|
||||||
|
}
|
||||||
|
rc, err := file.Open()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer rc.Close()
|
||||||
|
f, err := os.OpenFile(stdpath.Join(targetPath, file.FileInfo().Name()), os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
_, err = io.Copy(f, &stream.ReaderUpdatingProgress{
|
||||||
|
Reader: &stream.SimpleReaderWithSize{
|
||||||
|
Reader: rc,
|
||||||
|
Size: file.FileInfo().Size(),
|
||||||
|
},
|
||||||
|
UpdateProgress: up,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func filterPassword(err error) error {
|
||||||
|
if err != nil && strings.Contains(err.Error(), "password") {
|
||||||
|
return errs.WrongArchivePassword
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeName(name string) string {
|
||||||
|
b := []byte(name)
|
||||||
|
detector := chardet.NewTextDetector()
|
||||||
|
result, err := detector.DetectBest(b)
|
||||||
|
if err != nil {
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
enc := getEncoding(result.Charset)
|
||||||
|
if enc == nil {
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
i := bytes.NewReader(b)
|
||||||
|
decoder := transform.NewReader(i, enc.NewDecoder())
|
||||||
|
content, _ := io.ReadAll(decoder)
|
||||||
|
return string(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getEncoding(name string) (enc encoding.Encoding) {
|
||||||
|
switch name {
|
||||||
|
case "UTF-16BE":
|
||||||
|
enc = unicode.UTF16(unicode.BigEndian, unicode.IgnoreBOM)
|
||||||
|
case "UTF-16LE":
|
||||||
|
enc = unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM)
|
||||||
|
case "UTF-32BE":
|
||||||
|
enc = utf32.UTF32(utf32.BigEndian, utf32.IgnoreBOM)
|
||||||
|
case "UTF-32LE":
|
||||||
|
enc = utf32.UTF32(utf32.LittleEndian, utf32.IgnoreBOM)
|
||||||
|
case "ISO-8859-1":
|
||||||
|
enc = charmap.ISO8859_1
|
||||||
|
case "ISO-8859-2":
|
||||||
|
enc = charmap.ISO8859_2
|
||||||
|
case "ISO-8859-3":
|
||||||
|
enc = charmap.ISO8859_3
|
||||||
|
case "ISO-8859-4":
|
||||||
|
enc = charmap.ISO8859_4
|
||||||
|
case "ISO-8859-5":
|
||||||
|
enc = charmap.ISO8859_5
|
||||||
|
case "ISO-8859-6":
|
||||||
|
enc = charmap.ISO8859_6
|
||||||
|
case "ISO-8859-7":
|
||||||
|
enc = charmap.ISO8859_7
|
||||||
|
case "ISO-8859-8":
|
||||||
|
enc = charmap.ISO8859_8
|
||||||
|
case "ISO-8859-8-I":
|
||||||
|
enc = charmap.ISO8859_8I
|
||||||
|
case "ISO-8859-9":
|
||||||
|
enc = charmap.ISO8859_9
|
||||||
|
case "windows-1251":
|
||||||
|
enc = charmap.Windows1251
|
||||||
|
case "windows-1256":
|
||||||
|
enc = charmap.Windows1256
|
||||||
|
case "KOI8-R":
|
||||||
|
enc = charmap.KOI8R
|
||||||
|
case "Shift_JIS":
|
||||||
|
enc = japanese.ShiftJIS
|
||||||
|
case "GB-18030":
|
||||||
|
enc = simplifiedchinese.GB18030
|
||||||
|
case "EUC-JP":
|
||||||
|
enc = japanese.EUCJP
|
||||||
|
case "EUC-KR":
|
||||||
|
enc = korean.EUCKR
|
||||||
|
case "Big5":
|
||||||
|
enc = traditionalchinese.Big5
|
||||||
|
case "ISO-2022-JP":
|
||||||
|
enc = japanese.ISO2022JP
|
||||||
|
default:
|
||||||
|
enc = nil
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
|
@ -0,0 +1,174 @@
|
||||||
|
package zip
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/alist-org/alist/v3/internal/archive/tool"
|
||||||
|
"github.com/alist-org/alist/v3/internal/errs"
|
||||||
|
"github.com/alist-org/alist/v3/internal/model"
|
||||||
|
"github.com/alist-org/alist/v3/internal/stream"
|
||||||
|
"github.com/yeka/zip"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
stdpath "path"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Zip struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_ *Zip) AcceptedExtensions() []string {
|
||||||
|
return []string{".zip"}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_ *Zip) GetMeta(ss *stream.SeekableStream, args model.ArchiveArgs) (model.ArchiveMeta, error) {
|
||||||
|
reader, err := stream.NewReadAtSeeker(ss, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
zipReader, err := zip.NewReader(reader, ss.GetSize())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
encrypted := false
|
||||||
|
for _, file := range zipReader.File {
|
||||||
|
if file.IsEncrypted() {
|
||||||
|
encrypted = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &model.ArchiveMetaInfo{
|
||||||
|
Comment: zipReader.Comment,
|
||||||
|
Encrypted: encrypted,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_ *Zip) List(ss *stream.SeekableStream, args model.ArchiveInnerArgs) ([]model.Obj, error) {
|
||||||
|
reader, err := stream.NewReadAtSeeker(ss, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
zipReader, err := zip.NewReader(reader, ss.GetSize())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if args.InnerPath == "/" {
|
||||||
|
ret := make([]model.Obj, 0)
|
||||||
|
passVerified := false
|
||||||
|
for _, file := range zipReader.File {
|
||||||
|
if !passVerified && file.IsEncrypted() {
|
||||||
|
file.SetPassword(args.Password)
|
||||||
|
rc, e := file.Open()
|
||||||
|
if e != nil {
|
||||||
|
return nil, filterPassword(e)
|
||||||
|
}
|
||||||
|
_ = rc.Close()
|
||||||
|
passVerified = true
|
||||||
|
}
|
||||||
|
name := decodeName(file.Name)
|
||||||
|
if strings.Contains(strings.TrimSuffix(name, "/"), "/") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ret = append(ret, toModelObj(file.FileInfo()))
|
||||||
|
}
|
||||||
|
return ret, nil
|
||||||
|
} else {
|
||||||
|
innerPath := strings.TrimPrefix(args.InnerPath, "/") + "/"
|
||||||
|
ret := make([]model.Obj, 0)
|
||||||
|
exist := false
|
||||||
|
for _, file := range zipReader.File {
|
||||||
|
name := decodeName(file.Name)
|
||||||
|
if name == innerPath {
|
||||||
|
exist = true
|
||||||
|
}
|
||||||
|
dir := stdpath.Dir(strings.TrimSuffix(name, "/")) + "/"
|
||||||
|
if dir != innerPath {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ret = append(ret, toModelObj(file.FileInfo()))
|
||||||
|
}
|
||||||
|
if !exist {
|
||||||
|
return nil, errs.ObjectNotFound
|
||||||
|
}
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_ *Zip) Extract(ss *stream.SeekableStream, args model.ArchiveInnerArgs) (io.ReadCloser, int64, error) {
|
||||||
|
reader, err := stream.NewReadAtSeeker(ss, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
zipReader, err := zip.NewReader(reader, ss.GetSize())
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
innerPath := strings.TrimPrefix(args.InnerPath, "/")
|
||||||
|
for _, file := range zipReader.File {
|
||||||
|
if decodeName(file.Name) == innerPath {
|
||||||
|
if file.IsEncrypted() {
|
||||||
|
file.SetPassword(args.Password)
|
||||||
|
}
|
||||||
|
r, e := file.Open()
|
||||||
|
if e != nil {
|
||||||
|
return nil, 0, e
|
||||||
|
}
|
||||||
|
return r, file.FileInfo().Size(), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, 0, errs.ObjectNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_ *Zip) Decompress(ss *stream.SeekableStream, outputPath string, args model.ArchiveInnerArgs, up model.UpdateProgress) error {
|
||||||
|
reader, err := stream.NewReadAtSeeker(ss, 0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
zipReader, err := zip.NewReader(reader, ss.GetSize())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if args.InnerPath == "/" {
|
||||||
|
for i, file := range zipReader.File {
|
||||||
|
name := decodeName(file.Name)
|
||||||
|
err = decompress(file, name, outputPath, args.Password)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
up(float64(i+1) * 100.0 / float64(len(zipReader.File)))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
innerPath := strings.TrimPrefix(args.InnerPath, "/")
|
||||||
|
innerBase := stdpath.Base(innerPath)
|
||||||
|
createdBaseDir := false
|
||||||
|
for _, file := range zipReader.File {
|
||||||
|
name := decodeName(file.Name)
|
||||||
|
if name == innerPath {
|
||||||
|
err = _decompress(file, outputPath, args.Password, up)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
break
|
||||||
|
} else if strings.HasPrefix(name, innerPath+"/") {
|
||||||
|
targetPath := stdpath.Join(outputPath, innerBase)
|
||||||
|
if !createdBaseDir {
|
||||||
|
err = os.Mkdir(targetPath, 0700)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
createdBaseDir = true
|
||||||
|
}
|
||||||
|
restPath := strings.TrimPrefix(name, innerPath+"/")
|
||||||
|
err = decompress(file, restPath, targetPath, args.Password)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ tool.Tool = (*Zip)(nil)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
tool.RegisterTool(&Zip{})
|
||||||
|
}
|
|
@ -26,13 +26,14 @@ func initUser() {
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
salt := random.String(16)
|
salt := random.String(16)
|
||||||
admin = &model.User{
|
admin = &model.User{
|
||||||
Username: "admin",
|
Username: "admin",
|
||||||
Salt: salt,
|
Salt: salt,
|
||||||
PwdHash: model.TwoHashPwd(adminPassword, salt),
|
PwdHash: model.TwoHashPwd(adminPassword, salt),
|
||||||
Role: model.ADMIN,
|
Role: model.ADMIN,
|
||||||
BasePath: "/",
|
BasePath: "/",
|
||||||
Authn: "[]",
|
Authn: "[]",
|
||||||
Permission: 0xFF, // 0(can see hidden) - 7(can remove)
|
// 0(can see hidden) - 7(can remove) & 12(can read archives) - 13(can decompress archives)
|
||||||
|
Permission: 0x30FF,
|
||||||
}
|
}
|
||||||
if err := op.CreateUser(admin); err != nil {
|
if err := op.CreateUser(admin); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|
|
@ -5,18 +5,20 @@ import (
|
||||||
"github.com/alist-org/alist/v3/pkg/utils"
|
"github.com/alist-org/alist/v3/pkg/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GrantAdminPermissions gives admin Permission 0(can see hidden) - 9(webdav manage)
|
// GrantAdminPermissions gives admin Permission 0(can see hidden) - 9(webdav manage) and
|
||||||
// This patch is written to help users upgrading from older version better adapt to PR AlistGo/alist#7705.
|
// 12(can read archives) - 13(can decompress archives)
|
||||||
|
// This patch is written to help users upgrading from older version better adapt to PR AlistGo/alist#7705 and
|
||||||
|
// PR AlistGo/alist#7817.
|
||||||
func GrantAdminPermissions() {
|
func GrantAdminPermissions() {
|
||||||
admin, err := op.GetAdmin()
|
admin, err := op.GetAdmin()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Log.Errorf("Cannot grant permissions to admin: %v", err)
|
utils.Log.Errorf("Cannot grant permissions to admin: %v", err)
|
||||||
}
|
}
|
||||||
if (admin.Permission & 0x3FF) == 0 {
|
if (admin.Permission & 0x33FF) == 0 {
|
||||||
admin.Permission |= 0x3FF
|
admin.Permission |= 0x33FF
|
||||||
}
|
err = op.UpdateUser(admin)
|
||||||
err = op.UpdateUser(admin)
|
if err != nil {
|
||||||
if err != nil {
|
utils.Log.Errorf("Cannot grant permissions to admin: %v", err)
|
||||||
utils.Log.Errorf("Cannot grant permissions to admin: %v", err)
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,4 +16,6 @@ func InitTaskManager() {
|
||||||
if len(tool.TransferTaskManager.GetAll()) == 0 { //prevent offline downloaded files from being deleted
|
if len(tool.TransferTaskManager.GetAll()) == 0 { //prevent offline downloaded files from being deleted
|
||||||
CleanTempDir()
|
CleanTempDir()
|
||||||
}
|
}
|
||||||
|
fs.ArchiveDownloadTaskManager = tache.NewManager[*fs.ArchiveDownloadTask](tache.WithWorks(conf.Conf.Tasks.Decompress.Workers), tache.WithPersistFunction(db.GetTaskDataFunc("decompress", conf.Conf.Tasks.Decompress.TaskPersistant), db.UpdateTaskDataFunc("decompress", conf.Conf.Tasks.Decompress.TaskPersistant)), tache.WithMaxRetry(conf.Conf.Tasks.Decompress.MaxRetry))
|
||||||
|
fs.ArchiveContentUploadTaskManager.Manager = tache.NewManager[*fs.ArchiveContentUploadTask](tache.WithWorks(conf.Conf.Tasks.DecompressUpload.Workers), tache.WithMaxRetry(conf.Conf.Tasks.DecompressUpload.MaxRetry)) //decompress upload will not support persist
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,10 +53,12 @@ type TaskConfig struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type TasksConfig struct {
|
type TasksConfig struct {
|
||||||
Download TaskConfig `json:"download" envPrefix:"DOWNLOAD_"`
|
Download TaskConfig `json:"download" envPrefix:"DOWNLOAD_"`
|
||||||
Transfer TaskConfig `json:"transfer" envPrefix:"TRANSFER_"`
|
Transfer TaskConfig `json:"transfer" envPrefix:"TRANSFER_"`
|
||||||
Upload TaskConfig `json:"upload" envPrefix:"UPLOAD_"`
|
Upload TaskConfig `json:"upload" envPrefix:"UPLOAD_"`
|
||||||
Copy TaskConfig `json:"copy" envPrefix:"COPY_"`
|
Copy TaskConfig `json:"copy" envPrefix:"COPY_"`
|
||||||
|
Decompress TaskConfig `json:"decompress" envPrefix:"DECOMPRESS_"`
|
||||||
|
DecompressUpload TaskConfig `json:"decompress_upload" envPrefix:"DECOMPRESS_UPLOAD_"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Cors struct {
|
type Cors struct {
|
||||||
|
@ -169,6 +171,15 @@ func DefaultConfig() *Config {
|
||||||
MaxRetry: 2,
|
MaxRetry: 2,
|
||||||
// TaskPersistant: true,
|
// TaskPersistant: true,
|
||||||
},
|
},
|
||||||
|
Decompress: TaskConfig{
|
||||||
|
Workers: 5,
|
||||||
|
MaxRetry: 2,
|
||||||
|
// TaskPersistant: true,
|
||||||
|
},
|
||||||
|
DecompressUpload: TaskConfig{
|
||||||
|
Workers: 5,
|
||||||
|
MaxRetry: 2,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Cors: Cors{
|
Cors: Cors{
|
||||||
AllowOrigins: []string{"*"},
|
AllowOrigins: []string{"*"},
|
||||||
|
|
|
@ -123,7 +123,43 @@ type PutURLResult interface {
|
||||||
PutURL(ctx context.Context, dstDir model.Obj, name, url string) (model.Obj, error)
|
PutURL(ctx context.Context, dstDir model.Obj, name, url string) (model.Obj, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type UpdateProgress func(percentage float64)
|
type ArchiveReader interface {
|
||||||
|
// GetArchiveMeta get the meta-info of an archive
|
||||||
|
// return errs.WrongArchivePassword if the meta-info is also encrypted but provided password is wrong or empty
|
||||||
|
// return errs.NotImplement to use internal archive tools to get the meta-info, such as the following cases:
|
||||||
|
// 1. the driver do not support the format of the archive but there may be an internal tool do
|
||||||
|
// 2. handling archives is a VIP feature, but the driver does not have VIP access
|
||||||
|
GetArchiveMeta(ctx context.Context, obj model.Obj, args model.ArchiveArgs) (model.ArchiveMeta, error)
|
||||||
|
// ListArchive list the children of model.ArchiveArgs.InnerPath in the archive
|
||||||
|
// return errs.NotImplement to use internal archive tools to list the children
|
||||||
|
// return errs.NotSupport if the folder structure should be acquired from model.ArchiveMeta.GetTree
|
||||||
|
ListArchive(ctx context.Context, obj model.Obj, args model.ArchiveInnerArgs) ([]model.Obj, error)
|
||||||
|
// Extract get url/filepath/reader of a file in the archive
|
||||||
|
// return errs.NotImplement to use internal archive tools to extract
|
||||||
|
Extract(ctx context.Context, obj model.Obj, args model.ArchiveInnerArgs) (*model.Link, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ArchiveGetter interface {
|
||||||
|
// ArchiveGet get file by inner path
|
||||||
|
// return errs.NotImplement to use internal archive tools to get the children
|
||||||
|
// return errs.NotSupport if the folder structure should be acquired from model.ArchiveMeta.GetTree
|
||||||
|
ArchiveGet(ctx context.Context, obj model.Obj, args model.ArchiveInnerArgs) (model.Obj, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ArchiveDecompress interface {
|
||||||
|
ArchiveDecompress(ctx context.Context, srcObj, dstDir model.Obj, args model.ArchiveDecompressArgs) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type ArchiveDecompressResult interface {
|
||||||
|
// ArchiveDecompress decompress an archive
|
||||||
|
// when args.PutIntoNewDir, the new sub-folder should be named the same to the archive but without the extension
|
||||||
|
// return each decompressed obj from the root path of the archive when args.PutIntoNewDir is false
|
||||||
|
// return only the newly created folder when args.PutIntoNewDir is true
|
||||||
|
// return errs.NotImplement to use internal archive tools to decompress
|
||||||
|
ArchiveDecompress(ctx context.Context, srcObj, dstDir model.Obj, args model.ArchiveDecompressArgs) ([]model.Obj, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateProgress model.UpdateProgress
|
||||||
|
|
||||||
type Progress struct {
|
type Progress struct {
|
||||||
Total int64
|
Total int64
|
||||||
|
|
|
@ -19,6 +19,10 @@ var (
|
||||||
StorageNotFound = errors.New("storage not found")
|
StorageNotFound = errors.New("storage not found")
|
||||||
StreamIncomplete = errors.New("upload/download stream incomplete, possible network issue")
|
StreamIncomplete = errors.New("upload/download stream incomplete, possible network issue")
|
||||||
StreamPeekFail = errors.New("StreamPeekFail")
|
StreamPeekFail = errors.New("StreamPeekFail")
|
||||||
|
|
||||||
|
UnknownArchiveFormat = errors.New("unknown archive format")
|
||||||
|
WrongArchivePassword = errors.New("wrong archive password")
|
||||||
|
DriverExtractNotSupported = errors.New("driver extraction not supported")
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewErr wrap constant error with an extra message
|
// NewErr wrap constant error with an extra message
|
||||||
|
|
|
@ -0,0 +1,395 @@
|
||||||
|
package fs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
stderrors "errors"
|
||||||
|
"fmt"
|
||||||
|
"github.com/alist-org/alist/v3/internal/archive/tool"
|
||||||
|
"github.com/alist-org/alist/v3/internal/conf"
|
||||||
|
"github.com/alist-org/alist/v3/internal/driver"
|
||||||
|
"github.com/alist-org/alist/v3/internal/errs"
|
||||||
|
"github.com/alist-org/alist/v3/internal/model"
|
||||||
|
"github.com/alist-org/alist/v3/internal/op"
|
||||||
|
"github.com/alist-org/alist/v3/internal/stream"
|
||||||
|
"github.com/alist-org/alist/v3/internal/task"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"github.com/xhofe/tache"
|
||||||
|
"io"
|
||||||
|
"math/rand"
|
||||||
|
"mime"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
stdpath "path"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ArchiveDownloadTask struct {
|
||||||
|
task.TaskExtension
|
||||||
|
model.ArchiveDecompressArgs
|
||||||
|
status string
|
||||||
|
SrcObjPath string
|
||||||
|
DstDirPath string
|
||||||
|
srcStorage driver.Driver
|
||||||
|
dstStorage driver.Driver
|
||||||
|
SrcStorageMp string
|
||||||
|
DstStorageMp string
|
||||||
|
Tool tool.Tool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *ArchiveDownloadTask) GetName() string {
|
||||||
|
return fmt.Sprintf("decompress [%s](%s)[%s] to [%s](%s) with password <%s>", t.SrcStorageMp, t.SrcObjPath,
|
||||||
|
t.InnerPath, t.DstStorageMp, t.DstDirPath, t.Password)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *ArchiveDownloadTask) GetStatus() string {
|
||||||
|
return t.status
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *ArchiveDownloadTask) Run() error {
|
||||||
|
t.ClearEndTime()
|
||||||
|
t.SetStartTime(time.Now())
|
||||||
|
defer func() { t.SetEndTime(time.Now()) }()
|
||||||
|
uploadTask, err := t.RunWithoutPushUploadTask()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ArchiveContentUploadTaskManager.Add(uploadTask)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *ArchiveDownloadTask) RunWithoutPushUploadTask() (*ArchiveContentUploadTask, error) {
|
||||||
|
var err error
|
||||||
|
if t.srcStorage == nil {
|
||||||
|
t.srcStorage, err = op.GetStorageByMountPath(t.SrcStorageMp)
|
||||||
|
}
|
||||||
|
l, srcObj, err := op.Link(t.Ctx(), t.srcStorage, t.SrcObjPath, model.LinkArgs{
|
||||||
|
Header: http.Header{},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
fs := stream.FileStream{
|
||||||
|
Obj: srcObj,
|
||||||
|
Ctx: t.Ctx(),
|
||||||
|
}
|
||||||
|
ss, err := stream.NewSeekableStream(fs, l)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if err := ss.Close(); err != nil {
|
||||||
|
log.Errorf("failed to close file streamer, %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
var decompressUp model.UpdateProgress
|
||||||
|
if t.CacheFull {
|
||||||
|
t.SetTotalBytes(srcObj.GetSize())
|
||||||
|
t.status = "getting src object"
|
||||||
|
_, err = ss.CacheFullInTempFileAndUpdateProgress(t.SetProgress)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
decompressUp = func(_ float64) {}
|
||||||
|
} else {
|
||||||
|
decompressUp = t.SetProgress
|
||||||
|
}
|
||||||
|
t.status = "walking and decompressing"
|
||||||
|
dir, err := os.MkdirTemp(conf.Conf.TempDir, "dir-*")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = t.Tool.Decompress(ss, dir, t.ArchiveInnerArgs, decompressUp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
baseName := strings.TrimSuffix(srcObj.GetName(), stdpath.Ext(srcObj.GetName()))
|
||||||
|
uploadTask := &ArchiveContentUploadTask{
|
||||||
|
TaskExtension: task.TaskExtension{
|
||||||
|
Creator: t.GetCreator(),
|
||||||
|
},
|
||||||
|
ObjName: baseName,
|
||||||
|
InPlace: !t.PutIntoNewDir,
|
||||||
|
FilePath: dir,
|
||||||
|
DstDirPath: t.DstDirPath,
|
||||||
|
dstStorage: t.dstStorage,
|
||||||
|
DstStorageMp: t.DstStorageMp,
|
||||||
|
}
|
||||||
|
return uploadTask, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var ArchiveDownloadTaskManager *tache.Manager[*ArchiveDownloadTask]
|
||||||
|
|
||||||
|
type ArchiveContentUploadTask struct {
|
||||||
|
task.TaskExtension
|
||||||
|
status string
|
||||||
|
ObjName string
|
||||||
|
InPlace bool
|
||||||
|
FilePath string
|
||||||
|
DstDirPath string
|
||||||
|
dstStorage driver.Driver
|
||||||
|
DstStorageMp string
|
||||||
|
finalized bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *ArchiveContentUploadTask) GetName() string {
|
||||||
|
return fmt.Sprintf("upload %s to [%s](%s)", t.ObjName, t.DstStorageMp, t.DstDirPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *ArchiveContentUploadTask) GetStatus() string {
|
||||||
|
return t.status
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *ArchiveContentUploadTask) Run() error {
|
||||||
|
t.ClearEndTime()
|
||||||
|
t.SetStartTime(time.Now())
|
||||||
|
defer func() { t.SetEndTime(time.Now()) }()
|
||||||
|
return t.RunWithNextTaskCallback(func(nextTsk *ArchiveContentUploadTask) error {
|
||||||
|
ArchiveContentUploadTaskManager.Add(nextTsk)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *ArchiveContentUploadTask) RunWithNextTaskCallback(f func(nextTsk *ArchiveContentUploadTask) error) error {
|
||||||
|
var err error
|
||||||
|
if t.dstStorage == nil {
|
||||||
|
t.dstStorage, err = op.GetStorageByMountPath(t.DstStorageMp)
|
||||||
|
}
|
||||||
|
info, err := os.Stat(t.FilePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if info.IsDir() {
|
||||||
|
t.status = "src object is dir, listing objs"
|
||||||
|
nextDstPath := t.DstDirPath
|
||||||
|
if !t.InPlace {
|
||||||
|
nextDstPath = stdpath.Join(nextDstPath, t.ObjName)
|
||||||
|
err = op.MakeDir(t.Ctx(), t.dstStorage, nextDstPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
entries, err := os.ReadDir(t.FilePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var es error
|
||||||
|
for _, entry := range entries {
|
||||||
|
var nextFilePath string
|
||||||
|
if entry.IsDir() {
|
||||||
|
nextFilePath, err = moveToTempPath(stdpath.Join(t.FilePath, entry.Name()), "dir-")
|
||||||
|
} else {
|
||||||
|
nextFilePath, err = moveToTempPath(stdpath.Join(t.FilePath, entry.Name()), "file-")
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
es = stderrors.Join(es, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
err = f(&ArchiveContentUploadTask{
|
||||||
|
TaskExtension: task.TaskExtension{
|
||||||
|
Creator: t.GetCreator(),
|
||||||
|
},
|
||||||
|
ObjName: entry.Name(),
|
||||||
|
InPlace: false,
|
||||||
|
FilePath: nextFilePath,
|
||||||
|
DstDirPath: nextDstPath,
|
||||||
|
dstStorage: t.dstStorage,
|
||||||
|
DstStorageMp: t.DstStorageMp,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
es = stderrors.Join(es, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if es != nil {
|
||||||
|
return es
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
t.SetTotalBytes(info.Size())
|
||||||
|
file, err := os.Open(t.FilePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fs := &stream.FileStream{
|
||||||
|
Obj: &model.Object{
|
||||||
|
Name: t.ObjName,
|
||||||
|
Size: info.Size(),
|
||||||
|
Modified: time.Now(),
|
||||||
|
},
|
||||||
|
Mimetype: mime.TypeByExtension(filepath.Ext(t.ObjName)),
|
||||||
|
WebPutAsTask: true,
|
||||||
|
Reader: file,
|
||||||
|
}
|
||||||
|
fs.Closers.Add(file)
|
||||||
|
t.status = "uploading"
|
||||||
|
err = op.Put(t.Ctx(), t.dstStorage, t.DstDirPath, fs, t.SetProgress, true)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.deleteSrcFile()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *ArchiveContentUploadTask) Cancel() {
|
||||||
|
t.TaskExtension.Cancel()
|
||||||
|
t.deleteSrcFile()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *ArchiveContentUploadTask) deleteSrcFile() {
|
||||||
|
if !t.finalized {
|
||||||
|
_ = os.RemoveAll(t.FilePath)
|
||||||
|
t.finalized = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func moveToTempPath(path, prefix string) (string, error) {
|
||||||
|
newPath, err := genTempFileName(prefix)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
err = os.Rename(path, newPath)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return newPath, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func genTempFileName(prefix string) (string, error) {
|
||||||
|
retry := 0
|
||||||
|
for retry < 10000 {
|
||||||
|
newPath := stdpath.Join(conf.Conf.TempDir, prefix+strconv.FormatUint(uint64(rand.Uint32()), 10))
|
||||||
|
if _, err := os.Stat(newPath); err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return newPath, nil
|
||||||
|
} else {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
retry++
|
||||||
|
}
|
||||||
|
return "", errors.New("failed to generate temp-file name: too many retries")
|
||||||
|
}
|
||||||
|
|
||||||
|
type archiveContentUploadTaskManagerType struct {
|
||||||
|
*tache.Manager[*ArchiveContentUploadTask]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *archiveContentUploadTaskManagerType) Remove(id string) {
|
||||||
|
if t, ok := m.GetByID(id); ok {
|
||||||
|
t.deleteSrcFile()
|
||||||
|
m.Manager.Remove(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *archiveContentUploadTaskManagerType) RemoveAll() {
|
||||||
|
tasks := m.GetAll()
|
||||||
|
for _, t := range tasks {
|
||||||
|
m.Remove(t.GetID())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *archiveContentUploadTaskManagerType) RemoveByState(state ...tache.State) {
|
||||||
|
tasks := m.GetByState(state...)
|
||||||
|
for _, t := range tasks {
|
||||||
|
m.Remove(t.GetID())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *archiveContentUploadTaskManagerType) RemoveByCondition(condition func(task *ArchiveContentUploadTask) bool) {
|
||||||
|
tasks := m.GetByCondition(condition)
|
||||||
|
for _, t := range tasks {
|
||||||
|
m.Remove(t.GetID())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var ArchiveContentUploadTaskManager = &archiveContentUploadTaskManagerType{
|
||||||
|
Manager: nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
func archiveMeta(ctx context.Context, path string, args model.ArchiveMetaArgs) (*model.ArchiveMetaProvider, error) {
|
||||||
|
storage, actualPath, err := op.GetStorageAndActualPath(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithMessage(err, "failed get storage")
|
||||||
|
}
|
||||||
|
return op.GetArchiveMeta(ctx, storage, actualPath, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
func archiveList(ctx context.Context, path string, args model.ArchiveListArgs) ([]model.Obj, error) {
|
||||||
|
storage, actualPath, err := op.GetStorageAndActualPath(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithMessage(err, "failed get storage")
|
||||||
|
}
|
||||||
|
return op.ListArchive(ctx, storage, actualPath, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
func archiveDecompress(ctx context.Context, srcObjPath, dstDirPath string, args model.ArchiveDecompressArgs, lazyCache ...bool) (task.TaskExtensionInfo, error) {
|
||||||
|
srcStorage, srcObjActualPath, err := op.GetStorageAndActualPath(srcObjPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithMessage(err, "failed get src storage")
|
||||||
|
}
|
||||||
|
dstStorage, dstDirActualPath, err := op.GetStorageAndActualPath(dstDirPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithMessage(err, "failed get dst storage")
|
||||||
|
}
|
||||||
|
if srcStorage.GetStorage() == dstStorage.GetStorage() {
|
||||||
|
err = op.ArchiveDecompress(ctx, srcStorage, srcObjActualPath, dstDirActualPath, args, lazyCache...)
|
||||||
|
if !errors.Is(err, errs.NotImplement) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ext := stdpath.Ext(srcObjActualPath)
|
||||||
|
t, err := tool.GetArchiveTool(ext)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithMessagef(err, "failed get [%s] archive tool", ext)
|
||||||
|
}
|
||||||
|
taskCreator, _ := ctx.Value("user").(*model.User)
|
||||||
|
tsk := &ArchiveDownloadTask{
|
||||||
|
TaskExtension: task.TaskExtension{
|
||||||
|
Creator: taskCreator,
|
||||||
|
},
|
||||||
|
ArchiveDecompressArgs: args,
|
||||||
|
srcStorage: srcStorage,
|
||||||
|
dstStorage: dstStorage,
|
||||||
|
SrcObjPath: srcObjActualPath,
|
||||||
|
DstDirPath: dstDirActualPath,
|
||||||
|
SrcStorageMp: srcStorage.GetStorage().MountPath,
|
||||||
|
DstStorageMp: dstStorage.GetStorage().MountPath,
|
||||||
|
Tool: t,
|
||||||
|
}
|
||||||
|
if ctx.Value(conf.NoTaskKey) != nil {
|
||||||
|
uploadTask, err := tsk.RunWithoutPushUploadTask()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithMessagef(err, "failed download [%s]", srcObjPath)
|
||||||
|
}
|
||||||
|
defer uploadTask.deleteSrcFile()
|
||||||
|
var callback func(t *ArchiveContentUploadTask) error
|
||||||
|
callback = func(t *ArchiveContentUploadTask) error {
|
||||||
|
e := t.RunWithNextTaskCallback(callback)
|
||||||
|
t.deleteSrcFile()
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
return nil, uploadTask.RunWithNextTaskCallback(callback)
|
||||||
|
} else {
|
||||||
|
ArchiveDownloadTaskManager.Add(tsk)
|
||||||
|
return tsk, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func archiveDriverExtract(ctx context.Context, path string, args model.ArchiveInnerArgs) (*model.Link, model.Obj, error) {
|
||||||
|
storage, actualPath, err := op.GetStorageAndActualPath(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, errors.WithMessage(err, "failed get storage")
|
||||||
|
}
|
||||||
|
return op.DriverExtract(ctx, storage, actualPath, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
func archiveInternalExtract(ctx context.Context, path string, args model.ArchiveInnerArgs) (io.ReadCloser, int64, error) {
|
||||||
|
storage, actualPath, err := op.GetStorageAndActualPath(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, errors.WithMessage(err, "failed get storage")
|
||||||
|
}
|
||||||
|
return op.InternalExtract(ctx, storage, actualPath, args)
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/alist-org/alist/v3/internal/op"
|
"github.com/alist-org/alist/v3/internal/op"
|
||||||
"github.com/alist-org/alist/v3/internal/task"
|
"github.com/alist-org/alist/v3/internal/task"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
// the param named path of functions in this package is a mount path
|
// the param named path of functions in this package is a mount path
|
||||||
|
@ -109,6 +110,46 @@ func PutAsTask(ctx context.Context, dstDirPath string, file model.FileStreamer)
|
||||||
return t, err
|
return t, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ArchiveMeta(ctx context.Context, path string, args model.ArchiveMetaArgs) (*model.ArchiveMetaProvider, error) {
|
||||||
|
meta, err := archiveMeta(ctx, path, args)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("failed get archive meta %s: %+v", path, err)
|
||||||
|
}
|
||||||
|
return meta, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func ArchiveList(ctx context.Context, path string, args model.ArchiveListArgs) ([]model.Obj, error) {
|
||||||
|
objs, err := archiveList(ctx, path, args)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("failed list archive [%s]%s: %+v", path, args.InnerPath, err)
|
||||||
|
}
|
||||||
|
return objs, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func ArchiveDecompress(ctx context.Context, srcObjPath, dstDirPath string, args model.ArchiveDecompressArgs, lazyCache ...bool) (task.TaskExtensionInfo, error) {
|
||||||
|
t, err := archiveDecompress(ctx, srcObjPath, dstDirPath, args, lazyCache...)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("failed decompress [%s]%s: %+v", srcObjPath, args.InnerPath, err)
|
||||||
|
}
|
||||||
|
return t, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func ArchiveDriverExtract(ctx context.Context, path string, args model.ArchiveInnerArgs) (*model.Link, model.Obj, error) {
|
||||||
|
l, obj, err := archiveDriverExtract(ctx, path, args)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("failed extract [%s]%s: %+v", path, args.InnerPath, err)
|
||||||
|
}
|
||||||
|
return l, obj, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func ArchiveInternalExtract(ctx context.Context, path string, args model.ArchiveInnerArgs) (io.ReadCloser, int64, error) {
|
||||||
|
l, obj, err := archiveInternalExtract(ctx, path, args)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("failed extract [%s]%s: %+v", path, args.InnerPath, err)
|
||||||
|
}
|
||||||
|
return l, obj, err
|
||||||
|
}
|
||||||
|
|
||||||
type GetStoragesArgs struct {
|
type GetStoragesArgs struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
package model
|
||||||
|
|
||||||
|
type ObjTree interface {
|
||||||
|
Obj
|
||||||
|
GetChildren() []ObjTree
|
||||||
|
}
|
||||||
|
|
||||||
|
type ObjectTree struct {
|
||||||
|
Object
|
||||||
|
Children []ObjTree
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *ObjectTree) GetChildren() []ObjTree {
|
||||||
|
return t.Children
|
||||||
|
}
|
||||||
|
|
||||||
|
type ArchiveMeta interface {
|
||||||
|
GetComment() string
|
||||||
|
// IsEncrypted means if the content of the archive requires a password to access
|
||||||
|
// GetArchiveMeta should return errs.WrongArchivePassword if the meta-info is also encrypted,
|
||||||
|
// and the provided password is empty.
|
||||||
|
IsEncrypted() bool
|
||||||
|
// GetTree directly returns the full folder structure
|
||||||
|
// returns nil if the folder structure should be acquired by calling driver.ArchiveReader.ListArchive
|
||||||
|
GetTree() []ObjTree
|
||||||
|
}
|
||||||
|
|
||||||
|
type ArchiveMetaInfo struct {
|
||||||
|
Comment string
|
||||||
|
Encrypted bool
|
||||||
|
Tree []ObjTree
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ArchiveMetaInfo) GetComment() string {
|
||||||
|
return m.Comment
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ArchiveMetaInfo) IsEncrypted() bool {
|
||||||
|
return m.Encrypted
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ArchiveMetaInfo) GetTree() []ObjTree {
|
||||||
|
return m.Tree
|
||||||
|
}
|
||||||
|
|
||||||
|
type ArchiveMetaProvider struct {
|
||||||
|
ArchiveMeta
|
||||||
|
DriverProviding bool
|
||||||
|
}
|
|
@ -48,6 +48,33 @@ type FsOtherArgs struct {
|
||||||
Method string `json:"method" form:"method"`
|
Method string `json:"method" form:"method"`
|
||||||
Data interface{} `json:"data" form:"data"`
|
Data interface{} `json:"data" form:"data"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ArchiveArgs struct {
|
||||||
|
Password string
|
||||||
|
LinkArgs
|
||||||
|
}
|
||||||
|
|
||||||
|
type ArchiveInnerArgs struct {
|
||||||
|
ArchiveArgs
|
||||||
|
InnerPath string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ArchiveMetaArgs struct {
|
||||||
|
ArchiveArgs
|
||||||
|
Refresh bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type ArchiveListArgs struct {
|
||||||
|
ArchiveInnerArgs
|
||||||
|
Refresh bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type ArchiveDecompressArgs struct {
|
||||||
|
ArchiveInnerArgs
|
||||||
|
CacheFull bool
|
||||||
|
PutIntoNewDir bool
|
||||||
|
}
|
||||||
|
|
||||||
type RangeReadCloserIF interface {
|
type RangeReadCloserIF interface {
|
||||||
RangeRead(ctx context.Context, httpRange http_range.Range) (io.ReadCloser, error)
|
RangeRead(ctx context.Context, httpRange http_range.Range) (io.ReadCloser, error)
|
||||||
utils.ClosersIF
|
utils.ClosersIF
|
||||||
|
|
|
@ -48,8 +48,11 @@ type FileStreamer interface {
|
||||||
RangeRead(http_range.Range) (io.Reader, error)
|
RangeRead(http_range.Range) (io.Reader, error)
|
||||||
//for a non-seekable Stream, if Read is called, this function won't work
|
//for a non-seekable Stream, if Read is called, this function won't work
|
||||||
CacheFullInTempFile() (File, error)
|
CacheFullInTempFile() (File, error)
|
||||||
|
CacheFullInTempFileAndUpdateProgress(up UpdateProgress) (File, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UpdateProgress func(percentage float64)
|
||||||
|
|
||||||
type URL interface {
|
type URL interface {
|
||||||
URL() string
|
URL() string
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,8 @@ type User struct {
|
||||||
// 9: webdav write
|
// 9: webdav write
|
||||||
// 10: ftp/sftp login and read
|
// 10: ftp/sftp login and read
|
||||||
// 11: ftp/sftp write
|
// 11: ftp/sftp write
|
||||||
|
// 12: can read archives
|
||||||
|
// 13: can decompress archives
|
||||||
Permission int32 `json:"permission"`
|
Permission int32 `json:"permission"`
|
||||||
OtpSecret string `json:"-"`
|
OtpSecret string `json:"-"`
|
||||||
SsoID string `json:"sso_id"` // unique by sso platform
|
SsoID string `json:"sso_id"` // unique by sso platform
|
||||||
|
@ -127,6 +129,14 @@ func (u *User) CanFTPManage() bool {
|
||||||
return (u.Permission>>11)&1 == 1
|
return (u.Permission>>11)&1 == 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *User) CanReadArchives() bool {
|
||||||
|
return (u.Permission>>12)&1 == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) CanDecompress() bool {
|
||||||
|
return (u.Permission>>13)&1 == 1
|
||||||
|
}
|
||||||
|
|
||||||
func (u *User) JoinPath(reqPath string) (string, error) {
|
func (u *User) JoinPath(reqPath string) (string, error) {
|
||||||
return utils.JoinBasePath(u.BasePath, reqPath)
|
return utils.JoinBasePath(u.BasePath, reqPath)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,424 @@
|
||||||
|
package op
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
stderrors "errors"
|
||||||
|
"github.com/alist-org/alist/v3/internal/archive/tool"
|
||||||
|
"github.com/alist-org/alist/v3/internal/stream"
|
||||||
|
"io"
|
||||||
|
stdpath "path"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/Xhofe/go-cache"
|
||||||
|
"github.com/alist-org/alist/v3/internal/driver"
|
||||||
|
"github.com/alist-org/alist/v3/internal/errs"
|
||||||
|
"github.com/alist-org/alist/v3/internal/model"
|
||||||
|
"github.com/alist-org/alist/v3/pkg/singleflight"
|
||||||
|
"github.com/alist-org/alist/v3/pkg/utils"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
var archiveMetaCache = cache.NewMemCache(cache.WithShards[*model.ArchiveMetaProvider](64))
|
||||||
|
var archiveMetaG singleflight.Group[*model.ArchiveMetaProvider]
|
||||||
|
|
||||||
|
func GetArchiveMeta(ctx context.Context, storage driver.Driver, path string, args model.ArchiveMetaArgs) (*model.ArchiveMetaProvider, error) {
|
||||||
|
if storage.Config().CheckStatus && storage.GetStorage().Status != WORK {
|
||||||
|
return nil, errors.Errorf("storage not init: %s", storage.GetStorage().Status)
|
||||||
|
}
|
||||||
|
path = utils.FixAndCleanPath(path)
|
||||||
|
key := Key(storage, path)
|
||||||
|
if !args.Refresh {
|
||||||
|
if meta, ok := archiveMetaCache.Get(key); ok {
|
||||||
|
log.Debugf("use cache when get %s archive meta", path)
|
||||||
|
return meta, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn := func() (*model.ArchiveMetaProvider, error) {
|
||||||
|
_, m, err := getArchiveMeta(ctx, storage, path, args)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed to get %s archive met: %+v", path, err)
|
||||||
|
}
|
||||||
|
if !storage.Config().NoCache {
|
||||||
|
archiveMetaCache.Set(key, m, cache.WithEx[*model.ArchiveMetaProvider](time.Minute*time.Duration(storage.GetStorage().CacheExpiration)))
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
if storage.Config().OnlyLocal {
|
||||||
|
meta, err := fn()
|
||||||
|
return meta, err
|
||||||
|
}
|
||||||
|
meta, err, _ := archiveMetaG.Do(key, fn)
|
||||||
|
return meta, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func getArchiveToolAndStream(ctx context.Context, storage driver.Driver, path string, args model.LinkArgs) (model.Obj, tool.Tool, *stream.SeekableStream, error) {
|
||||||
|
l, obj, err := Link(ctx, storage, path, args)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, errors.WithMessagef(err, "failed get [%s] link", path)
|
||||||
|
}
|
||||||
|
ext := stdpath.Ext(obj.GetName())
|
||||||
|
t, err := tool.GetArchiveTool(ext)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, errors.WithMessagef(err, "failed get [%s] archive tool", ext)
|
||||||
|
}
|
||||||
|
ss, err := stream.NewSeekableStream(stream.FileStream{Ctx: ctx, Obj: obj}, l)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, errors.WithMessagef(err, "failed get [%s] stream", path)
|
||||||
|
}
|
||||||
|
return obj, t, ss, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getArchiveMeta(ctx context.Context, storage driver.Driver, path string, args model.ArchiveMetaArgs) (model.Obj, *model.ArchiveMetaProvider, error) {
|
||||||
|
storageAr, ok := storage.(driver.ArchiveReader)
|
||||||
|
if ok {
|
||||||
|
obj, err := GetUnwrap(ctx, storage, path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, errors.WithMessage(err, "failed to get file")
|
||||||
|
}
|
||||||
|
if obj.IsDir() {
|
||||||
|
return nil, nil, errors.WithStack(errs.NotFile)
|
||||||
|
}
|
||||||
|
meta, err := storageAr.GetArchiveMeta(ctx, obj, args.ArchiveArgs)
|
||||||
|
if !errors.Is(err, errs.NotImplement) {
|
||||||
|
return obj, &model.ArchiveMetaProvider{ArchiveMeta: meta, DriverProviding: true}, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
obj, t, ss, err := getArchiveToolAndStream(ctx, storage, path, args.LinkArgs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if err := ss.Close(); err != nil {
|
||||||
|
log.Errorf("failed to close file streamer, %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
meta, err := t.GetMeta(ss, args.ArchiveArgs)
|
||||||
|
return obj, &model.ArchiveMetaProvider{ArchiveMeta: meta, DriverProviding: false}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var archiveListCache = cache.NewMemCache(cache.WithShards[[]model.Obj](64))
|
||||||
|
var archiveListG singleflight.Group[[]model.Obj]
|
||||||
|
|
||||||
|
func ListArchive(ctx context.Context, storage driver.Driver, path string, args model.ArchiveListArgs) ([]model.Obj, error) {
|
||||||
|
if storage.Config().CheckStatus && storage.GetStorage().Status != WORK {
|
||||||
|
return nil, errors.Errorf("storage not init: %s", storage.GetStorage().Status)
|
||||||
|
}
|
||||||
|
path = utils.FixAndCleanPath(path)
|
||||||
|
metaKey := Key(storage, path)
|
||||||
|
key := stdpath.Join(metaKey, args.InnerPath)
|
||||||
|
if !args.Refresh {
|
||||||
|
if files, ok := archiveListCache.Get(key); ok {
|
||||||
|
log.Debugf("use cache when list archive [%s]%s", path, args.InnerPath)
|
||||||
|
return files, nil
|
||||||
|
}
|
||||||
|
if meta, ok := archiveMetaCache.Get(metaKey); ok {
|
||||||
|
log.Debugf("use meta cache when list archive [%s]%s", path, args.InnerPath)
|
||||||
|
return getChildrenFromArchiveMeta(meta, args.InnerPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
objs, err, _ := archiveListG.Do(key, func() ([]model.Obj, error) {
|
||||||
|
obj, files, err := listArchive(ctx, storage, path, args)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed to list archive [%s]%s: %+v", path, args.InnerPath, err)
|
||||||
|
}
|
||||||
|
// set path
|
||||||
|
for _, f := range files {
|
||||||
|
if s, ok := f.(model.SetPath); ok && f.GetPath() == "" && obj.GetPath() != "" {
|
||||||
|
s.SetPath(stdpath.Join(obj.GetPath(), args.InnerPath, f.GetName()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// warp obj name
|
||||||
|
model.WrapObjsName(files)
|
||||||
|
// sort objs
|
||||||
|
if storage.Config().LocalSort {
|
||||||
|
model.SortFiles(files, storage.GetStorage().OrderBy, storage.GetStorage().OrderDirection)
|
||||||
|
}
|
||||||
|
model.ExtractFolder(files, storage.GetStorage().ExtractFolder)
|
||||||
|
if !storage.Config().NoCache {
|
||||||
|
if len(files) > 0 {
|
||||||
|
log.Debugf("set cache: %s => %+v", key, files)
|
||||||
|
archiveListCache.Set(key, files, cache.WithEx[[]model.Obj](time.Minute*time.Duration(storage.GetStorage().CacheExpiration)))
|
||||||
|
} else {
|
||||||
|
log.Debugf("del cache: %s", key)
|
||||||
|
archiveListCache.Del(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return files, nil
|
||||||
|
})
|
||||||
|
return objs, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func _listArchive(ctx context.Context, storage driver.Driver, path string, args model.ArchiveListArgs) (model.Obj, []model.Obj, error) {
|
||||||
|
storageAr, ok := storage.(driver.ArchiveReader)
|
||||||
|
if ok {
|
||||||
|
obj, err := GetUnwrap(ctx, storage, path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, errors.WithMessage(err, "failed to get file")
|
||||||
|
}
|
||||||
|
if obj.IsDir() {
|
||||||
|
return nil, nil, errors.WithStack(errs.NotFile)
|
||||||
|
}
|
||||||
|
files, err := storageAr.ListArchive(ctx, obj, args.ArchiveInnerArgs)
|
||||||
|
if !errors.Is(err, errs.NotImplement) {
|
||||||
|
return obj, files, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
obj, t, ss, err := getArchiveToolAndStream(ctx, storage, path, args.LinkArgs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if err := ss.Close(); err != nil {
|
||||||
|
log.Errorf("failed to close file streamer, %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
files, err := t.List(ss, args.ArchiveInnerArgs)
|
||||||
|
return obj, files, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func listArchive(ctx context.Context, storage driver.Driver, path string, args model.ArchiveListArgs) (model.Obj, []model.Obj, error) {
|
||||||
|
obj, files, err := _listArchive(ctx, storage, path, args)
|
||||||
|
if errors.Is(err, errs.NotSupport) {
|
||||||
|
var meta model.ArchiveMeta
|
||||||
|
meta, err = GetArchiveMeta(ctx, storage, path, model.ArchiveMetaArgs{
|
||||||
|
ArchiveArgs: args.ArchiveArgs,
|
||||||
|
Refresh: args.Refresh,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
files, err = getChildrenFromArchiveMeta(meta, args.InnerPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err == nil && obj == nil {
|
||||||
|
obj, err = GetUnwrap(ctx, storage, path)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return obj, files, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func getChildrenFromArchiveMeta(meta model.ArchiveMeta, innerPath string) ([]model.Obj, error) {
|
||||||
|
obj := meta.GetTree()
|
||||||
|
if obj == nil {
|
||||||
|
return nil, errors.WithStack(errs.NotImplement)
|
||||||
|
}
|
||||||
|
dirs := splitPath(innerPath)
|
||||||
|
for _, dir := range dirs {
|
||||||
|
var next model.ObjTree
|
||||||
|
for _, c := range obj {
|
||||||
|
if c.GetName() == dir {
|
||||||
|
next = c
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if next == nil {
|
||||||
|
return nil, errors.WithStack(errs.ObjectNotFound)
|
||||||
|
}
|
||||||
|
if !next.IsDir() || next.GetChildren() == nil {
|
||||||
|
return nil, errors.WithStack(errs.NotFolder)
|
||||||
|
}
|
||||||
|
obj = next.GetChildren()
|
||||||
|
}
|
||||||
|
return utils.SliceConvert(obj, func(src model.ObjTree) (model.Obj, error) {
|
||||||
|
return src, nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func splitPath(path string) []string {
|
||||||
|
var parts []string
|
||||||
|
for {
|
||||||
|
dir, file := stdpath.Split(path)
|
||||||
|
if file == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
parts = append([]string{file}, parts...)
|
||||||
|
path = strings.TrimSuffix(dir, "/")
|
||||||
|
}
|
||||||
|
return parts
|
||||||
|
}
|
||||||
|
|
||||||
|
func ArchiveGet(ctx context.Context, storage driver.Driver, path string, args model.ArchiveListArgs) (model.Obj, model.Obj, error) {
|
||||||
|
if storage.Config().CheckStatus && storage.GetStorage().Status != WORK {
|
||||||
|
return nil, nil, errors.Errorf("storage not init: %s", storage.GetStorage().Status)
|
||||||
|
}
|
||||||
|
path = utils.FixAndCleanPath(path)
|
||||||
|
af, err := GetUnwrap(ctx, storage, path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, errors.WithMessage(err, "failed to get file")
|
||||||
|
}
|
||||||
|
if af.IsDir() {
|
||||||
|
return nil, nil, errors.WithStack(errs.NotFile)
|
||||||
|
}
|
||||||
|
if g, ok := storage.(driver.ArchiveGetter); ok {
|
||||||
|
obj, err := g.ArchiveGet(ctx, af, args.ArchiveInnerArgs)
|
||||||
|
if err == nil {
|
||||||
|
return af, model.WrapObjName(obj), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if utils.PathEqual(args.InnerPath, "/") {
|
||||||
|
return af, &model.ObjWrapName{
|
||||||
|
Name: RootName,
|
||||||
|
Obj: &model.Object{
|
||||||
|
Name: af.GetName(),
|
||||||
|
Path: af.GetPath(),
|
||||||
|
ID: af.GetID(),
|
||||||
|
Size: af.GetSize(),
|
||||||
|
Modified: af.ModTime(),
|
||||||
|
IsFolder: true,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
innerDir, name := stdpath.Split(args.InnerPath)
|
||||||
|
args.InnerPath = strings.TrimSuffix(innerDir, "/")
|
||||||
|
files, err := ListArchive(ctx, storage, path, args)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, errors.WithMessage(err, "failed get parent list")
|
||||||
|
}
|
||||||
|
for _, f := range files {
|
||||||
|
if f.GetName() == name {
|
||||||
|
return af, f, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, nil, errors.WithStack(errs.ObjectNotFound)
|
||||||
|
}
|
||||||
|
|
||||||
|
type extractLink struct {
|
||||||
|
Link *model.Link
|
||||||
|
Obj model.Obj
|
||||||
|
}
|
||||||
|
|
||||||
|
var extractCache = cache.NewMemCache(cache.WithShards[*extractLink](16))
|
||||||
|
var extractG singleflight.Group[*extractLink]
|
||||||
|
|
||||||
|
func DriverExtract(ctx context.Context, storage driver.Driver, path string, args model.ArchiveInnerArgs) (*model.Link, model.Obj, error) {
|
||||||
|
if storage.Config().CheckStatus && storage.GetStorage().Status != WORK {
|
||||||
|
return nil, nil, errors.Errorf("storage not init: %s", storage.GetStorage().Status)
|
||||||
|
}
|
||||||
|
key := stdpath.Join(Key(storage, path), args.InnerPath)
|
||||||
|
if link, ok := extractCache.Get(key); ok {
|
||||||
|
return link.Link, link.Obj, nil
|
||||||
|
} else if link, ok := extractCache.Get(key + ":" + args.IP); ok {
|
||||||
|
return link.Link, link.Obj, nil
|
||||||
|
}
|
||||||
|
fn := func() (*extractLink, error) {
|
||||||
|
link, err := driverExtract(ctx, storage, path, args)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed extract archive")
|
||||||
|
}
|
||||||
|
if link.Link.Expiration != nil {
|
||||||
|
if link.Link.IPCacheKey {
|
||||||
|
key = key + ":" + args.IP
|
||||||
|
}
|
||||||
|
extractCache.Set(key, link, cache.WithEx[*extractLink](*link.Link.Expiration))
|
||||||
|
}
|
||||||
|
return link, nil
|
||||||
|
}
|
||||||
|
if storage.Config().OnlyLocal {
|
||||||
|
link, err := fn()
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return link.Link, link.Obj, nil
|
||||||
|
}
|
||||||
|
link, err, _ := extractG.Do(key, fn)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return link.Link, link.Obj, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func driverExtract(ctx context.Context, storage driver.Driver, path string, args model.ArchiveInnerArgs) (*extractLink, error) {
|
||||||
|
storageAr, ok := storage.(driver.ArchiveReader)
|
||||||
|
if !ok {
|
||||||
|
return nil, errs.DriverExtractNotSupported
|
||||||
|
}
|
||||||
|
archiveFile, extracted, err := ArchiveGet(ctx, storage, path, model.ArchiveListArgs{
|
||||||
|
ArchiveInnerArgs: args,
|
||||||
|
Refresh: false,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithMessage(err, "failed to get file")
|
||||||
|
}
|
||||||
|
if extracted.IsDir() {
|
||||||
|
return nil, errors.WithStack(errs.NotFile)
|
||||||
|
}
|
||||||
|
link, err := storageAr.Extract(ctx, archiveFile, args)
|
||||||
|
return &extractLink{Link: link, Obj: extracted}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
type streamWithParent struct {
|
||||||
|
rc io.ReadCloser
|
||||||
|
parent *stream.SeekableStream
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *streamWithParent) Read(p []byte) (int, error) {
|
||||||
|
return s.rc.Read(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *streamWithParent) Close() error {
|
||||||
|
err1 := s.rc.Close()
|
||||||
|
err2 := s.parent.Close()
|
||||||
|
return stderrors.Join(err1, err2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func InternalExtract(ctx context.Context, storage driver.Driver, path string, args model.ArchiveInnerArgs) (io.ReadCloser, int64, error) {
|
||||||
|
_, t, ss, err := getArchiveToolAndStream(ctx, storage, path, args.LinkArgs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
rc, size, err := t.Extract(ss, args)
|
||||||
|
if err != nil {
|
||||||
|
if e := ss.Close(); e != nil {
|
||||||
|
log.Errorf("failed to close file streamer, %v", e)
|
||||||
|
}
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
return &streamWithParent{rc: rc, parent: ss}, size, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ArchiveDecompress(ctx context.Context, storage driver.Driver, srcPath, dstDirPath string, args model.ArchiveDecompressArgs, lazyCache ...bool) error {
|
||||||
|
if storage.Config().CheckStatus && storage.GetStorage().Status != WORK {
|
||||||
|
return errors.Errorf("storage not init: %s", storage.GetStorage().Status)
|
||||||
|
}
|
||||||
|
srcPath = utils.FixAndCleanPath(srcPath)
|
||||||
|
dstDirPath = utils.FixAndCleanPath(dstDirPath)
|
||||||
|
srcObj, err := GetUnwrap(ctx, storage, srcPath)
|
||||||
|
if err != nil {
|
||||||
|
return errors.WithMessage(err, "failed to get src object")
|
||||||
|
}
|
||||||
|
dstDir, err := GetUnwrap(ctx, storage, dstDirPath)
|
||||||
|
if err != nil {
|
||||||
|
return errors.WithMessage(err, "failed to get dst dir")
|
||||||
|
}
|
||||||
|
|
||||||
|
switch s := storage.(type) {
|
||||||
|
case driver.ArchiveDecompressResult:
|
||||||
|
var newObjs []model.Obj
|
||||||
|
newObjs, err = s.ArchiveDecompress(ctx, srcObj, dstDir, args)
|
||||||
|
if err == nil {
|
||||||
|
if newObjs != nil && len(newObjs) > 0 {
|
||||||
|
for _, newObj := range newObjs {
|
||||||
|
addCacheObj(storage, dstDirPath, model.WrapObjName(newObj))
|
||||||
|
}
|
||||||
|
} else if !utils.IsBool(lazyCache...) {
|
||||||
|
ClearCache(storage, dstDirPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case driver.ArchiveDecompress:
|
||||||
|
err = s.ArchiveDecompress(ctx, srcObj, dstDir, args)
|
||||||
|
if err == nil && !utils.IsBool(lazyCache...) {
|
||||||
|
ClearCache(storage, dstDirPath)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return errs.NotImplement
|
||||||
|
}
|
||||||
|
return errors.WithStack(err)
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"math"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/alist-org/alist/v3/internal/errs"
|
"github.com/alist-org/alist/v3/internal/errs"
|
||||||
|
@ -60,6 +61,8 @@ func (f *FileStream) Close() error {
|
||||||
err2 = os.RemoveAll(f.tmpFile.Name())
|
err2 = os.RemoveAll(f.tmpFile.Name())
|
||||||
if err2 != nil {
|
if err2 != nil {
|
||||||
err2 = errs.NewErr(err2, "failed to remove tmpFile [%s]", f.tmpFile.Name())
|
err2 = errs.NewErr(err2, "failed to remove tmpFile [%s]", f.tmpFile.Name())
|
||||||
|
} else {
|
||||||
|
f.tmpFile = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,6 +95,26 @@ func (f *FileStream) CacheFullInTempFile() (model.File, error) {
|
||||||
return f.tmpFile, nil
|
return f.tmpFile, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *FileStream) CacheFullInTempFileAndUpdateProgress(up model.UpdateProgress) (model.File, error) {
|
||||||
|
if f.tmpFile != nil {
|
||||||
|
return f.tmpFile, nil
|
||||||
|
}
|
||||||
|
if file, ok := f.Reader.(model.File); ok {
|
||||||
|
return file, nil
|
||||||
|
}
|
||||||
|
tmpF, err := utils.CreateTempFile(&ReaderUpdatingProgress{
|
||||||
|
Reader: f,
|
||||||
|
UpdateProgress: up,
|
||||||
|
}, f.GetSize())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
f.Add(tmpF)
|
||||||
|
f.tmpFile = tmpF
|
||||||
|
f.Reader = tmpF
|
||||||
|
return f.tmpFile, nil
|
||||||
|
}
|
||||||
|
|
||||||
const InMemoryBufMaxSize = 10 // Megabytes
|
const InMemoryBufMaxSize = 10 // Megabytes
|
||||||
const InMemoryBufMaxSizeBytes = InMemoryBufMaxSize * 1024 * 1024
|
const InMemoryBufMaxSizeBytes = InMemoryBufMaxSize * 1024 * 1024
|
||||||
|
|
||||||
|
@ -247,7 +270,202 @@ func (ss *SeekableStream) CacheFullInTempFile() (model.File, error) {
|
||||||
return ss.tmpFile, nil
|
return ss.tmpFile, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ss *SeekableStream) CacheFullInTempFileAndUpdateProgress(up model.UpdateProgress) (model.File, error) {
|
||||||
|
if ss.tmpFile != nil {
|
||||||
|
return ss.tmpFile, nil
|
||||||
|
}
|
||||||
|
if ss.mFile != nil {
|
||||||
|
return ss.mFile, nil
|
||||||
|
}
|
||||||
|
tmpF, err := utils.CreateTempFile(&ReaderUpdatingProgress{
|
||||||
|
Reader: ss,
|
||||||
|
UpdateProgress: up,
|
||||||
|
}, ss.GetSize())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ss.Add(tmpF)
|
||||||
|
ss.tmpFile = tmpF
|
||||||
|
ss.Reader = tmpF
|
||||||
|
return ss.tmpFile, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (f *FileStream) SetTmpFile(r *os.File) {
|
func (f *FileStream) SetTmpFile(r *os.File) {
|
||||||
f.Reader = r
|
f.Reader = r
|
||||||
f.tmpFile = r
|
f.tmpFile = r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ReaderWithSize interface {
|
||||||
|
io.Reader
|
||||||
|
GetSize() int64
|
||||||
|
}
|
||||||
|
|
||||||
|
type SimpleReaderWithSize struct {
|
||||||
|
io.Reader
|
||||||
|
Size int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *SimpleReaderWithSize) GetSize() int64 {
|
||||||
|
return r.Size
|
||||||
|
}
|
||||||
|
|
||||||
|
type ReaderUpdatingProgress struct {
|
||||||
|
Reader ReaderWithSize
|
||||||
|
model.UpdateProgress
|
||||||
|
offset int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ReaderUpdatingProgress) Read(p []byte) (n int, err error) {
|
||||||
|
n, err = r.Reader.Read(p)
|
||||||
|
r.offset += n
|
||||||
|
r.UpdateProgress(math.Min(100.0, float64(r.offset)/float64(r.Reader.GetSize())*100.0))
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
type SStreamReadAtSeeker interface {
|
||||||
|
model.File
|
||||||
|
GetRawStream() *SeekableStream
|
||||||
|
}
|
||||||
|
|
||||||
|
type readerCur struct {
|
||||||
|
reader io.Reader
|
||||||
|
cur int64
|
||||||
|
}
|
||||||
|
|
||||||
|
type RangeReadReadAtSeeker struct {
|
||||||
|
ss *SeekableStream
|
||||||
|
masterOff int64
|
||||||
|
readers []*readerCur
|
||||||
|
}
|
||||||
|
|
||||||
|
type FileReadAtSeeker struct {
|
||||||
|
ss *SeekableStream
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewReadAtSeeker(ss *SeekableStream, offset int64, forceRange ...bool) (SStreamReadAtSeeker, error) {
|
||||||
|
if ss.mFile != nil {
|
||||||
|
_, err := ss.mFile.Seek(offset, io.SeekStart)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &FileReadAtSeeker{ss: ss}, nil
|
||||||
|
}
|
||||||
|
var r io.Reader
|
||||||
|
var err error
|
||||||
|
if offset != 0 || utils.IsBool(forceRange...) {
|
||||||
|
if offset < 0 || offset > ss.GetSize() {
|
||||||
|
return nil, errors.New("offset out of range")
|
||||||
|
}
|
||||||
|
r, err = ss.RangeRead(http_range.Range{Start: offset, Length: -1})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if rc, ok := r.(io.Closer); ok {
|
||||||
|
ss.Closers.Add(rc)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
r = ss
|
||||||
|
}
|
||||||
|
return &RangeReadReadAtSeeker{
|
||||||
|
ss: ss,
|
||||||
|
masterOff: offset,
|
||||||
|
readers: []*readerCur{{reader: r, cur: offset}},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RangeReadReadAtSeeker) GetRawStream() *SeekableStream {
|
||||||
|
return r.ss
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RangeReadReadAtSeeker) getReaderAtOffset(off int64) (*readerCur, error) {
|
||||||
|
for _, reader := range r.readers {
|
||||||
|
if reader.cur == off {
|
||||||
|
return reader, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reader, err := r.ss.RangeRead(http_range.Range{Start: off, Length: -1})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if c, ok := reader.(io.Closer); ok {
|
||||||
|
r.ss.Closers.Add(c)
|
||||||
|
}
|
||||||
|
rc := &readerCur{reader: reader, cur: off}
|
||||||
|
r.readers = append(r.readers, rc)
|
||||||
|
return rc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RangeReadReadAtSeeker) ReadAt(p []byte, off int64) (int, error) {
|
||||||
|
rc, err := r.getReaderAtOffset(off)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
num := 0
|
||||||
|
for num < len(p) {
|
||||||
|
n, err := rc.reader.Read(p[num:])
|
||||||
|
rc.cur += int64(n)
|
||||||
|
num += n
|
||||||
|
if err != nil {
|
||||||
|
return num, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return num, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RangeReadReadAtSeeker) Seek(offset int64, whence int) (int64, error) {
|
||||||
|
switch whence {
|
||||||
|
case io.SeekStart:
|
||||||
|
case io.SeekCurrent:
|
||||||
|
if offset == 0 {
|
||||||
|
return r.masterOff, nil
|
||||||
|
}
|
||||||
|
offset += r.masterOff
|
||||||
|
case io.SeekEnd:
|
||||||
|
offset += r.ss.GetSize()
|
||||||
|
default:
|
||||||
|
return 0, errs.NotSupport
|
||||||
|
}
|
||||||
|
if offset < 0 {
|
||||||
|
return r.masterOff, errors.New("invalid seek: negative position")
|
||||||
|
}
|
||||||
|
if offset > r.ss.GetSize() {
|
||||||
|
return r.masterOff, io.EOF
|
||||||
|
}
|
||||||
|
r.masterOff = offset
|
||||||
|
return offset, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RangeReadReadAtSeeker) Read(p []byte) (n int, err error) {
|
||||||
|
rc, err := r.getReaderAtOffset(r.masterOff)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
n, err = rc.reader.Read(p)
|
||||||
|
rc.cur += int64(n)
|
||||||
|
r.masterOff += int64(n)
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RangeReadReadAtSeeker) Close() error {
|
||||||
|
return r.ss.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileReadAtSeeker) GetRawStream() *SeekableStream {
|
||||||
|
return f.ss
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileReadAtSeeker) Read(p []byte) (n int, err error) {
|
||||||
|
return f.ss.mFile.Read(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileReadAtSeeker) ReadAt(p []byte, off int64) (n int, err error) {
|
||||||
|
return f.ss.mFile.ReadAt(p, off)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileReadAtSeeker) Seek(offset int64, whence int) (int64, error) {
|
||||||
|
return f.ss.mFile.Seek(offset, whence)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileReadAtSeeker) Close() error {
|
||||||
|
return f.ss.Close()
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
package task
|
||||||
|
|
||||||
|
import "github.com/xhofe/tache"
|
||||||
|
|
||||||
|
type Manager[T tache.Task] interface {
|
||||||
|
Add(task T)
|
||||||
|
Cancel(id string)
|
||||||
|
CancelAll()
|
||||||
|
CancelByCondition(condition func(task T) bool)
|
||||||
|
GetAll() []T
|
||||||
|
GetByID(id string) (T, bool)
|
||||||
|
GetByState(state ...tache.State) []T
|
||||||
|
GetByCondition(condition func(task T) bool) []T
|
||||||
|
Remove(id string)
|
||||||
|
RemoveAll()
|
||||||
|
RemoveByState(state ...tache.State)
|
||||||
|
RemoveByCondition(condition func(task T) bool)
|
||||||
|
Retry(id string)
|
||||||
|
RetryAllFailed()
|
||||||
|
}
|
|
@ -8,10 +8,8 @@ import (
|
||||||
"github.com/alist-org/alist/v3/internal/model"
|
"github.com/alist-org/alist/v3/internal/model"
|
||||||
"github.com/alist-org/alist/v3/internal/op"
|
"github.com/alist-org/alist/v3/internal/op"
|
||||||
"github.com/alist-org/alist/v3/internal/stream"
|
"github.com/alist-org/alist/v3/internal/stream"
|
||||||
"github.com/alist-org/alist/v3/pkg/http_range"
|
|
||||||
"github.com/alist-org/alist/v3/server/common"
|
"github.com/alist-org/alist/v3/server/common"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"io"
|
|
||||||
fs2 "io/fs"
|
fs2 "io/fs"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
@ -20,9 +18,7 @@ import (
|
||||||
|
|
||||||
type FileDownloadProxy struct {
|
type FileDownloadProxy struct {
|
||||||
ftpserver.FileTransfer
|
ftpserver.FileTransfer
|
||||||
ss *stream.SeekableStream
|
reader stream.SStreamReadAtSeeker
|
||||||
reader io.Reader
|
|
||||||
cur int64
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func OpenDownload(ctx context.Context, reqPath string, offset int64) (*FileDownloadProxy, error) {
|
func OpenDownload(ctx context.Context, reqPath string, offset int64) (*FileDownloadProxy, error) {
|
||||||
|
@ -55,22 +51,16 @@ func OpenDownload(ctx context.Context, reqPath string, offset int64) (*FileDownl
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var reader io.Reader
|
reader, err := stream.NewReadAtSeeker(ss, offset)
|
||||||
if offset != 0 {
|
if err != nil {
|
||||||
reader, err = ss.RangeRead(http_range.Range{Start: offset, Length: -1})
|
_ = ss.Close()
|
||||||
if err != nil {
|
return nil, err
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
reader = ss
|
|
||||||
}
|
}
|
||||||
return &FileDownloadProxy{ss: ss, reader: reader}, nil
|
return &FileDownloadProxy{reader: reader}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FileDownloadProxy) Read(p []byte) (n int, err error) {
|
func (f *FileDownloadProxy) Read(p []byte) (n int, err error) {
|
||||||
n, err = f.reader.Read(p)
|
return f.reader.Read(p)
|
||||||
f.cur += int64(n)
|
|
||||||
return n, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FileDownloadProxy) Write(p []byte) (n int, err error) {
|
func (f *FileDownloadProxy) Write(p []byte) (n int, err error) {
|
||||||
|
@ -78,32 +68,11 @@ func (f *FileDownloadProxy) Write(p []byte) (n int, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FileDownloadProxy) Seek(offset int64, whence int) (int64, error) {
|
func (f *FileDownloadProxy) Seek(offset int64, whence int) (int64, error) {
|
||||||
switch whence {
|
return f.reader.Seek(offset, whence)
|
||||||
case io.SeekStart:
|
|
||||||
break
|
|
||||||
case io.SeekCurrent:
|
|
||||||
offset += f.cur
|
|
||||||
break
|
|
||||||
case io.SeekEnd:
|
|
||||||
offset += f.ss.GetSize()
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
return 0, errs.NotSupport
|
|
||||||
}
|
|
||||||
if offset < 0 {
|
|
||||||
return 0, errors.New("Seek: negative position")
|
|
||||||
}
|
|
||||||
reader, err := f.ss.RangeRead(http_range.Range{Start: offset, Length: -1})
|
|
||||||
if err != nil {
|
|
||||||
return f.cur, err
|
|
||||||
}
|
|
||||||
f.cur = offset
|
|
||||||
f.reader = reader
|
|
||||||
return offset, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FileDownloadProxy) Close() error {
|
func (f *FileDownloadProxy) Close() error {
|
||||||
return f.ss.Close()
|
return f.reader.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
type OsFileInfoAdapter struct {
|
type OsFileInfoAdapter struct {
|
||||||
|
|
|
@ -0,0 +1,381 @@
|
||||||
|
package handles
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/alist-org/alist/v3/internal/archive/tool"
|
||||||
|
"github.com/alist-org/alist/v3/internal/conf"
|
||||||
|
"github.com/alist-org/alist/v3/internal/errs"
|
||||||
|
"github.com/alist-org/alist/v3/internal/fs"
|
||||||
|
"github.com/alist-org/alist/v3/internal/model"
|
||||||
|
"github.com/alist-org/alist/v3/internal/op"
|
||||||
|
"github.com/alist-org/alist/v3/internal/setting"
|
||||||
|
"github.com/alist-org/alist/v3/internal/sign"
|
||||||
|
"github.com/alist-org/alist/v3/pkg/utils"
|
||||||
|
"github.com/alist-org/alist/v3/server/common"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"mime"
|
||||||
|
stdpath "path"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ArchiveMetaReq struct {
|
||||||
|
Path string `json:"path" form:"path"`
|
||||||
|
Password string `json:"password" form:"password"`
|
||||||
|
Refresh bool `json:"refresh" form:"refresh"`
|
||||||
|
ArchivePass string `json:"archive_pass" form:"archive_pass"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ArchiveMetaResp struct {
|
||||||
|
Comment string `json:"comment"`
|
||||||
|
IsEncrypted bool `json:"encrypted"`
|
||||||
|
Content []ArchiveContentResp `json:"content"`
|
||||||
|
RawURL string `json:"raw_url"`
|
||||||
|
Sign string `json:"sign"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ArchiveContentResp struct {
|
||||||
|
ObjResp
|
||||||
|
Children []ArchiveContentResp `json:"children,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func toObjsRespWithoutSignAndThumb(obj model.Obj) ObjResp {
|
||||||
|
return ObjResp{
|
||||||
|
Name: obj.GetName(),
|
||||||
|
Size: obj.GetSize(),
|
||||||
|
IsDir: obj.IsDir(),
|
||||||
|
Modified: obj.ModTime(),
|
||||||
|
Created: obj.CreateTime(),
|
||||||
|
HashInfoStr: obj.GetHash().String(),
|
||||||
|
HashInfo: obj.GetHash().Export(),
|
||||||
|
Sign: "",
|
||||||
|
Thumb: "",
|
||||||
|
Type: utils.GetObjType(obj.GetName(), obj.IsDir()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func toContentResp(objs []model.ObjTree) []ArchiveContentResp {
|
||||||
|
if objs == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
ret, _ := utils.SliceConvert(objs, func(src model.ObjTree) (ArchiveContentResp, error) {
|
||||||
|
return ArchiveContentResp{
|
||||||
|
ObjResp: toObjsRespWithoutSignAndThumb(src),
|
||||||
|
Children: toContentResp(src.GetChildren()),
|
||||||
|
}, nil
|
||||||
|
})
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func FsArchiveMeta(c *gin.Context) {
|
||||||
|
var req ArchiveMetaReq
|
||||||
|
if err := c.ShouldBind(&req); err != nil {
|
||||||
|
common.ErrorResp(c, err, 400)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
user := c.MustGet("user").(*model.User)
|
||||||
|
if !user.CanReadArchives() {
|
||||||
|
common.ErrorResp(c, errs.PermissionDenied, 403)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
reqPath, err := user.JoinPath(req.Path)
|
||||||
|
if err != nil {
|
||||||
|
common.ErrorResp(c, err, 403)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
meta, err := op.GetNearestMeta(reqPath)
|
||||||
|
if err != nil {
|
||||||
|
if !errors.Is(errors.Cause(err), errs.MetaNotFound) {
|
||||||
|
common.ErrorResp(c, err, 500, true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.Set("meta", meta)
|
||||||
|
if !common.CanAccess(user, meta, reqPath, req.Password) {
|
||||||
|
common.ErrorStrResp(c, "password is incorrect or you have no permission", 403)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
archiveArgs := model.ArchiveArgs{
|
||||||
|
LinkArgs: model.LinkArgs{
|
||||||
|
Header: c.Request.Header,
|
||||||
|
Type: c.Query("type"),
|
||||||
|
HttpReq: c.Request,
|
||||||
|
},
|
||||||
|
Password: req.ArchivePass,
|
||||||
|
}
|
||||||
|
ret, err := fs.ArchiveMeta(c, reqPath, model.ArchiveMetaArgs{
|
||||||
|
ArchiveArgs: archiveArgs,
|
||||||
|
Refresh: req.Refresh,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, errs.WrongArchivePassword) {
|
||||||
|
common.ErrorResp(c, err, 202)
|
||||||
|
} else {
|
||||||
|
common.ErrorResp(c, err, 500)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s := ""
|
||||||
|
if isEncrypt(meta, reqPath) || setting.GetBool(conf.SignAll) {
|
||||||
|
s = sign.Sign(reqPath)
|
||||||
|
}
|
||||||
|
api := "/ae"
|
||||||
|
if ret.DriverProviding {
|
||||||
|
api = "/ad"
|
||||||
|
}
|
||||||
|
common.SuccessResp(c, ArchiveMetaResp{
|
||||||
|
Comment: ret.GetComment(),
|
||||||
|
IsEncrypted: ret.IsEncrypted(),
|
||||||
|
Content: toContentResp(ret.GetTree()),
|
||||||
|
RawURL: fmt.Sprintf("%s%s%s", common.GetApiUrl(c.Request), api, utils.EncodePath(reqPath, true)),
|
||||||
|
Sign: s,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type ArchiveListReq struct {
|
||||||
|
ArchiveMetaReq
|
||||||
|
model.PageReq
|
||||||
|
InnerPath string `json:"inner_path" form:"inner_path"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ArchiveListResp struct {
|
||||||
|
Content []ObjResp `json:"content"`
|
||||||
|
Total int64 `json:"total"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func FsArchiveList(c *gin.Context) {
|
||||||
|
var req ArchiveListReq
|
||||||
|
if err := c.ShouldBind(&req); err != nil {
|
||||||
|
common.ErrorResp(c, err, 400)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req.Validate()
|
||||||
|
user := c.MustGet("user").(*model.User)
|
||||||
|
if !user.CanReadArchives() {
|
||||||
|
common.ErrorResp(c, errs.PermissionDenied, 403)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
reqPath, err := user.JoinPath(req.Path)
|
||||||
|
if err != nil {
|
||||||
|
common.ErrorResp(c, err, 403)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
meta, err := op.GetNearestMeta(reqPath)
|
||||||
|
if err != nil {
|
||||||
|
if !errors.Is(errors.Cause(err), errs.MetaNotFound) {
|
||||||
|
common.ErrorResp(c, err, 500, true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.Set("meta", meta)
|
||||||
|
if !common.CanAccess(user, meta, reqPath, req.Password) {
|
||||||
|
common.ErrorStrResp(c, "password is incorrect or you have no permission", 403)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
objs, err := fs.ArchiveList(c, reqPath, model.ArchiveListArgs{
|
||||||
|
ArchiveInnerArgs: model.ArchiveInnerArgs{
|
||||||
|
ArchiveArgs: model.ArchiveArgs{
|
||||||
|
LinkArgs: model.LinkArgs{
|
||||||
|
Header: c.Request.Header,
|
||||||
|
Type: c.Query("type"),
|
||||||
|
HttpReq: c.Request,
|
||||||
|
},
|
||||||
|
Password: req.ArchivePass,
|
||||||
|
},
|
||||||
|
InnerPath: utils.FixAndCleanPath(req.InnerPath),
|
||||||
|
},
|
||||||
|
Refresh: req.Refresh,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, errs.WrongArchivePassword) {
|
||||||
|
common.ErrorResp(c, err, 202)
|
||||||
|
} else {
|
||||||
|
common.ErrorResp(c, err, 500)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
total, objs := pagination(objs, &req.PageReq)
|
||||||
|
ret, _ := utils.SliceConvert(objs, func(src model.Obj) (ObjResp, error) {
|
||||||
|
return toObjsRespWithoutSignAndThumb(src), nil
|
||||||
|
})
|
||||||
|
common.SuccessResp(c, ArchiveListResp{
|
||||||
|
Content: ret,
|
||||||
|
Total: int64(total),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type ArchiveDecompressReq struct {
|
||||||
|
SrcDir string `json:"src_dir" form:"src_dir"`
|
||||||
|
DstDir string `json:"dst_dir" form:"dst_dir"`
|
||||||
|
Name string `json:"name" form:"name"`
|
||||||
|
ArchivePass string `json:"archive_pass" form:"archive_pass"`
|
||||||
|
InnerPath string `json:"inner_path" form:"inner_path"`
|
||||||
|
CacheFull bool `json:"cache_full" form:"cache_full"`
|
||||||
|
PutIntoNewDir bool `json:"put_into_new_dir" form:"put_into_new_dir"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func FsArchiveDecompress(c *gin.Context) {
|
||||||
|
var req ArchiveDecompressReq
|
||||||
|
if err := c.ShouldBind(&req); err != nil {
|
||||||
|
common.ErrorResp(c, err, 400)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
user := c.MustGet("user").(*model.User)
|
||||||
|
if !user.CanDecompress() {
|
||||||
|
common.ErrorResp(c, errs.PermissionDenied, 403)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
srcPath, err := user.JoinPath(stdpath.Join(req.SrcDir, req.Name))
|
||||||
|
if err != nil {
|
||||||
|
common.ErrorResp(c, err, 403)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dstDir, err := user.JoinPath(req.DstDir)
|
||||||
|
if err != nil {
|
||||||
|
common.ErrorResp(c, err, 403)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t, err := fs.ArchiveDecompress(c, srcPath, dstDir, model.ArchiveDecompressArgs{
|
||||||
|
ArchiveInnerArgs: model.ArchiveInnerArgs{
|
||||||
|
ArchiveArgs: model.ArchiveArgs{
|
||||||
|
LinkArgs: model.LinkArgs{
|
||||||
|
Header: c.Request.Header,
|
||||||
|
Type: c.Query("type"),
|
||||||
|
HttpReq: c.Request,
|
||||||
|
},
|
||||||
|
Password: req.ArchivePass,
|
||||||
|
},
|
||||||
|
InnerPath: utils.FixAndCleanPath(req.InnerPath),
|
||||||
|
},
|
||||||
|
CacheFull: req.CacheFull,
|
||||||
|
PutIntoNewDir: req.PutIntoNewDir,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, errs.WrongArchivePassword) {
|
||||||
|
common.ErrorResp(c, err, 202)
|
||||||
|
} else {
|
||||||
|
common.ErrorResp(c, err, 500)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
common.SuccessResp(c, gin.H{
|
||||||
|
"task": getTaskInfo(t),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func ArchiveDown(c *gin.Context) {
|
||||||
|
archiveRawPath := c.MustGet("path").(string)
|
||||||
|
innerPath := utils.FixAndCleanPath(c.Query("inner"))
|
||||||
|
password := c.Query("pass")
|
||||||
|
filename := stdpath.Base(innerPath)
|
||||||
|
storage, err := fs.GetStorage(archiveRawPath, &fs.GetStoragesArgs{})
|
||||||
|
if err != nil {
|
||||||
|
common.ErrorResp(c, err, 500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if common.ShouldProxy(storage, filename) {
|
||||||
|
ArchiveProxy(c)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
link, _, err := fs.ArchiveDriverExtract(c, archiveRawPath, model.ArchiveInnerArgs{
|
||||||
|
ArchiveArgs: model.ArchiveArgs{
|
||||||
|
LinkArgs: model.LinkArgs{
|
||||||
|
IP: c.ClientIP(),
|
||||||
|
Header: c.Request.Header,
|
||||||
|
Type: c.Query("type"),
|
||||||
|
HttpReq: c.Request,
|
||||||
|
},
|
||||||
|
Password: password,
|
||||||
|
},
|
||||||
|
InnerPath: innerPath,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
common.ErrorResp(c, err, 500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
down(c, link)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ArchiveProxy(c *gin.Context) {
|
||||||
|
archiveRawPath := c.MustGet("path").(string)
|
||||||
|
innerPath := utils.FixAndCleanPath(c.Query("inner"))
|
||||||
|
password := c.Query("pass")
|
||||||
|
filename := stdpath.Base(innerPath)
|
||||||
|
storage, err := fs.GetStorage(archiveRawPath, &fs.GetStoragesArgs{})
|
||||||
|
if err != nil {
|
||||||
|
common.ErrorResp(c, err, 500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if canProxy(storage, filename) {
|
||||||
|
// TODO: Support external download proxy URL
|
||||||
|
link, file, err := fs.ArchiveDriverExtract(c, archiveRawPath, model.ArchiveInnerArgs{
|
||||||
|
ArchiveArgs: model.ArchiveArgs{
|
||||||
|
LinkArgs: model.LinkArgs{
|
||||||
|
Header: c.Request.Header,
|
||||||
|
Type: c.Query("type"),
|
||||||
|
HttpReq: c.Request,
|
||||||
|
},
|
||||||
|
Password: password,
|
||||||
|
},
|
||||||
|
InnerPath: innerPath,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
common.ErrorResp(c, err, 500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
localProxy(c, link, file, storage.GetStorage().ProxyRange)
|
||||||
|
} else {
|
||||||
|
common.ErrorStrResp(c, "proxy not allowed", 403)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ArchiveInternalExtract(c *gin.Context) {
|
||||||
|
archiveRawPath := c.MustGet("path").(string)
|
||||||
|
innerPath := utils.FixAndCleanPath(c.Query("inner"))
|
||||||
|
password := c.Query("pass")
|
||||||
|
rc, size, err := fs.ArchiveInternalExtract(c, archiveRawPath, model.ArchiveInnerArgs{
|
||||||
|
ArchiveArgs: model.ArchiveArgs{
|
||||||
|
LinkArgs: model.LinkArgs{
|
||||||
|
Header: c.Request.Header,
|
||||||
|
Type: c.Query("type"),
|
||||||
|
HttpReq: c.Request,
|
||||||
|
},
|
||||||
|
Password: password,
|
||||||
|
},
|
||||||
|
InnerPath: innerPath,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
common.ErrorResp(c, err, 500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if err := rc.Close(); err != nil {
|
||||||
|
log.Errorf("failed to close file streamer, %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
headers := map[string]string{
|
||||||
|
"Referrer-Policy": "no-referrer",
|
||||||
|
"Cache-Control": "max-age=0, no-cache, no-store, must-revalidate",
|
||||||
|
}
|
||||||
|
if c.Query("attachment") == "true" {
|
||||||
|
filename := stdpath.Base(innerPath)
|
||||||
|
headers["Content-Disposition"] = fmt.Sprintf("attachment; filename=\"%s\"", filename)
|
||||||
|
}
|
||||||
|
contentType := c.Request.Header.Get("Content-Type")
|
||||||
|
if contentType == "" {
|
||||||
|
fileExt := stdpath.Ext(innerPath)
|
||||||
|
contentType = mime.TypeByExtension(fileExt)
|
||||||
|
}
|
||||||
|
c.DataFromReader(200, size, contentType, rc, headers)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ArchiveExtensions(c *gin.Context) {
|
||||||
|
var ext []string
|
||||||
|
for key := range tool.Tools {
|
||||||
|
ext = append(ext, strings.TrimPrefix(key, "."))
|
||||||
|
}
|
||||||
|
common.SuccessResp(c, ext)
|
||||||
|
}
|
|
@ -40,28 +40,7 @@ func Down(c *gin.Context) {
|
||||||
common.ErrorResp(c, err, 500)
|
common.ErrorResp(c, err, 500)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if link.MFile != nil {
|
down(c, link)
|
||||||
defer func(ReadSeekCloser io.ReadCloser) {
|
|
||||||
err := ReadSeekCloser.Close()
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("close data error: %s", err)
|
|
||||||
}
|
|
||||||
}(link.MFile)
|
|
||||||
}
|
|
||||||
c.Header("Referrer-Policy", "no-referrer")
|
|
||||||
c.Header("Cache-Control", "max-age=0, no-cache, no-store, must-revalidate")
|
|
||||||
if setting.GetBool(conf.ForwardDirectLinkParams) {
|
|
||||||
query := c.Request.URL.Query()
|
|
||||||
for _, v := range conf.SlicesMap[conf.IgnoreDirectLinkParams] {
|
|
||||||
query.Del(v)
|
|
||||||
}
|
|
||||||
link.URL, err = utils.InjectQuery(link.URL, query)
|
|
||||||
if err != nil {
|
|
||||||
common.ErrorResp(c, err, 500)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
c.Redirect(302, link.URL)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,31 +74,62 @@ func Proxy(c *gin.Context) {
|
||||||
common.ErrorResp(c, err, 500)
|
common.ErrorResp(c, err, 500)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if link.URL != "" && setting.GetBool(conf.ForwardDirectLinkParams) {
|
localProxy(c, link, file, storage.GetStorage().ProxyRange)
|
||||||
query := c.Request.URL.Query()
|
|
||||||
for _, v := range conf.SlicesMap[conf.IgnoreDirectLinkParams] {
|
|
||||||
query.Del(v)
|
|
||||||
}
|
|
||||||
link.URL, err = utils.InjectQuery(link.URL, query)
|
|
||||||
if err != nil {
|
|
||||||
common.ErrorResp(c, err, 500)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if storage.GetStorage().ProxyRange {
|
|
||||||
common.ProxyRange(link, file.GetSize())
|
|
||||||
}
|
|
||||||
err = common.Proxy(c.Writer, c.Request, link, file)
|
|
||||||
if err != nil {
|
|
||||||
common.ErrorResp(c, err, 500, true)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
common.ErrorStrResp(c, "proxy not allowed", 403)
|
common.ErrorStrResp(c, "proxy not allowed", 403)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func down(c *gin.Context, link *model.Link) {
|
||||||
|
var err error
|
||||||
|
if link.MFile != nil {
|
||||||
|
defer func(ReadSeekCloser io.ReadCloser) {
|
||||||
|
err := ReadSeekCloser.Close()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("close data error: %s", err)
|
||||||
|
}
|
||||||
|
}(link.MFile)
|
||||||
|
}
|
||||||
|
c.Header("Referrer-Policy", "no-referrer")
|
||||||
|
c.Header("Cache-Control", "max-age=0, no-cache, no-store, must-revalidate")
|
||||||
|
if setting.GetBool(conf.ForwardDirectLinkParams) {
|
||||||
|
query := c.Request.URL.Query()
|
||||||
|
for _, v := range conf.SlicesMap[conf.IgnoreDirectLinkParams] {
|
||||||
|
query.Del(v)
|
||||||
|
}
|
||||||
|
link.URL, err = utils.InjectQuery(link.URL, query)
|
||||||
|
if err != nil {
|
||||||
|
common.ErrorResp(c, err, 500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.Redirect(302, link.URL)
|
||||||
|
}
|
||||||
|
|
||||||
|
func localProxy(c *gin.Context, link *model.Link, file model.Obj, proxyRange bool) {
|
||||||
|
var err error
|
||||||
|
if link.URL != "" && setting.GetBool(conf.ForwardDirectLinkParams) {
|
||||||
|
query := c.Request.URL.Query()
|
||||||
|
for _, v := range conf.SlicesMap[conf.IgnoreDirectLinkParams] {
|
||||||
|
query.Del(v)
|
||||||
|
}
|
||||||
|
link.URL, err = utils.InjectQuery(link.URL, query)
|
||||||
|
if err != nil {
|
||||||
|
common.ErrorResp(c, err, 500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if proxyRange {
|
||||||
|
common.ProxyRange(link, file.GetSize())
|
||||||
|
}
|
||||||
|
err = common.Proxy(c.Writer, c.Request, link, file)
|
||||||
|
if err != nil {
|
||||||
|
common.ErrorResp(c, err, 500, true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO need optimize
|
// TODO need optimize
|
||||||
// when can be proxy?
|
// when can be proxy?
|
||||||
// 1. text file
|
// 1. text file
|
||||||
|
|
|
@ -75,7 +75,7 @@ func getUserInfo(c *gin.Context) (bool, uint, bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTargetedHandler[T task.TaskExtensionInfo](manager *tache.Manager[T], callback func(c *gin.Context, task T)) gin.HandlerFunc {
|
func getTargetedHandler[T task.TaskExtensionInfo](manager task.Manager[T], callback func(c *gin.Context, task T)) gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
isAdmin, uid, ok := getUserInfo(c)
|
isAdmin, uid, ok := getUserInfo(c)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -97,7 +97,7 @@ func getTargetedHandler[T task.TaskExtensionInfo](manager *tache.Manager[T], cal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getBatchHandler[T task.TaskExtensionInfo](manager *tache.Manager[T], callback func(task T)) gin.HandlerFunc {
|
func getBatchHandler[T task.TaskExtensionInfo](manager task.Manager[T], callback func(task T)) gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
isAdmin, uid, ok := getUserInfo(c)
|
isAdmin, uid, ok := getUserInfo(c)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -122,7 +122,7 @@ func getBatchHandler[T task.TaskExtensionInfo](manager *tache.Manager[T], callba
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func taskRoute[T task.TaskExtensionInfo](g *gin.RouterGroup, manager *tache.Manager[T]) {
|
func taskRoute[T task.TaskExtensionInfo](g *gin.RouterGroup, manager task.Manager[T]) {
|
||||||
g.GET("/undone", func(c *gin.Context) {
|
g.GET("/undone", func(c *gin.Context) {
|
||||||
isAdmin, uid, ok := getUserInfo(c)
|
isAdmin, uid, ok := getUserInfo(c)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -220,4 +220,6 @@ func SetupTaskRoute(g *gin.RouterGroup) {
|
||||||
taskRoute(g.Group("/copy"), fs.CopyTaskManager)
|
taskRoute(g.Group("/copy"), fs.CopyTaskManager)
|
||||||
taskRoute(g.Group("/offline_download"), tool.DownloadTaskManager)
|
taskRoute(g.Group("/offline_download"), tool.DownloadTaskManager)
|
||||||
taskRoute(g.Group("/offline_download_transfer"), tool.TransferTaskManager)
|
taskRoute(g.Group("/offline_download_transfer"), tool.TransferTaskManager)
|
||||||
|
taskRoute(g.Group("/decompress"), fs.ArchiveDownloadTaskManager)
|
||||||
|
taskRoute(g.Group("/decompress_upload"), fs.ArchiveContentUploadTaskManager)
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,12 @@ func Init(e *gin.Engine) {
|
||||||
g.GET("/p/*path", middlewares.Down, handles.Proxy)
|
g.GET("/p/*path", middlewares.Down, handles.Proxy)
|
||||||
g.HEAD("/d/*path", middlewares.Down, handles.Down)
|
g.HEAD("/d/*path", middlewares.Down, handles.Down)
|
||||||
g.HEAD("/p/*path", middlewares.Down, handles.Proxy)
|
g.HEAD("/p/*path", middlewares.Down, handles.Proxy)
|
||||||
|
g.GET("/ad/*path", middlewares.Down, handles.ArchiveDown)
|
||||||
|
g.GET("/ap/*path", middlewares.Down, handles.ArchiveProxy)
|
||||||
|
g.GET("/ae/*path", middlewares.Down, handles.ArchiveInternalExtract)
|
||||||
|
g.HEAD("/ad/*path", middlewares.Down, handles.ArchiveDown)
|
||||||
|
g.HEAD("/ap/*path", middlewares.Down, handles.ArchiveProxy)
|
||||||
|
g.HEAD("/ae/*path", middlewares.Down, handles.ArchiveInternalExtract)
|
||||||
|
|
||||||
api := g.Group("/api")
|
api := g.Group("/api")
|
||||||
auth := api.Group("", middlewares.Auth)
|
auth := api.Group("", middlewares.Auth)
|
||||||
|
@ -77,6 +83,7 @@ func Init(e *gin.Engine) {
|
||||||
public := api.Group("/public")
|
public := api.Group("/public")
|
||||||
public.Any("/settings", handles.PublicSettings)
|
public.Any("/settings", handles.PublicSettings)
|
||||||
public.Any("/offline_download_tools", handles.OfflineDownloadTools)
|
public.Any("/offline_download_tools", handles.OfflineDownloadTools)
|
||||||
|
public.Any("/archive_extensions", handles.ArchiveExtensions)
|
||||||
|
|
||||||
_fs(auth.Group("/fs"))
|
_fs(auth.Group("/fs"))
|
||||||
_task(auth.Group("/task", middlewares.AuthNotGuest))
|
_task(auth.Group("/task", middlewares.AuthNotGuest))
|
||||||
|
@ -173,6 +180,10 @@ func _fs(g *gin.RouterGroup) {
|
||||||
// g.POST("/add_qbit", handles.AddQbittorrent)
|
// g.POST("/add_qbit", handles.AddQbittorrent)
|
||||||
// g.POST("/add_transmission", handles.SetTransmission)
|
// g.POST("/add_transmission", handles.SetTransmission)
|
||||||
g.POST("/add_offline_download", handles.AddOfflineDownload)
|
g.POST("/add_offline_download", handles.AddOfflineDownload)
|
||||||
|
a := g.Group("/archive")
|
||||||
|
a.Any("/meta", handles.FsArchiveMeta)
|
||||||
|
a.Any("/list", handles.FsArchiveList)
|
||||||
|
a.POST("/decompress", handles.FsArchiveDecompress)
|
||||||
}
|
}
|
||||||
|
|
||||||
func _task(g *gin.RouterGroup) {
|
func _task(g *gin.RouterGroup) {
|
||||||
|
|
Loading…
Reference in New Issue