自动上传服务端版本

This commit is contained in:
2025-10-23 15:39:38 +08:00
parent 7fbbaf1b5f
commit 329384d8ef
6 changed files with 424 additions and 3 deletions

9
go.mod
View File

@@ -26,6 +26,7 @@ require (
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/dlclark/regexp2 v1.11.4 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/filecoin-project/go-clock v0.1.0 // indirect
@@ -38,10 +39,12 @@ require (
github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7 // indirect
github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55 // indirect
github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f // indirect
github.com/go-ini/ini v1.67.0 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
github.com/go-stack/stack v1.8.0 // indirect
github.com/goccy/go-json v0.10.5 // indirect
github.com/google/gopacket v1.1.19 // indirect
github.com/google/pprof v0.0.0-20230405160723-4a4c7d95572b // indirect
github.com/grokify/html-strip-tags-go v0.1.0 // indirect
@@ -76,6 +79,9 @@ require (
github.com/miekg/dns v1.1.68 // indirect
github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect
github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect
github.com/minio/crc64nvme v1.0.2 // indirect
github.com/minio/md5-simd v1.1.2 // indirect
github.com/minio/minio-go/v7 v7.0.95 // indirect
github.com/minio/sha256-simd v1.0.1 // indirect
github.com/mr-tron/base58 v1.2.0 // indirect
github.com/multiformats/go-base32 v0.1.0 // indirect
@@ -94,6 +100,7 @@ require (
github.com/olekukonko/tablewriter v1.0.9 // indirect
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
github.com/philhofer/fwd v1.2.0 // indirect
github.com/pion/datachannel v1.5.10 // indirect
github.com/pion/dtls/v2 v2.2.12 // indirect
github.com/pion/dtls/v3 v3.0.6 // indirect
@@ -123,7 +130,9 @@ require (
github.com/quic-go/webtransport-go v0.9.0 // indirect
github.com/redis/go-redis/v9 v9.12.1 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/rs/xid v1.6.0 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/tinylib/msgp v1.3.0 // indirect
github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect
github.com/wlynxg/anet v0.0.5 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect

19
go.sum
View File

@@ -49,6 +49,8 @@ github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cn
github.com/dop251/goja v0.0.0-20250630131328-58d95d85e994 h1:aQYWswi+hRL2zJqGacdCZx32XjKYV8ApXFGntw79XAM=
github.com/dop251/goja v0.0.0-20250630131328-58d95d85e994/go.mod h1:MxLav0peU43GgvwVgNbLAj1s/bSGboKkhuULvq/7hx4=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
@@ -82,6 +84,8 @@ github.com/getlantern/systray v1.2.2/go.mod h1:pXFOI1wwqwYXEhLPm9ZGjS2u/vVELeIgN
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
@@ -92,6 +96,8 @@ github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5Nq
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/gogf/gf/contrib/nosql/redis/v2 v2.9.3 h1:VTbeHq8XpBCWFIwBGmuBl+jP8AepULnpgNz8GPBKBRQ=
github.com/gogf/gf/contrib/nosql/redis/v2 v2.9.3/go.mod h1:gcidgAYn4IWbx08QUThg7jw6bz3KklXI9/5zg8jnVHY=
github.com/gogf/gf/v2 v2.9.3 h1:qjN4s55FfUzxZ1AE8vUHNDX3V0eIOUGXhF2DjRTVZQ4=
@@ -160,6 +166,7 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/koron/go-ssdp v0.0.6 h1:Jb0h04599eq/CY7rB5YEqPS83HmRfHP2azkxMN2rFtU=
@@ -226,6 +233,12 @@ github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b/go.mod h1:lxPUiZwKo
github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc h1:PTfri+PuQmWDqERdnNMiD9ZejrlswWrCpBEZgWOiTrc=
github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc/go.mod h1:cGKTAVKx4SxOuR/czcZ/E2RSJ3sfHs8FpHhQ5CWMf9s=
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ=
github.com/minio/crc64nvme v1.0.2 h1:6uO1UxGAD+kwqWWp7mBFsi5gAse66C4NXO8cmcVculg=
github.com/minio/crc64nvme v1.0.2/go.mod h1:eVfm2fAzLlxMdUGc0EEBGSMmPwmXD5XiNRpnu9J3bvg=
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
github.com/minio/minio-go/v7 v7.0.95 h1:ywOUPg+PebTMTzn9VDsoFJy32ZuARN9zhB+K3IYEvYU=
github.com/minio/minio-go/v7 v7.0.95/go.mod h1:wOOX3uxS334vImCNRVyIDdXX9OsXDm89ToynKgqUKlo=
github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM=
github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8=
@@ -275,6 +288,8 @@ github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgF
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y=
github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM=
github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM=
github.com/pion/datachannel v1.5.10 h1:ly0Q26K1i6ZkGf42W7D4hQYR90pZwzFOjTq5AuCKk4o=
github.com/pion/datachannel v1.5.10/go.mod h1:p/jJfC9arb29W7WrxyKbepTU20CFgyx5oLo8Rs4Py/M=
github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s=
@@ -347,6 +362,8 @@ github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
@@ -395,6 +412,8 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
github.com/tinylib/msgp v1.3.0 h1:ULuf7GPooDaIlbyvgAxBV/FI7ynli6LZ1/nVUNu+0ww=
github.com/tinylib/msgp v1.3.0/go.mod h1:ykjzy2wzgrlvpDCRc4LA8UXy6D8bzMSuAF3WD57Gok0=
github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=

View File

@@ -1,14 +1,20 @@
package cmd
import (
"bytes"
"context"
"fmt"
"path"
"runtime"
"github.com/ayflying/p2p/internal/service"
"github.com/gogf/gf/v2/crypto/gsha1"
"github.com/gogf/gf/v2/encoding/gcompress"
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gcfg"
"github.com/gogf/gf/v2/os/gcmd"
"github.com/gogf/gf/v2/os/gfile"
)
var (
@@ -21,8 +27,8 @@ var (
//加载编辑配置文件
g.Cfg("hack").GetAdapter().(*gcfg.AdapterFile).SetFileName("hack/config.yaml")
//获取文件名
getFileName, err := g.Cfg("hack").Get(ctx, "gfcli.build.name")
filename := getFileName.String()
getName, err := g.Cfg("hack").Get(ctx, "gfcli.build.name")
name := getName.String()
getPath, err := g.Cfg("hack").Get(ctx, "gfcli.build.path")
pathMain := getPath.String()
@@ -34,7 +40,40 @@ var (
// 拼接操作系统和架构格式OS_ARCH
platform := fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH)
var filePath = path.Join(pathMain, version, platform, filename)
var versionFile = make(map[string]string)
var filePath = path.Join(pathMain, version, platform, name)
dirList, _ := gfile.ScanDir(path.Join(pathMain, version), "*", false)
for _, v := range dirList {
updateFilename := gfile.Name(v)
updateFilePath := path.Join("server_update", name, version, updateFilename)
var obj bytes.Buffer
g.Log().Debugf(ctx, "读取目录成功:%v", v)
fileMian := path.Join(v, name)
g.Log().Debugf(ctx, "判断当前文件是否存在:%v", fileMian)
if gfile.IsFile(fileMian) {
// 写入文件哈希
versionFile[updateFilePath+".gz"] = gsha1.MustEncryptFile(fileMian)
err = gcompress.GzipPathWriter(fileMian, &obj)
service.S3().PutObject(ctx, &obj, updateFilePath+".gz")
g.Log().Debugf(ctx, "成功上传文件到:%v", updateFilePath+".gz")
}
if gfile.IsFile(fileMian + ".exe") {
// 写入文件哈希
versionFile[updateFilePath+".gz"] = gsha1.MustEncryptFile(fileMian + ".exe")
err = gcompress.GzipPathWriter(fileMian+".exe", &obj)
service.S3().PutObject(ctx, &obj, updateFilePath+".gz")
g.Log().Debugf(ctx, "成功上传文件到:%v", updateFilePath+".gz")
}
// 写入文件版本文件
fileByte := gjson.MustEncode(versionFile)
service.S3().PutObject(ctx, bytes.NewReader(fileByte), path.Join("server_update", name, version, "version.json"))
if err != nil {
g.Log().Error(ctx, err)
}
}
g.Log().Debugf(ctx, "当前获取到的地址为:%v", filePath)
return

View File

@@ -7,4 +7,5 @@ package logic
import (
_ "github.com/ayflying/p2p/internal/logic/os"
_ "github.com/ayflying/p2p/internal/logic/p2p"
_ "github.com/ayflying/p2p/internal/logic/s3"
)

285
internal/logic/s3/s3.go Normal file
View File

@@ -0,0 +1,285 @@
package s3
import (
"context"
"fmt"
"io"
"log"
"net/url"
"path"
"time"
"github.com/ayflying/p2p/internal/service"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gcache"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/util/gconv"
"github.com/minio/minio-go/v7"
"github.com/minio/minio-go/v7/pkg/credentials"
)
// ctx 全局上下文,用于在整个包中传递请求范围的数据
var (
//client *minio.Client
)
// DataType 定义了 S3 配置的数据结构,用于存储访问 S3 所需的各种信息
type DataType struct {
AccessKey string `json:"access_key"` // 访问 S3 的密钥 ID
SecretKey string `json:"secret_key"` // 访问 S3 的密钥
Address string `json:"address"` // S3 服务的地址
Ssl bool `json:"ssl"` // 是否使用 SSL 加密连接
Url string `json:"url"` // S3 服务的访问 URL
BucketName string `json:"bucket_name"` // 默认存储桶名称
}
var (
clientList = make(map[string]*minio.Client) // Minio S3 客户端实例
cfgList = make(map[string]*DataType) // S3 配置信息
)
// Mod 定义了 S3 模块的结构体,包含一个 S3 客户端实例和配置信息
type sS3 struct {
client *minio.Client
cfg *DataType
}
func init() {
service.RegisterS3(New())
}
// New 根据配置创建一个新的 S3 模块实例
// 如果未提供名称,则从配置中获取默认的 S3 类型
// 配置错误时会触发 panic
func New(_name ...string) *sS3 {
var name string
if len(_name) > 0 {
name = _name[0]
} else {
getName, _ := g.Cfg("local").Get(gctx.New(), "s3.type")
name = getName.String()
}
if _, ok := cfgList[name]; ok {
return &sS3{
client: clientList[name],
cfg: cfgList[name],
}
}
get, err := g.Cfg("local").Get(gctx.New(), "s3."+name)
if err != nil {
panic(err.Error())
}
var cfg *DataType
get.Scan(&cfg)
// 使用 minio-go 创建 S3 客户端
obj, err := minio.New(
cfg.Address,
&minio.Options{
Creds: credentials.NewStaticV4(cfg.AccessKey, cfg.SecretKey, ""),
Secure: cfg.Ssl,
//BucketLookup: minio.BucketLookupPath,
},
)
if err != nil {
log.Fatalln(err)
}
// 复制初始化参数
cfgList[name] = cfg
clientList[name] = obj
mod := &sS3{
client: clientList[name],
cfg: cfgList[name],
}
return mod
}
//// GetCfg 获取当前 S3 模块的配置信息
//func (s *sS3) GetCfg() *DataType {
// return s.cfg
//}
// GetFileUrl 生成指向 S3 存储桶中指定文件的预签名 URL
// 预签名 URL 可用于在有限时间内访问 S3 存储桶中的文件
// 支持从缓存中获取预签名 URL以减少重复请求
func (s *sS3) GetFileUrl(ctx context.Context, name string, _expires ...time.Duration) (presignedURL *url.URL, err error) {
// 设置预签名 URL 的有效期为 1 小时,可通过参数覆盖
expires := time.Hour * 1
if len(_expires) > 0 {
expires = _expires[0]
}
// 生成缓存键
cacheKey := fmt.Sprintf("s3:%v:%v", name, s.cfg.BucketName)
// 尝试从缓存中获取预签名 URL
get, _ := gcache.Get(ctx, cacheKey)
if !get.IsEmpty() {
// 将缓存中的值转换为 *url.URL 类型
err = gconv.Struct(get.Val(), &presignedURL)
return
}
// 调用 S3 客户端生成预签名 URL
presignedURL, err = s.client.PresignedGetObject(ctx, s.cfg.BucketName, name, expires, nil)
// 将生成的预签名 URL 存入缓存
err = gcache.Set(ctx, cacheKey, presignedURL, expires)
return
}
// PutFileUrl 生成一个用于上传文件到指定存储桶的预签名 URL
// 预签名 URL 的有效期默认为 10 分钟
func (s *sS3) PutFileUrl(ctx context.Context, name string) (presignedURL *url.URL, err error) {
// 设置预签名 URL 的有效期为 10 分钟
expires := time.Minute * 10
// 调用 S3 客户端生成预签名 URL
presignedURL, err = s.client.PresignedPutObject(ctx, s.cfg.BucketName, name, expires)
return
}
// ListBuckets 获取当前 S3 客户端可访问的所有存储桶列表
// 出错时返回 nil
func (s *sS3) ListBuckets(ctx context.Context, ) []minio.BucketInfo {
buckets, err := s.client.ListBuckets(ctx)
if err != nil {
return nil
}
return buckets
}
// PutObject 上传文件到指定的存储桶中
// 支持指定文件大小,未指定时将读取文件直到结束
func (s *sS3) PutObject(ctx context.Context, f io.Reader, name string, _size ...int64) (res minio.UploadInfo, err error) {
// 初始化文件大小为 -1表示将读取文件至结束
var size = int64(-1)
//if len(_size) > 0 {
// size = _size[0]
//}
// 调用 S3 客户端上传文件,设置内容类型为 "application/octet-stream"
res, err = s.client.PutObject(ctx, s.cfg.BucketName, name, f, size, minio.PutObjectOptions{
//ContentType: "application/octet-stream",
})
if err != nil {
// 记录上传错误日志
g.Log().Error(ctx, err)
}
return
}
// RemoveObject 从指定存储桶中删除指定名称的文件
func (s *sS3) RemoveObject(ctx context.Context, name string) (err error) {
opts := minio.RemoveObjectOptions{
ForceDelete: true,
//GovernanceBypass: true,
//VersionID: "myversionid",
}
// 调用 S3 客户端删除文件
err = s.client.RemoveObject(ctx, s.cfg.BucketName, name, opts)
return
}
// ListObjects 获取指定存储桶中指定前缀的文件列表
// 返回一个包含文件信息的通道
func (s *sS3) ListObjects(ctx context.Context, prefix string) (res <-chan minio.ObjectInfo, err error) {
// 调用 S3 客户端获取文件列表
res = s.client.ListObjects(ctx, s.cfg.BucketName, minio.ListObjectsOptions{
Prefix: prefix,
})
return
}
// StatObject 获取指定存储桶中指定文件的元数据信息
func (s *sS3) StatObject(ctx context.Context, objectName string) (res minio.ObjectInfo, err error) {
res, err = s.client.StatObject(ctx, s.cfg.BucketName, objectName, minio.StatObjectOptions{})
return
}
//// SetBucketPolicy 设置指定存储桶或对象前缀的访问策略
//// 目前使用固定的策略,可根据需求修改
//func (s *sS3) SetBucketPolicy(ctx context.Context, prefix string) (err error) {
// // 定义访问策略
// policy := `{"Version": "2012-10-17","Statement": [{"Action": ["s3:GetObject"],"Effect": "Allow","Principal": {"AWS": ["*"]},"Resource": ["arn:aws:s3:::my-bucketname/*"],"Sid": ""}]}`
// // 调用 S3 客户端设置存储桶策略
// err = s.client.SetBucketPolicy(ctx, s.cfg.BucketName, policy)
// return
//}
// GetUrl 获取文件的访问地址
// 支持返回默认文件地址,根据 SSL 配置生成不同格式的 URL
func (s *sS3) GetUrl(filePath string, defaultFile ...string) (url string) {
bucketName := s.cfg.BucketName
get := s.cfg.Url
// 如果没有指定文件路径,且提供了默认文件路径,则使用默认路径
if filePath == "" && len(defaultFile) > 0 {
filePath = defaultFile[0]
}
//switch s.cfg.Provider {
//case "qiniu":
// url = get + path.Join(bucketName, filePath)
//default:
// url = get + filePath
//}
url = get + filePath
if !s.cfg.Ssl {
url = get + path.Join(bucketName, filePath)
}
return
}
// GetPath 从文件访问 URL 中提取文件路径
func (s *sS3) GetPath(url string) (filePath string) {
bucketName := s.cfg.BucketName
get := s.cfg.Url
return url[len(get+bucketName)+1:]
}
// CopyObject 在指定存储桶内复制文件
// bucketName 存储桶名称
// dstStr 目标文件路径
// srcStr 源文件路径
// 返回操作过程中可能出现的错误
func (s *sS3) CopyObject(ctx context.Context, dstStr string, srcStr string) (err error) {
// 定义目标文件的复制选项,包含存储桶名称和目标文件路径
var dst = minio.CopyDestOptions{
Bucket: s.cfg.BucketName,
Object: dstStr,
}
// 定义源文件的复制选项,包含存储桶名称和源文件路径
var src = minio.CopySrcOptions{
Bucket: s.cfg.BucketName,
Object: srcStr,
}
// 调用 S3 客户端的 CopyObject 方法,将源文件复制到目标位置
// 忽略返回的复制信息,仅关注是否发生错误
_, err = s.client.CopyObject(ctx, dst, src)
return
}
// Rename 重命名文件
func (s *sS3) Rename(ctx context.Context, oldName string, newName string) (err error) {
// 复制文件到新的名称
g.Log().Debugf(nil, "仓库=%v,rename %s to %s", s.cfg.BucketName, oldName, newName)
err = s.CopyObject(ctx, newName, oldName)
if err != nil {
g.Log().Error(ctx, err)
return
}
// 删除原始文件
err = s.RemoveObject(ctx, oldName)
if err != nil {
g.Log().Error(ctx, err)
return
}
return
}

68
internal/service/s_3.go Normal file
View File

@@ -0,0 +1,68 @@
// ================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// You can delete these comments if you wish manually maintain this interface file.
// ================================================================================
package service
import (
"context"
"io"
"net/url"
"time"
"github.com/minio/minio-go/v7"
)
type (
IS3 interface {
// GetFileUrl 生成指向 S3 存储桶中指定文件的预签名 URL
// 预签名 URL 可用于在有限时间内访问 S3 存储桶中的文件
// 支持从缓存中获取预签名 URL以减少重复请求
GetFileUrl(ctx context.Context, name string, _expires ...time.Duration) (presignedURL *url.URL, err error)
// PutFileUrl 生成一个用于上传文件到指定存储桶的预签名 URL
// 预签名 URL 的有效期默认为 10 分钟
PutFileUrl(ctx context.Context, name string) (presignedURL *url.URL, err error)
// ListBuckets 获取当前 S3 客户端可访问的所有存储桶列表
// 出错时返回 nil
ListBuckets(ctx context.Context) []minio.BucketInfo
// PutObject 上传文件到指定的存储桶中
// 支持指定文件大小,未指定时将读取文件直到结束
PutObject(ctx context.Context, f io.Reader, name string, _size ...int64) (res minio.UploadInfo, err error)
// RemoveObject 从指定存储桶中删除指定名称的文件
RemoveObject(ctx context.Context, name string) (err error)
// ListObjects 获取指定存储桶中指定前缀的文件列表
// 返回一个包含文件信息的通道
ListObjects(ctx context.Context, prefix string) (res <-chan minio.ObjectInfo, err error)
// StatObject 获取指定存储桶中指定文件的元数据信息
StatObject(ctx context.Context, objectName string) (res minio.ObjectInfo, err error)
// GetUrl 获取文件的访问地址
// 支持返回默认文件地址,根据 SSL 配置生成不同格式的 URL
GetUrl(filePath string, defaultFile ...string) (url string)
// GetPath 从文件访问 URL 中提取文件路径
GetPath(url string) (filePath string)
// CopyObject 在指定存储桶内复制文件
// bucketName 存储桶名称
// dstStr 目标文件路径
// srcStr 源文件路径
// 返回操作过程中可能出现的错误
CopyObject(ctx context.Context, dstStr string, srcStr string) (err error)
// Rename 重命名文件
Rename(ctx context.Context, oldName string, newName string) (err error)
}
)
var (
localS3 IS3
)
func S3() IS3 {
if localS3 == nil {
panic("implement not found for interface IS3, forgot register?")
}
return localS3
}
func RegisterS3(i IS3) {
localS3 = i
}