diff --git a/go.mod b/go.mod index b0ee7447c..6d8177ab9 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,8 @@ module github.com/openimsdk/open-im-server/v3 -go 1.19 +go 1.21 + +toolchain go1.21.8 require ( firebase.google.com/go v3.13.0+incompatible @@ -12,17 +14,14 @@ require ( github.com/gorilla/websocket v1.5.1 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible // indirect - github.com/minio/minio-go/v7 v7.0.67 github.com/mitchellh/mapstructure v1.5.0 github.com/openimsdk/localcache v0.0.1 github.com/openimsdk/protocol v0.0.58-google - github.com/openimsdk/tools v0.0.47-alpha.8 + github.com/openimsdk/tools v0.0.47-alpha.9 github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/client_golang v1.18.0 - github.com/sirupsen/logrus v1.9.3 // indirect github.com/stretchr/testify v1.8.4 go.mongodb.org/mongo-driver v1.14.0 - golang.org/x/image v0.15.0 google.golang.org/api v0.165.0 google.golang.org/grpc v1.62.1 google.golang.org/protobuf v1.33.0 @@ -33,15 +32,11 @@ require github.com/google/uuid v1.6.0 require ( github.com/IBM/sarama v1.43.0 - github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible github.com/go-redis/redis v6.15.9+incompatible github.com/redis/go-redis/v9 v9.4.0 github.com/robfig/cron/v3 v3.0.1 - github.com/spf13/pflag v1.0.5 github.com/stathat/consistent v1.0.0 - github.com/tencentyun/cos-go-sdk-v5 v0.7.46 golang.org/x/sync v0.6.0 - gopkg.in/src-d/go-git.v4 v4.13.1 gotest.tools v2.2.0+incompatible ) @@ -53,6 +48,7 @@ require ( cloud.google.com/go/iam v1.1.5 // indirect cloud.google.com/go/longrunning v0.5.4 // indirect cloud.google.com/go/storage v1.36.0 // indirect + github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bytedance/sonic v1.9.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect @@ -64,7 +60,6 @@ require ( github.com/eapache/go-resiliency v1.6.0 // indirect github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 // indirect github.com/eapache/queue v1.1.0 // indirect - github.com/emirpasic/gods v1.12.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/gin-contrib/sse v0.1.0 // indirect @@ -85,7 +80,6 @@ require ( github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jcmturner/aescts/v2 v2.0.0 // indirect github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect github.com/jcmturner/gofork v1.7.6 // indirect @@ -95,15 +89,15 @@ require ( github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd // indirect github.com/klauspost/compress v1.17.7 // indirect github.com/klauspost/cpuid/v2 v2.2.6 // indirect + github.com/kr/text v0.1.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/lithammer/shortuuid v3.0.0+incompatible // indirect github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/minio/md5-simd v1.1.2 // indirect + github.com/minio/minio-go/v7 v7.0.69 // indirect github.com/minio/sha256-simd v1.0.1 // indirect - github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect @@ -118,11 +112,10 @@ require ( github.com/prometheus/procfs v0.12.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rs/xid v1.5.0 // indirect - github.com/sergi/go-diff v1.0.0 // indirect - github.com/src-d/gcfg v1.4.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/objx v0.5.0 // indirect + github.com/tencentyun/cos-go-sdk-v5 v0.7.47 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect - github.com/xanzy/ssh-agent v0.2.1 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/scram v1.1.2 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect @@ -136,6 +129,7 @@ require ( go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/arch v0.3.0 // indirect + golang.org/x/image v0.15.0 // indirect golang.org/x/net v0.22.0 // indirect golang.org/x/oauth2 v0.17.0 // indirect golang.org/x/sys v0.18.0 // indirect @@ -145,8 +139,6 @@ require ( google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect - gopkg.in/src-d/go-billy.v4 v4.3.2 // indirect - gopkg.in/warnings.v0 v0.1.2 // indirect gorm.io/gorm v1.25.8 // indirect stathat.com/c/consistent v1.0.0 // indirect ) diff --git a/go.sum b/go.sum index fa95ed0ba..318a2a757 100644 --- a/go.sum +++ b/go.sum @@ -16,27 +16,19 @@ cloud.google.com/go/storage v1.36.0/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYE firebase.google.com/go v3.13.0+incompatible h1:3TdYC3DDi6aHn20qoRkxwGqNgdjtblwVAyRLQwGn/+4= firebase.google.com/go v3.13.0+incompatible/go.mod h1:xlah6XbEyW6tbfSklcfe5FHJIwjt8toICdV5Wh9ptHs= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/IBM/sarama v1.42.2 h1:VoY4hVIZ+WQJ8G9KNY/SQlWguBQXQ9uvFPOnrcu8hEw= -github.com/IBM/sarama v1.42.2/go.mod h1:FLPGUGwYqEs62hq2bVG6Io2+5n+pS6s/WOXVKWSLFtE= +github.com/IBM/sarama v1.43.0 h1:YFFDn8mMI2QL0wOrG0J2sFoVIAFl7hS9JQi2YZsXtJc= github.com/IBM/sarama v1.43.0/go.mod h1:zlE6HEbC/SMQ9mhEYaF7nNLYOUyrs0obySKCckWP9BM= -github.com/OpenIMSDK/protocol v0.0.56 h1:mbVFyDBachEsmJLfYW5AU1z2KL8AUEpoHG8RPCIxjgg= -github.com/OpenIMSDK/protocol v0.0.56/go.mod h1:F25dFrwrIx3lkNoiuf6FkCfxuwf8L4Z8UIsdTHP/r0Y= -github.com/OpenIMSDK/tools v0.0.37 h1:qvDqmA4RbEJtPjZouWCkVuf/pjm6Y8nUrG5iH2gcnOg= -github.com/OpenIMSDK/tools v0.0.37/go.mod h1:wBfR5CYmEyvxl03QJbTkhz1CluK6J4/lX0lviu8JAjE= github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM= -github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= -github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= 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/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= -github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= +github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= +github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= @@ -54,8 +46,8 @@ github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5P github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ= +github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -72,17 +64,16 @@ github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 h1:Oy0F4A github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3/go.mod h1:YvSRo5mw33fLEx1+DlK6L2VV43tJt5Eyel9n9XBcR+0= github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= -github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= +github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= @@ -92,14 +83,13 @@ github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= -github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= -github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= @@ -153,6 +143,7 @@ github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= +github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= @@ -184,8 +175,6 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= -github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= @@ -198,7 +187,6 @@ github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh6 github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= @@ -206,10 +194,9 @@ github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkr github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= +github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= 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/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY= -github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= 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/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg= @@ -218,12 +205,11 @@ github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa02 github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc= github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8= @@ -240,12 +226,10 @@ github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvls github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= 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.67 h1:BeBvZWAS+kRJm1vGTMJYVjKUNoo0FoEt/wUWdUtfmh8= -github.com/minio/minio-go/v7 v7.0.67/go.mod h1:+UXocnUeZ3wHvVh5s95gcrA4YjMIbccT6ubB+1m054A= +github.com/minio/minio-go/v7 v7.0.69 h1:l8AnsQFyY1xiwa/DaQskY4NXSLA2yrGsW5iD9nRPVS0= +github.com/minio/minio-go/v7 v7.0.69/go.mod h1:XAvOPJQ5Xlzk5o3o/ArO2NMbhSGkimC+bpW/ngRKDmQ= 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/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= @@ -275,22 +259,12 @@ github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= github.com/openimsdk/protocol v0.0.58-google h1:cGNUVaXO9LqcFgIb4NvrtEOrv0spGecoQKyN8YWhyZs= github.com/openimsdk/protocol v0.0.58-google/go.mod h1:OZQA9FR55lseYoN2Ql1XAHYKHJGu7OMNkUbuekrKCM8= -github.com/openimsdk/tools v0.0.46-alpha.16 h1:4ouPoTrCuyREF1UPBaka+Oge4x0XsICfNMoGxJuziKU= -github.com/openimsdk/tools v0.0.46-alpha.16/go.mod h1:hMH6pHDVhOXjA8NQ25P7mOtfRXb5lsPAv/uUDR8342Y= -github.com/openimsdk/tools v0.0.46-alpha.16.0.20240322040503-5ee151e04e7d h1:XqhSyp3iHMSzUVRFWpoentayDfteybGHW7wT8WuvVEg= -github.com/openimsdk/tools v0.0.46-alpha.16.0.20240322040503-5ee151e04e7d/go.mod h1:Czxh+12vxUMypTIDZBHcTHwYL6o+DGMrC1ZmHqAk/tc= -github.com/openimsdk/tools v0.0.47-alpha.4 h1:18BJ3A7G5gN4DxtVSWuiNH1ZgaTd8blytsBwYOTUGwE= -github.com/openimsdk/tools v0.0.47-alpha.4/go.mod h1:7LNWVXlqHUhTXeETk2ZcBPVzUFIjafHpP5SHh9E+9AY= -github.com/openimsdk/tools v0.0.47-alpha.5 h1:CcLnq0Ne30f9aachsN/LpW1p+C0bzIoIcwen5eCA6to= -github.com/openimsdk/tools v0.0.47-alpha.5/go.mod h1:7LNWVXlqHUhTXeETk2ZcBPVzUFIjafHpP5SHh9E+9AY= -github.com/openimsdk/tools v0.0.47-alpha.6 h1:GwV026servNNisB5MjlLr3G497+4z7hy6Rc+E14IElc= -github.com/openimsdk/tools v0.0.47-alpha.6/go.mod h1:7LNWVXlqHUhTXeETk2ZcBPVzUFIjafHpP5SHh9E+9AY= -github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= +github.com/openimsdk/tools v0.0.47-alpha.9 h1:s+P5+PVam26SSJeWrvoBslbjQYp5/SHdbBBgLV3UMW4= +github.com/openimsdk/tools v0.0.47-alpha.9/go.mod h1:mUsH+ANKbdmhUih43ijJHvuYcU8owm7X3kdFH7FsIec= github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -311,23 +285,17 @@ github.com/redis/go-redis/v9 v9.4.0/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0 github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4= -github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= github.com/stathat/consistent v1.0.0 h1:ZFJ1QTRn8npNBKW065raSZ8xfOqhpb8vLOkfp4CcL/U= github.com/stathat/consistent v1.0.0/go.mod h1:uajTPbgSygZBJ+V+0mY7meZ8i0XAcZs7AQ6V121XSxw= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -343,14 +311,12 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.563/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/kms v1.0.563/go.mod h1:uom4Nvi9W+Qkom0exYiJ9VWJjXwyxtPYTkKkaLMlfE0= -github.com/tencentyun/cos-go-sdk-v5 v0.7.46 h1:IeTiMR8qZ7iQWhAGb1niw5vt0T1TfAwPeB8Gn/oTkuk= -github.com/tencentyun/cos-go-sdk-v5 v0.7.46/go.mod h1:DH9US8nB+AJXqwu/AMOrCFN1COv3dpytXuJWHgdg7kE= +github.com/tencentyun/cos-go-sdk-v5 v0.7.47 h1:uoS4Sob16qEYoapkqJq1D1Vnsy9ira9BfNUMtoFYTI4= +github.com/tencentyun/cos-go-sdk-v5 v0.7.47/go.mod h1:DH9US8nB+AJXqwu/AMOrCFN1COv3dpytXuJWHgdg7kE= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70= -github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= @@ -375,11 +341,13 @@ go.opentelemetry.io/otel v1.23.0/go.mod h1:YCycw9ZeKhcJFrb34iVSkyT0iczq/zYDtZYFu go.opentelemetry.io/otel/metric v1.23.0 h1:pazkx7ss4LFVVYSxYew7L5I6qvLXHA0Ap2pwV+9Cnpo= go.opentelemetry.io/otel/metric v1.23.0/go.mod h1:MqUW2X2a6Q8RN96E2/nqNoT+z9BSms20Jb7Bbp+HiTo= go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= +go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= go.opentelemetry.io/otel/trace v1.23.0 h1:37Ik5Ib7xfYVb4V1UtnT97T1jI+AoIYkJyPkuL4iJgI= go.opentelemetry.io/otel/trace v1.23.0/go.mod h1:GSGTbIClEsuZrGIzoEHqsVfxgn5UkggkflQwDScNUsk= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= @@ -387,9 +355,7 @@ go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/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-20190701094942-4def268fd1a4/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-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= @@ -412,7 +378,6 @@ golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73r 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-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-20200114155413-6afb5195e5aa/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-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= @@ -439,9 +404,7 @@ golang.org/x/sync v0.6.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-20180909124046-d0be0721c37e/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-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -454,7 +417,6 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -463,9 +425,7 @@ golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= @@ -480,7 +440,6 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm 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-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -491,6 +450,7 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T 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-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= google.golang.org/api v0.165.0 h1:zd5d4JIIIaYYsfVy1HzoXYZ9rWCSBxxAglbczzo7Bgc= google.golang.org/api v0.165.0/go.mod h1:2OatzO7ZDQsoS7IFf3rvsE17/TldiU3F/zxFHeqUB5o= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= @@ -527,21 +487,13 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/src-d/go-billy.v4 v4.3.2 h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg= -gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98= -gopkg.in/src-d/go-git-fixtures.v3 v3.5.0 h1:ivZFOIltbce2Mo8IjzUHAFoq/IylO9WHhNOAJK+LsJg= -gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= -gopkg.in/src-d/go-git.v4 v4.13.1 h1:SRtFyV8Kxc0UP7aCHcijOMQGPxHSmMOPrzulQWolkYE= -gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= -gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/internal/msgtransfer/init.go b/internal/msgtransfer/init.go index cebbe67ea..71db7c859 100644 --- a/internal/msgtransfer/init.go +++ b/internal/msgtransfer/init.go @@ -18,6 +18,8 @@ import ( "context" "errors" "fmt" + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/redisutil" "net/http" "os" "os/signal" @@ -27,7 +29,6 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister" "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" @@ -55,14 +56,15 @@ type MsgTransfer struct { } func Start(ctx context.Context, config *config.GlobalConfig, prometheusPort, index int) error { - log.CInfo(ctx, "MSG-TRANSFER server is initializing", - "prometheusPort", prometheusPort, "index", index) - rdb, err := cache.NewRedis(ctx, &config.Redis) + log.CInfo(ctx, "MSG-TRANSFER server is initializing", "prometheusPort", prometheusPort, "index", index) + mgocli, err := mongoutil.NewMongoDB(ctx, config.Mongo.Build()) + if err != nil { + return err + } + rdb, err := redisutil.NewRedisClient(ctx, config.Redis.Build()) if err != nil { return err } - - mongo, err := unrelation.NewMongoDB(ctx, &config.Mongo) if err != nil { return err } @@ -77,7 +79,7 @@ func Start(ctx context.Context, config *config.GlobalConfig, prometheusPort, ind client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin"))) msgModel := cache.NewMsgCacheModel(rdb, config.MsgCacheTimeout, &config.Redis) - msgDocModel, err := mgo.NewMsgMongo(mongo.GetDatabase(config.Mongo.Database)) + msgDocModel, err := mgo.NewMsgMongo(mgocli.GetDB()) if err != nil { return err } diff --git a/internal/rpc/third/s3.go b/internal/rpc/third/s3.go index 18af41840..882d3576e 100644 --- a/internal/rpc/third/s3.go +++ b/internal/rpc/third/s3.go @@ -24,14 +24,14 @@ import ( "time" "github.com/google/uuid" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/cont" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" "github.com/openimsdk/protocol/third" "github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/log" "github.com/openimsdk/tools/mcontext" + "github.com/openimsdk/tools/s3" + "github.com/openimsdk/tools/s3/cont" "github.com/openimsdk/tools/utils/datautil" ) diff --git a/internal/rpc/third/third.go b/internal/rpc/third/third.go index 063f03b63..85c5f1f0f 100644 --- a/internal/rpc/third/third.go +++ b/internal/rpc/third/third.go @@ -24,16 +24,16 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/cos" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/minio" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/oss" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/protocol/third" "github.com/openimsdk/tools/db/mongoutil" "github.com/openimsdk/tools/db/redisutil" "github.com/openimsdk/tools/discovery" "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/s3" + "github.com/openimsdk/tools/s3/cos" + "github.com/openimsdk/tools/s3/minio" + "github.com/openimsdk/tools/s3/oss" "google.golang.org/grpc" ) diff --git a/pkg/common/db/cache/meta_cache.go b/pkg/common/db/cache/meta_cache.go index cd4cddf95..6a9f6fe88 100644 --- a/pkg/common/db/cache/meta_cache.go +++ b/pkg/common/db/cache/meta_cache.go @@ -74,7 +74,7 @@ func (m *metaCacheRedis) Copy() metaCache { keys: keys, maxRetryTimes: m.maxRetryTimes, retryInterval: m.retryInterval, - redisClient: redisClient, + redisClient: m.redisClient, } } diff --git a/pkg/common/db/cache/s3.go b/pkg/common/db/cache/s3.go index 28e993be0..1610283ca 100644 --- a/pkg/common/db/cache/s3.go +++ b/pkg/common/db/cache/s3.go @@ -16,12 +16,14 @@ package cache import ( "context" + "github.com/openimsdk/tools/s3/cont" + "github.com/openimsdk/tools/s3/minio" "strconv" "time" "github.com/dtm-labs/rockscache" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/tools/s3" "github.com/redis/go-redis/v9" ) @@ -83,7 +85,7 @@ type S3Cache interface { DelS3Key(engine string, keys ...string) S3Cache } -func NewS3Cache(rdb redis.UniversalClient, s3 s3.Interface) S3Cache { +func NewS3Cache(rdb redis.UniversalClient, s3 s3.Interface) cont.S3Cache { rcClient := rockscache.NewClient(rdb, rockscache.NewDefaultOptions()) return &s3CacheRedis{ rcClient: rcClient, @@ -100,7 +102,7 @@ type s3CacheRedis struct { expireTime time.Duration } -func (g *s3CacheRedis) NewCache() S3Cache { +func (g *s3CacheRedis) newCache() *s3CacheRedis { return &s3CacheRedis{ rcClient: g.rcClient, expireTime: g.expireTime, @@ -109,14 +111,14 @@ func (g *s3CacheRedis) NewCache() S3Cache { } } -func (g *s3CacheRedis) DelS3Key(engine string, keys ...string) S3Cache { - s3cache := g.NewCache() +func (g *s3CacheRedis) DelS3Key(ctx context.Context, engine string, keys ...string) error { + s3cache := g.newCache() ks := make([]string, 0, len(keys)) for _, key := range keys { ks = append(ks, g.getS3Key(engine, key)) } s3cache.AddKeys(ks...) - return s3cache + return s3cache.ExecDel(ctx) } func (g *s3CacheRedis) getS3Key(engine string, name string) string { @@ -137,7 +139,7 @@ type MinioCache interface { DelImageThumbnailKey(key string, format string, width int, height int) MinioCache } -func NewMinioCache(rdb redis.UniversalClient) MinioCache { +func NewMinioCache(rdb redis.UniversalClient) minio.Cache { rcClient := rockscache.NewClient(rdb, rockscache.NewDefaultOptions()) return &minioCacheRedis{ rcClient: rcClient, @@ -152,7 +154,7 @@ type minioCacheRedis struct { expireTime time.Duration } -func (g *minioCacheRedis) NewCache() MinioCache { +func (g *minioCacheRedis) newCache() *minioCacheRedis { return &minioCacheRedis{ rcClient: g.rcClient, expireTime: g.expireTime, @@ -160,20 +162,20 @@ func (g *minioCacheRedis) NewCache() MinioCache { } } -func (g *minioCacheRedis) DelObjectImageInfoKey(keys ...string) MinioCache { - s3cache := g.NewCache() +func (g *minioCacheRedis) DelObjectImageInfoKey(ctx context.Context, keys ...string) error { + s3cache := g.newCache() ks := make([]string, 0, len(keys)) for _, key := range keys { ks = append(ks, g.getObjectImageInfoKey(key)) } s3cache.AddKeys(ks...) - return s3cache + return s3cache.ExecDel(ctx) } -func (g *minioCacheRedis) DelImageThumbnailKey(key string, format string, width int, height int) MinioCache { - s3cache := g.NewCache() +func (g *minioCacheRedis) DelImageThumbnailKey(ctx context.Context, key string, format string, width int, height int) error { + s3cache := g.newCache() s3cache.AddKeys(g.getMinioImageThumbnailKey(key, format, width, height)) - return s3cache + return s3cache.ExecDel(ctx) } func (g *minioCacheRedis) getObjectImageInfoKey(key string) string { @@ -184,7 +186,7 @@ func (g *minioCacheRedis) getMinioImageThumbnailKey(key string, format string, w return "MINIO:THUMBNAIL:" + format + ":w" + strconv.Itoa(width) + ":h" + strconv.Itoa(height) + ":" + key } -func (g *minioCacheRedis) GetImageObjectKeyInfo(ctx context.Context, key string, fn func(ctx context.Context) (*MinioImageInfo, error)) (*MinioImageInfo, error) { +func (g *minioCacheRedis) GetImageObjectKeyInfo(ctx context.Context, key string, fn func(ctx context.Context) (*minio.ImageInfo, error)) (*minio.ImageInfo, error) { info, err := getCache(ctx, g.rcClient, g.getObjectImageInfoKey(key), g.expireTime, fn) if err != nil { return nil, err diff --git a/pkg/common/db/controller/s3.go b/pkg/common/db/controller/s3.go index e847c9c8f..eae47c421 100644 --- a/pkg/common/db/controller/s3.go +++ b/pkg/common/db/controller/s3.go @@ -20,9 +20,9 @@ import ( "time" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/cont" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" + "github.com/openimsdk/tools/s3" + "github.com/openimsdk/tools/s3/cont" "github.com/redis/go-redis/v9" ) diff --git a/pkg/common/db/s3/cont/consts.go b/pkg/common/db/s3/cont/consts.go deleted file mode 100644 index 45f1dd7e3..000000000 --- a/pkg/common/db/s3/cont/consts.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cont - -const ( - // HashPath defines the storage path for hash data within the 'openim' directory. - hashPath = "openim/data/hash/" - - // TempPath specifies the directory for temporary files in the 'openim' structure. - tempPath = "openim/temp/" - - // DirectPath indicates the directory for direct uploads or access within the 'openim' structure. - DirectPath = "openim/direct" - - // UploadTypeMultipart represents the identifier for multipart uploads, - // allowing large files to be uploaded in chunks. - UploadTypeMultipart = 1 - - // UploadTypePresigned signifies the use of presigned URLs for uploads, - // facilitating secure, authorized file transfers without requiring direct access to the storage credentials. - UploadTypePresigned = 2 - - // PartSeparator is used as a delimiter in multipart upload processes, - // separating individual file parts. - partSeparator = "," -) diff --git a/pkg/common/db/s3/cont/controller.go b/pkg/common/db/s3/cont/controller.go deleted file mode 100644 index 7eea22d18..000000000 --- a/pkg/common/db/s3/cont/controller.go +++ /dev/null @@ -1,282 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cont - -import ( - "context" - "crypto/md5" - "encoding/hex" - "errors" - "fmt" - "path" - "strings" - "time" - - "github.com/google/uuid" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" - "github.com/openimsdk/tools/errs" - "github.com/openimsdk/tools/log" -) - -func New(cache cache.S3Cache, impl s3.Interface) *Controller { - return &Controller{ - cache: cache, - impl: impl, - } -} - -type Controller struct { - cache cache.S3Cache - impl s3.Interface -} - -func (c *Controller) Engine() string { - return c.impl.Engine() -} - -func (c *Controller) HashPath(md5 string) string { - return path.Join(hashPath, md5) -} - -func (c *Controller) NowPath() string { - now := time.Now() - return path.Join( - fmt.Sprintf("%04d", now.Year()), - fmt.Sprintf("%02d", now.Month()), - fmt.Sprintf("%02d", now.Day()), - fmt.Sprintf("%02d", now.Hour()), - fmt.Sprintf("%02d", now.Minute()), - fmt.Sprintf("%02d", now.Second()), - ) -} - -func (c *Controller) UUID() string { - id := uuid.New() - return hex.EncodeToString(id[:]) -} - -func (c *Controller) PartSize(ctx context.Context, size int64) (int64, error) { - return c.impl.PartSize(ctx, size) -} - -func (c *Controller) PartLimit() *s3.PartLimit { - return c.impl.PartLimit() -} - -func (c *Controller) StatObject(ctx context.Context, name string) (*s3.ObjectInfo, error) { - return c.cache.GetKey(ctx, c.impl.Engine(), name) -} - -func (c *Controller) GetHashObject(ctx context.Context, hash string) (*s3.ObjectInfo, error) { - return c.StatObject(ctx, c.HashPath(hash)) -} - -func (c *Controller) InitiateUpload(ctx context.Context, hash string, size int64, expire time.Duration, maxParts int) (*InitiateUploadResult, error) { - defer log.ZDebug(ctx, "return") - if size < 0 { - return nil, errors.New("invalid size") - } - if hashBytes, err := hex.DecodeString(hash); err != nil { - return nil, err - } else if len(hashBytes) != md5.Size { - return nil, errors.New("invalid md5") - } - partSize, err := c.impl.PartSize(ctx, size) - if err != nil { - return nil, err - } - partNumber := int(size / partSize) - if size%partSize > 0 { - partNumber++ - } - if maxParts > 0 && partNumber > 0 && partNumber < maxParts { - return nil, fmt.Errorf("too many parts: %d", partNumber) - } - if info, err := c.StatObject(ctx, c.HashPath(hash)); err == nil { - return nil, &HashAlreadyExistsError{Object: info} - } else if !c.impl.IsNotFound(err) { - return nil, err - } - if size <= partSize { - // Pre-signed upload - key := path.Join(tempPath, c.NowPath(), fmt.Sprintf("%s_%d_%s.presigned", hash, size, c.UUID())) - rawURL, err := c.impl.PresignedPutObject(ctx, key, expire) - if err != nil { - return nil, err - } - return &InitiateUploadResult{ - UploadID: newMultipartUploadID(multipartUploadID{ - Type: UploadTypePresigned, - ID: "", - Key: key, - Size: size, - Hash: hash, - }), - PartSize: partSize, - Sign: &s3.AuthSignResult{ - Parts: []s3.SignPart{ - { - PartNumber: 1, - URL: rawURL, - }, - }, - }, - }, nil - } else { - // Fragment upload - upload, err := c.impl.InitiateMultipartUpload(ctx, c.HashPath(hash)) - if err != nil { - return nil, err - } - if maxParts < 0 { - maxParts = partNumber - } - var authSign *s3.AuthSignResult - if maxParts > 0 { - partNumbers := make([]int, maxParts) - for i := 0; i < maxParts; i++ { - partNumbers[i] = i + 1 - } - authSign, err = c.impl.AuthSign(ctx, upload.UploadID, upload.Key, time.Hour*24, partNumbers) - if err != nil { - return nil, err - } - } - return &InitiateUploadResult{ - UploadID: newMultipartUploadID(multipartUploadID{ - Type: UploadTypeMultipart, - ID: upload.UploadID, - Key: upload.Key, - Size: size, - Hash: hash, - }), - PartSize: partSize, - Sign: authSign, - }, nil - } -} - -func (c *Controller) CompleteUpload(ctx context.Context, uploadID string, partHashs []string) (*UploadResult, error) { - defer log.ZDebug(ctx, "return") - upload, err := parseMultipartUploadID(uploadID) - if err != nil { - return nil, err - } - if md5Sum := md5.Sum([]byte(strings.Join(partHashs, partSeparator))); hex.EncodeToString(md5Sum[:]) != upload.Hash { - return nil, errors.New("md5 mismatching") - } - if info, err := c.StatObject(ctx, c.HashPath(upload.Hash)); err == nil { - return &UploadResult{ - Key: info.Key, - Size: info.Size, - Hash: info.ETag, - }, nil - } else if !c.IsNotFound(err) { - return nil, err - } - cleanObject := make(map[string]struct{}) - defer func() { - for key := range cleanObject { - _ = c.impl.DeleteObject(ctx, key) - } - }() - var targetKey string - switch upload.Type { - case UploadTypeMultipart: - parts := make([]s3.Part, len(partHashs)) - for i, part := range partHashs { - parts[i] = s3.Part{ - PartNumber: i + 1, - ETag: part, - } - } - // todo: Validation size - result, err := c.impl.CompleteMultipartUpload(ctx, upload.ID, upload.Key, parts) - if err != nil { - return nil, err - } - targetKey = result.Key - case UploadTypePresigned: - uploadInfo, err := c.StatObject(ctx, upload.Key) - if err != nil { - return nil, err - } - cleanObject[uploadInfo.Key] = struct{}{} - if uploadInfo.Size != upload.Size { - return nil, errors.New("upload size mismatching") - } - md5Sum := md5.Sum([]byte(strings.Join([]string{uploadInfo.ETag}, partSeparator))) - if md5val := hex.EncodeToString(md5Sum[:]); md5val != upload.Hash { - return nil, errs.ErrArgs.WrapMsg(fmt.Sprintf("md5 mismatching %s != %s", md5val, upload.Hash)) - } - // Prevents concurrent operations at this time that cause files to be overwritten - copyInfo, err := c.impl.CopyObject(ctx, uploadInfo.Key, upload.Key+"."+c.UUID()) - if err != nil { - return nil, err - } - cleanObject[copyInfo.Key] = struct{}{} - if copyInfo.ETag != uploadInfo.ETag { - return nil, errors.New("[concurrency]copy md5 mismatching") - } - hashCopyInfo, err := c.impl.CopyObject(ctx, copyInfo.Key, c.HashPath(upload.Hash)) - if err != nil { - return nil, err - } - log.ZInfo(ctx, "hashCopyInfo", "value", fmt.Sprintf("%+v", hashCopyInfo)) - targetKey = hashCopyInfo.Key - default: - return nil, errors.New("invalid upload id type") - } - if err := c.cache.DelS3Key(c.impl.Engine(), targetKey).ExecDel(ctx); err != nil { - return nil, err - } - return &UploadResult{ - Key: targetKey, - Size: upload.Size, - Hash: upload.Hash, - }, nil -} - -func (c *Controller) AuthSign(ctx context.Context, uploadID string, partNumbers []int) (*s3.AuthSignResult, error) { - upload, err := parseMultipartUploadID(uploadID) - if err != nil { - return nil, err - } - switch upload.Type { - case UploadTypeMultipart: - return c.impl.AuthSign(ctx, upload.ID, upload.Key, time.Hour*24, partNumbers) - case UploadTypePresigned: - return nil, errors.New("presigned id not support auth sign") - default: - return nil, errors.New("invalid upload id type") - } -} - -func (c *Controller) IsNotFound(err error) bool { - return c.impl.IsNotFound(err) || errs.ErrRecordNotFound.Is(err) -} - -func (c *Controller) AccessURL(ctx context.Context, name string, expire time.Duration, opt *s3.AccessURLOption) (string, error) { - if opt.Image != nil { - opt.Filename = "" - opt.ContentType = "" - } - return c.impl.AccessURL(ctx, name, expire, opt) -} - -func (c *Controller) FormData(ctx context.Context, name string, size int64, contentType string, duration time.Duration) (*s3.FormData, error) { - return c.impl.FormData(ctx, name, size, contentType, duration) -} diff --git a/pkg/common/db/s3/cont/doc.go b/pkg/common/db/s3/cont/doc.go deleted file mode 100644 index 16138316f..000000000 --- a/pkg/common/db/s3/cont/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright © 2024 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cont // import "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/cont" diff --git a/pkg/common/db/s3/cont/error.go b/pkg/common/db/s3/cont/error.go deleted file mode 100644 index 8225274d3..000000000 --- a/pkg/common/db/s3/cont/error.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cont - -import ( - "fmt" - - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" -) - -type HashAlreadyExistsError struct { - Object *s3.ObjectInfo -} - -func (e *HashAlreadyExistsError) Error() string { - return fmt.Sprintf("hash already exists: %s", e.Object.Key) -} diff --git a/pkg/common/db/s3/cont/id.go b/pkg/common/db/s3/cont/id.go deleted file mode 100644 index 47f37d4aa..000000000 --- a/pkg/common/db/s3/cont/id.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cont - -import ( - "encoding/base64" - "encoding/json" - "fmt" -) - -type multipartUploadID struct { - Type int `json:"a,omitempty"` - ID string `json:"b,omitempty"` - Key string `json:"c,omitempty"` - Size int64 `json:"d,omitempty"` - Hash string `json:"e,omitempty"` -} - -func newMultipartUploadID(id multipartUploadID) string { - data, err := json.Marshal(id) - if err != nil { - panic(err) - } - return base64.StdEncoding.EncodeToString(data) -} - -func parseMultipartUploadID(id string) (*multipartUploadID, error) { - data, err := base64.StdEncoding.DecodeString(id) - if err != nil { - return nil, fmt.Errorf("invalid multipart upload id: %w", err) - } - var upload multipartUploadID - if err := json.Unmarshal(data, &upload); err != nil { - return nil, fmt.Errorf("invalid multipart upload id: %w", err) - } - return &upload, nil -} diff --git a/pkg/common/db/s3/cont/structs.go b/pkg/common/db/s3/cont/structs.go deleted file mode 100644 index de484cc5f..000000000 --- a/pkg/common/db/s3/cont/structs.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cont - -import "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" - -type InitiateUploadResult struct { - // UploadID uniquely identifies the upload session for tracking and management purposes. - UploadID string `json:"uploadID"` - - // PartSize specifies the size of each part in a multipart upload. This is relevant for breaking down large uploads into manageable pieces. - PartSize int64 `json:"partSize"` - - // Sign contains the authentication and signature information necessary for securely uploading each part. This could include signed URLs or tokens. - Sign *s3.AuthSignResult `json:"sign"` -} - -type UploadResult struct { - Hash string `json:"hash"` - Size int64 `json:"size"` - Key string `json:"key"` -} diff --git a/pkg/common/db/s3/cos/cos.go b/pkg/common/db/s3/cos/cos.go deleted file mode 100644 index 1ee17173e..000000000 --- a/pkg/common/db/s3/cos/cos.go +++ /dev/null @@ -1,400 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cos - -import ( - "context" - "crypto/hmac" - "crypto/sha1" - "encoding/base64" - "encoding/hex" - "encoding/json" - "errors" - "fmt" - "net/http" - "net/url" - "strconv" - "strings" - "time" - - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" - "github.com/openimsdk/tools/errs" - "github.com/tencentyun/cos-go-sdk-v5" -) - -const ( - minPartSize int64 = 1024 * 1024 * 1 // 1MB - maxPartSize int64 = 1024 * 1024 * 1024 * 5 // 5GB - maxNumSize int64 = 1000 -) - -const ( - imagePng = "png" - imageJpg = "jpg" - imageJpeg = "jpeg" - imageGif = "gif" - imageWebp = "webp" -) - -const successCode = http.StatusOK - -type Config struct { - BucketURL string - SecretID string - SecretKey string - SessionToken string - PublicRead bool -} - -func NewCos(conf Config) (s3.Interface, error) { - u, err := url.Parse(conf.BucketURL) - if err != nil { - panic(err) - } - client := cos.NewClient(&cos.BaseURL{BucketURL: u}, &http.Client{ - Transport: &cos.AuthorizationTransport{ - SecretID: conf.SecretID, - SecretKey: conf.SecretKey, - SessionToken: conf.SessionToken, - }, - }) - return &Cos{ - publicRead: conf.PublicRead, - copyURL: u.Host + "/", - client: client, - credential: client.GetCredential(), - }, nil -} - -type Cos struct { - publicRead bool - copyURL string - client *cos.Client - credential *cos.Credential -} - -func (c *Cos) Engine() string { - return "tencent-cos" -} - -func (c *Cos) PartLimit() *s3.PartLimit { - return &s3.PartLimit{ - MinPartSize: minPartSize, - MaxPartSize: maxPartSize, - MaxNumSize: maxNumSize, - } -} - -func (c *Cos) InitiateMultipartUpload(ctx context.Context, name string) (*s3.InitiateMultipartUploadResult, error) { - result, _, err := c.client.Object.InitiateMultipartUpload(ctx, name, nil) - if err != nil { - return nil, err - } - return &s3.InitiateMultipartUploadResult{ - UploadID: result.UploadID, - Bucket: result.Bucket, - Key: result.Key, - }, nil -} - -func (c *Cos) CompleteMultipartUpload(ctx context.Context, uploadID string, name string, parts []s3.Part) (*s3.CompleteMultipartUploadResult, error) { - opts := &cos.CompleteMultipartUploadOptions{ - Parts: make([]cos.Object, len(parts)), - } - for i, part := range parts { - opts.Parts[i] = cos.Object{ - PartNumber: part.PartNumber, - ETag: strings.ReplaceAll(part.ETag, `"`, ``), - } - } - result, _, err := c.client.Object.CompleteMultipartUpload(ctx, name, uploadID, opts) - if err != nil { - return nil, err - } - return &s3.CompleteMultipartUploadResult{ - Location: result.Location, - Bucket: result.Bucket, - Key: result.Key, - ETag: result.ETag, - }, nil -} - -func (c *Cos) PartSize(ctx context.Context, size int64) (int64, error) { - if size <= 0 { - return 0, errors.New("size must be greater than 0") - } - if size > maxPartSize*maxNumSize { - return 0, fmt.Errorf("COS size must be less than the maximum allowed limit") - } - if size <= minPartSize*maxNumSize { - return minPartSize, nil - } - partSize := size / maxNumSize - if size%maxNumSize != 0 { - partSize++ - } - return partSize, nil -} - -func (c *Cos) AuthSign(ctx context.Context, uploadID string, name string, expire time.Duration, partNumbers []int) (*s3.AuthSignResult, error) { - result := s3.AuthSignResult{ - URL: c.client.BaseURL.BucketURL.String() + "/" + cos.EncodeURIComponent(name), - Query: url.Values{"uploadId": {uploadID}}, - Header: make(http.Header), - Parts: make([]s3.SignPart, len(partNumbers)), - } - req, err := http.NewRequestWithContext(ctx, http.MethodPut, result.URL, nil) - if err != nil { - return nil, err - } - cos.AddAuthorizationHeader(c.credential.SecretID, c.credential.SecretKey, c.credential.SessionToken, req, cos.NewAuthTime(expire)) - result.Header = req.Header - for i, partNumber := range partNumbers { - result.Parts[i] = s3.SignPart{ - PartNumber: partNumber, - Query: url.Values{"partNumber": {strconv.Itoa(partNumber)}}, - } - } - return &result, nil -} - -func (c *Cos) PresignedPutObject(ctx context.Context, name string, expire time.Duration) (string, error) { - rawURL, err := c.client.Object.GetPresignedURL(ctx, http.MethodPut, name, c.credential.SecretID, c.credential.SecretKey, expire, nil) - if err != nil { - return "", err - } - return rawURL.String(), nil -} - -func (c *Cos) DeleteObject(ctx context.Context, name string) error { - _, err := c.client.Object.Delete(ctx, name) - return err -} - -func (c *Cos) StatObject(ctx context.Context, name string) (*s3.ObjectInfo, error) { - if name != "" && name[0] == '/' { - name = name[1:] - } - info, err := c.client.Object.Head(ctx, name, nil) - if err != nil { - return nil, err - } - res := &s3.ObjectInfo{Key: name} - if res.ETag = strings.ToLower(strings.ReplaceAll(info.Header.Get("ETag"), `"`, "")); res.ETag == "" { - return nil, errors.New("StatObject etag not found") - } - if contentLengthStr := info.Header.Get("Content-Length"); contentLengthStr == "" { - return nil, errors.New("StatObject content-length not found") - } else { - res.Size, err = strconv.ParseInt(contentLengthStr, 10, 64) - if err != nil { - return nil, fmt.Errorf("StatObject content-length parse error: %w", err) - } - if res.Size < 0 { - return nil, errors.New("StatObject content-length must be greater than 0") - } - } - if lastModified := info.Header.Get("Last-Modified"); lastModified == "" { - return nil, errors.New("StatObject last-modified not found") - } else { - res.LastModified, err = time.Parse(http.TimeFormat, lastModified) - if err != nil { - return nil, fmt.Errorf("StatObject last-modified parse error: %w", err) - } - } - return res, nil -} - -func (c *Cos) CopyObject(ctx context.Context, src string, dst string) (*s3.CopyObjectInfo, error) { - sourceURL := c.copyURL + src - result, _, err := c.client.Object.Copy(ctx, dst, sourceURL, nil) - if err != nil { - return nil, err - } - return &s3.CopyObjectInfo{ - Key: dst, - ETag: strings.ReplaceAll(result.ETag, `"`, ``), - }, nil -} - -func (c *Cos) IsNotFound(err error) bool { - switch e := errs.Unwrap(err).(type) { - case *cos.ErrorResponse: - return e.Response.StatusCode == http.StatusNotFound || e.Code == "NoSuchKey" - default: - return false - } -} - -func (c *Cos) AbortMultipartUpload(ctx context.Context, uploadID string, name string) error { - _, err := c.client.Object.AbortMultipartUpload(ctx, name, uploadID) - return err -} - -func (c *Cos) ListUploadedParts(ctx context.Context, uploadID string, name string, partNumberMarker int, maxParts int) (*s3.ListUploadedPartsResult, error) { - result, _, err := c.client.Object.ListParts(ctx, name, uploadID, &cos.ObjectListPartsOptions{ - MaxParts: strconv.Itoa(maxParts), - PartNumberMarker: strconv.Itoa(partNumberMarker), - }) - if err != nil { - return nil, err - } - res := &s3.ListUploadedPartsResult{ - Key: result.Key, - UploadID: result.UploadID, - UploadedParts: make([]s3.UploadedPart, len(result.Parts)), - } - res.MaxParts, _ = strconv.Atoi(result.MaxParts) - res.NextPartNumberMarker, _ = strconv.Atoi(result.NextPartNumberMarker) - for i, part := range result.Parts { - lastModified, _ := time.Parse(http.TimeFormat, part.LastModified) - res.UploadedParts[i] = s3.UploadedPart{ - PartNumber: part.PartNumber, - LastModified: lastModified, - ETag: part.ETag, - Size: part.Size, - } - } - return res, nil -} - -func (c *Cos) AccessURL(ctx context.Context, name string, expire time.Duration, opt *s3.AccessURLOption) (string, error) { - var imageMogr string - var option cos.PresignedURLOptions - if opt != nil { - query := make(url.Values) - if opt.Image != nil { - // https://cloud.tencent.com/document/product/436/44880 - style := make([]string, 0, 2) - wh := make([]string, 2) - if opt.Image.Width > 0 { - wh[0] = strconv.Itoa(opt.Image.Width) - } - if opt.Image.Height > 0 { - wh[1] = strconv.Itoa(opt.Image.Height) - } - if opt.Image.Width > 0 || opt.Image.Height > 0 { - style = append(style, strings.Join(wh, "x")) - } - switch opt.Image.Format { - case - imagePng, - imageJpg, - imageJpeg, - imageGif, - imageWebp: - style = append(style, "format/"+opt.Image.Format) - } - if len(style) > 0 { - imageMogr = "imageMogr2/thumbnail/" + strings.Join(style, "/") + "/ignore-error/1" - } - } - if opt.ContentType != "" { - query.Set("response-content-type", opt.ContentType) - } - if opt.Filename != "" { - query.Set("response-content-disposition", `attachment; filename=`+strconv.Quote(opt.Filename)) - } - if len(query) > 0 { - option.Query = &query - } - } - if expire <= 0 { - expire = time.Hour * 24 * 365 * 99 // 99 years - } else if expire < time.Second { - expire = time.Second - } - rawURL, err := c.getPresignedURL(ctx, name, expire, &option) - if err != nil { - return "", err - } - if imageMogr != "" { - if rawURL.RawQuery == "" { - rawURL.RawQuery = imageMogr - } else { - rawURL.RawQuery = rawURL.RawQuery + "&" + imageMogr - } - } - return rawURL.String(), nil -} - -func (c *Cos) getPresignedURL(ctx context.Context, name string, expire time.Duration, opt *cos.PresignedURLOptions) (*url.URL, error) { - if !c.publicRead { - return c.client.Object.GetPresignedURL(ctx, http.MethodGet, name, c.credential.SecretID, c.credential.SecretKey, expire, opt) - } - return c.client.Object.GetObjectURL(name), nil -} - -func (c *Cos) FormData(ctx context.Context, name string, size int64, contentType string, duration time.Duration) (*s3.FormData, error) { - // https://cloud.tencent.com/document/product/436/14690 - now := time.Now() - expiration := now.Add(duration) - keyTime := fmt.Sprintf("%d;%d", now.Unix(), expiration.Unix()) - conditions := []any{ - map[string]string{"q-sign-algorithm": "sha1"}, - map[string]string{"q-ak": c.credential.SecretID}, - map[string]string{"q-sign-time": keyTime}, - map[string]string{"key": name}, - } - if contentType != "" { - conditions = append(conditions, map[string]string{"Content-Type": contentType}) - } - policy := map[string]any{ - "expiration": expiration.Format("2006-01-02T15:04:05.000Z"), - "conditions": conditions, - } - policyJson, err := json.Marshal(policy) - if err != nil { - return nil, err - } - signKey := hmacSha1val(c.credential.SecretKey, keyTime) - strToSign := sha1val(string(policyJson)) - signature := hmacSha1val(signKey, strToSign) - - fd := &s3.FormData{ - URL: c.client.BaseURL.BucketURL.String(), - File: "file", - Expires: expiration, - FormData: map[string]string{ - "policy": base64.StdEncoding.EncodeToString(policyJson), - "q-sign-algorithm": "sha1", - "q-ak": c.credential.SecretID, - "q-key-time": keyTime, - "q-signature": signature, - "key": name, - "success_action_status": strconv.Itoa(successCode), - }, - SuccessCodes: []int{successCode}, - } - if contentType != "" { - fd.FormData["Content-Type"] = contentType - } - if c.credential.SessionToken != "" { - fd.FormData["x-cos-security-token"] = c.credential.SessionToken - } - return fd, nil -} - -func hmacSha1val(key, msg string) string { - v := hmac.New(sha1.New, []byte(key)) - v.Write([]byte(msg)) - return hex.EncodeToString(v.Sum(nil)) -} - -func sha1val(msg string) string { - sha1Hash := sha1.New() - sha1Hash.Write([]byte(msg)) - return hex.EncodeToString(sha1Hash.Sum(nil)) -} diff --git a/pkg/common/db/s3/cos/doc.go b/pkg/common/db/s3/cos/doc.go deleted file mode 100644 index fdf0ecab0..000000000 --- a/pkg/common/db/s3/cos/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright © 2024 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cos // import "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/cos" diff --git a/pkg/common/db/s3/cos/internal.go b/pkg/common/db/s3/cos/internal.go deleted file mode 100644 index 064546953..000000000 --- a/pkg/common/db/s3/cos/internal.go +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cos - -import ( - "context" - "net/http" - "net/url" - _ "unsafe" - - "github.com/tencentyun/cos-go-sdk-v5" -) - -//go:linkname newRequest github.com/tencentyun/cos-go-sdk-v5.(*Client).newRequest -func newRequest(c *cos.Client, ctx context.Context, baseURL *url.URL, uri, method string, body any, optQuery any, optHeader any) (req *http.Request, err error) diff --git a/pkg/common/db/s3/doc.go b/pkg/common/db/s3/doc.go deleted file mode 100644 index 4b7f4fc3e..000000000 --- a/pkg/common/db/s3/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright © 2024 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package s3 // import "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" diff --git a/pkg/common/db/s3/minio/doc.go b/pkg/common/db/s3/minio/doc.go deleted file mode 100644 index b7db5e05f..000000000 --- a/pkg/common/db/s3/minio/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright © 2024 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package minio // import "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/minio" diff --git a/pkg/common/db/s3/minio/image.go b/pkg/common/db/s3/minio/image.go deleted file mode 100644 index 3223993f4..000000000 --- a/pkg/common/db/s3/minio/image.go +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package minio - -import ( - "image" - _ "image/gif" - _ "image/jpeg" - _ "image/png" - "io" - - _ "golang.org/x/image/bmp" - _ "golang.org/x/image/tiff" - _ "golang.org/x/image/webp" -) - -const ( - formatPng = "png" - formatJpeg = "jpeg" - formatJpg = "jpg" - formatGif = "gif" -) - -func ImageStat(reader io.Reader) (image.Image, string, error) { - return image.Decode(reader) -} - -func ImageWidthHeight(img image.Image) (int, int) { - bounds := img.Bounds().Max - return bounds.X, bounds.Y -} - -func resizeImage(img image.Image, maxWidth, maxHeight int) image.Image { - bounds := img.Bounds() - imgWidth := bounds.Max.X - imgHeight := bounds.Max.Y - - // Calculating scaling - scaleWidth := float64(maxWidth) / float64(imgWidth) - scaleHeight := float64(maxHeight) / float64(imgHeight) - - // If both are 0, then no scaling is done and the original image is returned - if maxWidth == 0 && maxHeight == 0 { - return img - } - - // If both width and height are greater than 0, select a smaller zoom ratio to maintain the aspect ratio - if maxWidth > 0 && maxHeight > 0 { - scale := scaleWidth - if scaleHeight < scaleWidth { - scale = scaleHeight - } - - // Calculate Thumbnail Size - thumbnailWidth := int(float64(imgWidth) * scale) - thumbnailHeight := int(float64(imgHeight) * scale) - - // Thumbnails are generated using the Resample method of the "image" library. - thumbnail := image.NewRGBA(image.Rect(0, 0, thumbnailWidth, thumbnailHeight)) - for y := 0; y < thumbnailHeight; y++ { - for x := 0; x < thumbnailWidth; x++ { - srcX := int(float64(x) / scale) - srcY := int(float64(y) / scale) - thumbnail.Set(x, y, img.At(srcX, srcY)) - } - } - - return thumbnail - } - - // If only width or height is specified, thumbnails are generated based on the maximum not to exceed rule - if maxWidth > 0 { - thumbnailWidth := maxWidth - thumbnailHeight := int(float64(imgHeight) * scaleWidth) - - // Thumbnails are generated using the Resample method of the "image" library. - thumbnail := image.NewRGBA(image.Rect(0, 0, thumbnailWidth, thumbnailHeight)) - for y := 0; y < thumbnailHeight; y++ { - for x := 0; x < thumbnailWidth; x++ { - srcX := int(float64(x) / scaleWidth) - srcY := int(float64(y) / scaleWidth) - thumbnail.Set(x, y, img.At(srcX, srcY)) - } - } - - return thumbnail - } - - if maxHeight > 0 { - thumbnailWidth := int(float64(imgWidth) * scaleHeight) - thumbnailHeight := maxHeight - - // Thumbnails are generated using the Resample method of the "image" library. - thumbnail := image.NewRGBA(image.Rect(0, 0, thumbnailWidth, thumbnailHeight)) - for y := 0; y < thumbnailHeight; y++ { - for x := 0; x < thumbnailWidth; x++ { - srcX := int(float64(x) / scaleHeight) - srcY := int(float64(y) / scaleHeight) - thumbnail.Set(x, y, img.At(srcX, srcY)) - } - } - - return thumbnail - } - - // By default, the original image is returned - return img -} diff --git a/pkg/common/db/s3/minio/internal.go b/pkg/common/db/s3/minio/internal.go deleted file mode 100644 index 7e9dcd9e4..000000000 --- a/pkg/common/db/s3/minio/internal.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package minio - -import ( - "net/url" - _ "unsafe" - - "github.com/minio/minio-go/v7" -) - -//go:linkname makeTargetURL github.com/minio/minio-go/v7.(*Client).makeTargetURL -func makeTargetURL(client *minio.Client, bucketName, objectName, bucketLocation string, isVirtualHostStyle bool, queryValues url.Values) (*url.URL, error) diff --git a/pkg/common/db/s3/minio/minio.go b/pkg/common/db/s3/minio/minio.go deleted file mode 100644 index 43214d991..000000000 --- a/pkg/common/db/s3/minio/minio.go +++ /dev/null @@ -1,499 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package minio - -import ( - "context" - "errors" - "fmt" - "io" - "net/http" - "net/url" - "path" - "reflect" - "strconv" - "strings" - "sync" - "time" - "unsafe" - - "github.com/minio/minio-go/v7" - "github.com/minio/minio-go/v7/pkg/credentials" - "github.com/minio/minio-go/v7/pkg/signer" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" - "github.com/openimsdk/tools/errs" - "github.com/openimsdk/tools/log" -) - -const ( - unsignedPayload = "UNSIGNED-PAYLOAD" -) - -const ( - minPartSize int64 = 1024 * 1024 * 5 // 5MB - maxPartSize int64 = 1024 * 1024 * 1024 * 5 // 5GB - maxNumSize int64 = 10000 -) - -const ( - maxImageWidth = 1024 - maxImageHeight = 1024 - maxImageSize = 1024 * 1024 * 50 - imageThumbnailPath = "openim/thumbnail" -) - -const successCode = http.StatusOK - -type Config struct { - Bucket string - Endpoint string - AccessKeyID string - SecretAccessKey string - SessionToken string - SignEndpoint string - PublicRead bool -} - -func NewMinio(cache cache.MinioCache, conf Config) (s3.Interface, error) { - u, err := url.Parse(conf.Endpoint) - if err != nil { - return nil, err - } - opts := &minio.Options{ - Creds: credentials.NewStaticV4(conf.AccessKeyID, conf.SecretAccessKey, conf.SessionToken), - Secure: u.Scheme == "https", - } - client, err := minio.New(u.Host, opts) - if err != nil { - return nil, err - } - m := &Minio{ - conf: conf, - bucket: conf.Bucket, - core: &minio.Core{Client: client}, - lock: &sync.Mutex{}, - init: false, - cache: cache, - } - if conf.SignEndpoint == "" || conf.SignEndpoint == conf.Endpoint { - m.opts = opts - m.sign = m.core.Client - m.prefix = u.Path - u.Path = "" - conf.Endpoint = u.String() - m.signEndpoint = conf.Endpoint - } else { - su, err := url.Parse(conf.SignEndpoint) - if err != nil { - return nil, err - } - m.opts = &minio.Options{ - Creds: credentials.NewStaticV4(conf.AccessKeyID, conf.SecretAccessKey, conf.SessionToken), - Secure: su.Scheme == "https", - } - m.sign, err = minio.New(su.Host, m.opts) - if err != nil { - return nil, err - } - m.prefix = su.Path - su.Path = "" - conf.SignEndpoint = su.String() - m.signEndpoint = conf.SignEndpoint - } - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - if err := m.initMinio(ctx); err != nil { - fmt.Println("init minio error:", err) - } - return m, nil -} - -type Minio struct { - conf Config - bucket string - signEndpoint string - location string - opts *minio.Options - core *minio.Core - sign *minio.Client - lock sync.Locker - init bool - prefix string - cache cache.MinioCache -} - -func (m *Minio) initMinio(ctx context.Context) error { - if m.init { - return nil - } - m.lock.Lock() - defer m.lock.Unlock() - if m.init { - return nil - } - exists, err := m.core.Client.BucketExists(ctx, m.conf.Bucket) - if err != nil { - return fmt.Errorf("check bucket exists error: %w", err) - } - if !exists { - if err = m.core.Client.MakeBucket(ctx, m.conf.Bucket, minio.MakeBucketOptions{}); err != nil { - return fmt.Errorf("make bucket error: %w", err) - } - } - if m.conf.PublicRead { - policy := fmt.Sprintf( - `{"Version": "2012-10-17","Statement": [{"Action": ["s3:GetObject","s3:PutObject"],"Effect": "Allow","Principal": {"AWS": ["*"]},"Resource": ["arn:aws:s3:::%s/*"],"Sid": ""}]}`, - m.conf.Bucket, - ) - if err = m.core.Client.SetBucketPolicy(ctx, m.conf.Bucket, policy); err != nil { - return err - } - } - m.location, err = m.core.Client.GetBucketLocation(ctx, m.conf.Bucket) - if err != nil { - return err - } - func() { - if m.conf.SignEndpoint == "" || m.conf.SignEndpoint == m.conf.Endpoint { - return - } - defer func() { - if r := recover(); r != nil { - m.sign = m.core.Client - log.ZWarn( - context.Background(), - "set sign bucket location cache panic", - errors.New("failed to get private field value"), - "recover", - fmt.Sprintf("%+v", r), - "development version", - "github.com/minio/minio-go/v7 v7.0.61", - ) - } - }() - blc := reflect.ValueOf(m.sign).Elem().FieldByName("bucketLocCache") - vblc := reflect.New(reflect.PtrTo(blc.Type())) - *(*unsafe.Pointer)(vblc.UnsafePointer()) = unsafe.Pointer(blc.UnsafeAddr()) - vblc.Elem().Elem().Interface().(interface{ Set(string, string) }).Set(m.conf.Bucket, m.location) - }() - m.init = true - return nil -} - -func (m *Minio) Engine() string { - return "minio" -} - -func (m *Minio) PartLimit() *s3.PartLimit { - return &s3.PartLimit{ - MinPartSize: minPartSize, - MaxPartSize: maxPartSize, - MaxNumSize: maxNumSize, - } -} - -func (m *Minio) InitiateMultipartUpload(ctx context.Context, name string) (*s3.InitiateMultipartUploadResult, error) { - if err := m.initMinio(ctx); err != nil { - return nil, err - } - uploadID, err := m.core.NewMultipartUpload(ctx, m.bucket, name, minio.PutObjectOptions{}) - if err != nil { - return nil, err - } - return &s3.InitiateMultipartUploadResult{ - Bucket: m.bucket, - Key: name, - UploadID: uploadID, - }, nil -} - -func (m *Minio) CompleteMultipartUpload(ctx context.Context, uploadID string, name string, parts []s3.Part) (*s3.CompleteMultipartUploadResult, error) { - if err := m.initMinio(ctx); err != nil { - return nil, err - } - minioParts := make([]minio.CompletePart, len(parts)) - for i, part := range parts { - minioParts[i] = minio.CompletePart{ - PartNumber: part.PartNumber, - ETag: strings.ToLower(part.ETag), - } - } - upload, err := m.core.CompleteMultipartUpload(ctx, m.bucket, name, uploadID, minioParts, minio.PutObjectOptions{}) - if err != nil { - return nil, err - } - m.delObjectImageInfoKey(ctx, name, upload.Size) - return &s3.CompleteMultipartUploadResult{ - Location: upload.Location, - Bucket: upload.Bucket, - Key: upload.Key, - ETag: strings.ToLower(upload.ETag), - }, nil -} - -func (m *Minio) PartSize(ctx context.Context, size int64) (int64, error) { - if size <= 0 { - return 0, errors.New("size must be greater than 0") - } - if size > maxPartSize*maxNumSize { - return 0, fmt.Errorf("MINIO size must be less than the maximum allowed limit") - } - if size <= minPartSize*maxNumSize { - return minPartSize, nil - } - partSize := size / maxNumSize - if size%maxNumSize != 0 { - partSize++ - } - return partSize, nil -} - -func (m *Minio) AuthSign(ctx context.Context, uploadID string, name string, expire time.Duration, partNumbers []int) (*s3.AuthSignResult, error) { - if err := m.initMinio(ctx); err != nil { - return nil, err - } - creds, err := m.opts.Creds.Get() - if err != nil { - return nil, err - } - result := s3.AuthSignResult{ - URL: m.signEndpoint + "/" + m.bucket + "/" + name, - Query: url.Values{"uploadId": {uploadID}}, - Parts: make([]s3.SignPart, len(partNumbers)), - } - for i, partNumber := range partNumbers { - rawURL := result.URL + "?partNumber=" + strconv.Itoa(partNumber) + "&uploadId=" + uploadID - request, err := http.NewRequestWithContext(ctx, http.MethodPut, rawURL, nil) - if err != nil { - return nil, err - } - request.Header.Set("X-Amz-Content-Sha256", unsignedPayload) - request = signer.SignV4Trailer(*request, creds.AccessKeyID, creds.SecretAccessKey, creds.SessionToken, m.location, nil) - result.Parts[i] = s3.SignPart{ - PartNumber: partNumber, - Query: url.Values{"partNumber": {strconv.Itoa(partNumber)}}, - Header: request.Header, - } - } - if m.prefix != "" { - result.URL = m.signEndpoint + m.prefix + "/" + m.bucket + "/" + name - } - return &result, nil -} - -func (m *Minio) PresignedPutObject(ctx context.Context, name string, expire time.Duration) (string, error) { - if err := m.initMinio(ctx); err != nil { - return "", err - } - rawURL, err := m.sign.PresignedPutObject(ctx, m.bucket, name, expire) - if err != nil { - return "", err - } - if m.prefix != "" { - rawURL.Path = path.Join(m.prefix, rawURL.Path) - } - return rawURL.String(), nil -} - -func (m *Minio) DeleteObject(ctx context.Context, name string) error { - if err := m.initMinio(ctx); err != nil { - return err - } - return m.core.Client.RemoveObject(ctx, m.bucket, name, minio.RemoveObjectOptions{}) -} - -func (m *Minio) StatObject(ctx context.Context, name string) (*s3.ObjectInfo, error) { - if err := m.initMinio(ctx); err != nil { - return nil, err - } - info, err := m.core.Client.StatObject(ctx, m.bucket, name, minio.StatObjectOptions{}) - if err != nil { - return nil, err - } - return &s3.ObjectInfo{ - ETag: strings.ToLower(info.ETag), - Key: info.Key, - Size: info.Size, - LastModified: info.LastModified, - }, nil -} - -func (m *Minio) CopyObject(ctx context.Context, src string, dst string) (*s3.CopyObjectInfo, error) { - if err := m.initMinio(ctx); err != nil { - return nil, err - } - result, err := m.core.Client.CopyObject(ctx, minio.CopyDestOptions{ - Bucket: m.bucket, - Object: dst, - }, minio.CopySrcOptions{ - Bucket: m.bucket, - Object: src, - }) - if err != nil { - return nil, err - } - return &s3.CopyObjectInfo{ - Key: dst, - ETag: strings.ToLower(result.ETag), - }, nil -} - -func (m *Minio) IsNotFound(err error) bool { - switch e := errs.Unwrap(err).(type) { - case minio.ErrorResponse: - return e.StatusCode == http.StatusNotFound || e.Code == "NoSuchKey" - case *minio.ErrorResponse: - return e.StatusCode == http.StatusNotFound || e.Code == "NoSuchKey" - default: - return false - } -} - -func (m *Minio) AbortMultipartUpload(ctx context.Context, uploadID string, name string) error { - if err := m.initMinio(ctx); err != nil { - return err - } - return m.core.AbortMultipartUpload(ctx, m.bucket, name, uploadID) -} - -func (m *Minio) ListUploadedParts(ctx context.Context, uploadID string, name string, partNumberMarker int, maxParts int) (*s3.ListUploadedPartsResult, error) { - if err := m.initMinio(ctx); err != nil { - return nil, err - } - result, err := m.core.ListObjectParts(ctx, m.bucket, name, uploadID, partNumberMarker, maxParts) - if err != nil { - return nil, err - } - res := &s3.ListUploadedPartsResult{ - Key: result.Key, - UploadID: result.UploadID, - MaxParts: result.MaxParts, - NextPartNumberMarker: result.NextPartNumberMarker, - UploadedParts: make([]s3.UploadedPart, len(result.ObjectParts)), - } - for i, part := range result.ObjectParts { - res.UploadedParts[i] = s3.UploadedPart{ - PartNumber: part.PartNumber, - LastModified: part.LastModified, - ETag: part.ETag, - Size: part.Size, - } - } - return res, nil -} - -func (m *Minio) PresignedGetObject(ctx context.Context, name string, expire time.Duration, query url.Values) (string, error) { - if expire <= 0 { - expire = time.Hour * 24 * 365 * 99 // 99 years - } else if expire < time.Second { - expire = time.Second - } - var ( - rawURL *url.URL - err error - ) - if m.conf.PublicRead { - rawURL, err = makeTargetURL(m.sign, m.bucket, name, m.location, false, query) - } else { - rawURL, err = m.sign.PresignedGetObject(ctx, m.bucket, name, expire, query) - } - if err != nil { - return "", err - } - if m.prefix != "" { - rawURL.Path = path.Join(m.prefix, rawURL.Path) - } - return rawURL.String(), nil -} - -func (m *Minio) AccessURL(ctx context.Context, name string, expire time.Duration, opt *s3.AccessURLOption) (string, error) { - if err := m.initMinio(ctx); err != nil { - return "", err - } - reqParams := make(url.Values) - if opt != nil { - if opt.ContentType != "" { - reqParams.Set("response-content-type", opt.ContentType) - } - if opt.Filename != "" { - reqParams.Set("response-content-disposition", `attachment; filename=`+strconv.Quote(opt.Filename)) - } - } - if opt.Image == nil || (opt.Image.Width < 0 && opt.Image.Height < 0 && opt.Image.Format == "") || (opt.Image.Width > maxImageWidth || opt.Image.Height > maxImageHeight) { - return m.PresignedGetObject(ctx, name, expire, reqParams) - } - return m.getImageThumbnailURL(ctx, name, expire, opt.Image) -} - -func (m *Minio) getObjectData(ctx context.Context, name string, limit int64) ([]byte, error) { - object, err := m.core.Client.GetObject(ctx, m.bucket, name, minio.GetObjectOptions{}) - if err != nil { - return nil, err - } - defer object.Close() - if limit < 0 { - return io.ReadAll(object) - } - return io.ReadAll(io.LimitReader(object, limit)) -} - -func (m *Minio) FormData(ctx context.Context, name string, size int64, contentType string, duration time.Duration) (*s3.FormData, error) { - if err := m.initMinio(ctx); err != nil { - return nil, err - } - policy := minio.NewPostPolicy() - if err := policy.SetKey(name); err != nil { - return nil, err - } - expires := time.Now().Add(duration) - if err := policy.SetExpires(expires); err != nil { - return nil, err - } - if size > 0 { - if err := policy.SetContentLengthRange(0, size); err != nil { - return nil, err - } - } - if err := policy.SetSuccessStatusAction(strconv.Itoa(successCode)); err != nil { - return nil, err - } - if contentType != "" { - if err := policy.SetContentType(contentType); err != nil { - return nil, err - } - } - if err := policy.SetBucket(m.bucket); err != nil { - return nil, err - } - u, fd, err := m.core.PresignedPostPolicy(ctx, policy) - if err != nil { - return nil, err - } - sign, err := url.Parse(m.signEndpoint) - if err != nil { - return nil, err - } - u.Scheme = sign.Scheme - u.Host = sign.Host - return &s3.FormData{ - URL: u.String(), - File: "file", - Header: nil, - FormData: fd, - Expires: expires, - SuccessCodes: []int{successCode}, - }, nil -} diff --git a/pkg/common/db/s3/minio/thumbnail.go b/pkg/common/db/s3/minio/thumbnail.go deleted file mode 100644 index a6eed4bb5..000000000 --- a/pkg/common/db/s3/minio/thumbnail.go +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package minio - -import ( - "bytes" - "context" - "errors" - "fmt" - "image" - "image/gif" - "image/jpeg" - "image/png" - "net/url" - "path/filepath" - "strings" - "time" - - "github.com/minio/minio-go/v7" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" - "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" - "github.com/openimsdk/tools/log" -) - -func (m *Minio) getImageThumbnailURL(ctx context.Context, name string, expire time.Duration, opt *s3.Image) (string, error) { - var img image.Image - info, err := m.cache.GetImageObjectKeyInfo(ctx, name, func(ctx context.Context) (info *cache.MinioImageInfo, err error) { - info, img, err = m.getObjectImageInfo(ctx, name) - return - }) - if err != nil { - return "", err - } - if !info.IsImg { - return "", servererrs.ErrData.WrapMsg("object not image") - } - if opt.Width > info.Width || opt.Width <= 0 { - opt.Width = info.Width - } - if opt.Height > info.Height || opt.Height <= 0 { - opt.Height = info.Height - } - opt.Format = strings.ToLower(opt.Format) - if opt.Format == formatJpg { - opt.Format = formatJpeg - } - switch opt.Format { - case formatPng, formatJpeg, formatGif: - default: - opt.Format = "" - } - reqParams := make(url.Values) - if opt.Width == info.Width && opt.Height == info.Height && (opt.Format == info.Format || opt.Format == "") { - reqParams.Set("response-content-type", "image/"+info.Format) - return m.PresignedGetObject(ctx, name, expire, reqParams) - } - if opt.Format == "" { - switch opt.Format { - case formatGif: - opt.Format = formatGif - case formatJpeg: - opt.Format = formatJpeg - case formatPng: - opt.Format = formatPng - default: - opt.Format = formatPng - } - } - key, err := m.cache.GetThumbnailKey(ctx, name, opt.Format, opt.Width, opt.Height, func(ctx context.Context) (string, error) { - if img == nil { - var reader *minio.Object - reader, err = m.core.Client.GetObject(ctx, m.bucket, name, minio.GetObjectOptions{}) - if err != nil { - return "", err - } - defer reader.Close() - img, _, err = ImageStat(reader) - if err != nil { - return "", err - } - } - thumbnail := resizeImage(img, opt.Width, opt.Height) - buf := bytes.NewBuffer(nil) - switch opt.Format { - case formatPng: - err = png.Encode(buf, thumbnail) - case formatJpeg: - err = jpeg.Encode(buf, thumbnail, nil) - case formatGif: - err = gif.Encode(buf, thumbnail, nil) - } - cacheKey := filepath.Join(imageThumbnailPath, info.Etag, fmt.Sprintf("image_w%d_h%d.%s", opt.Width, opt.Height, opt.Format)) - if _, err = m.core.Client.PutObject(ctx, m.bucket, cacheKey, buf, int64(buf.Len()), minio.PutObjectOptions{}); err != nil { - return "", err - } - return cacheKey, nil - }) - if err != nil { - return "", err - } - reqParams.Set("response-content-type", "image/"+opt.Format) - return m.PresignedGetObject(ctx, key, expire, reqParams) -} - -func (m *Minio) getObjectImageInfo(ctx context.Context, name string) (*cache.MinioImageInfo, image.Image, error) { - fileInfo, err := m.StatObject(ctx, name) - if err != nil { - return nil, nil, err - } - if fileInfo.Size > maxImageSize { - return nil, nil, errors.New("file size too large") - } - imageData, err := m.getObjectData(ctx, name, fileInfo.Size) - if err != nil { - return nil, nil, err - } - var info cache.MinioImageInfo - imageInfo, format, err := ImageStat(bytes.NewReader(imageData)) - if err == nil { - info.IsImg = true - info.Format = format - info.Width, info.Height = ImageWidthHeight(imageInfo) - } else { - info.IsImg = false - } - info.Etag = fileInfo.ETag - return &info, imageInfo, nil -} - -func (m *Minio) delObjectImageInfoKey(ctx context.Context, key string, size int64) { - if size > 0 && size > maxImageSize { - return - } - if err := m.cache.DelObjectImageInfoKey(key).ExecDel(ctx); err != nil { - log.ZError(ctx, "DelObjectImageInfoKey failed", err, "key", key) - } -} diff --git a/pkg/common/db/s3/oss/doc.go b/pkg/common/db/s3/oss/doc.go deleted file mode 100644 index ff8a13ff9..000000000 --- a/pkg/common/db/s3/oss/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright © 2024 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oss // import "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/oss" diff --git a/pkg/common/db/s3/oss/internal.go b/pkg/common/db/s3/oss/internal.go deleted file mode 100644 index 155708ffd..000000000 --- a/pkg/common/db/s3/oss/internal.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oss - -import ( - "net/http" - "net/url" - _ "unsafe" - - "github.com/aliyun/aliyun-oss-go-sdk/oss" -) - -//go:linkname signHeader github.com/aliyun/aliyun-oss-go-sdk/oss.Conn.signHeader -func signHeader(c oss.Conn, req *http.Request, canonicalizedResource string) - -//go:linkname getURLParams github.com/aliyun/aliyun-oss-go-sdk/oss.Conn.getURLParams -func getURLParams(c oss.Conn, params map[string]any) string - -//go:linkname getURL github.com/aliyun/aliyun-oss-go-sdk/oss.urlMaker.getURL -func getURL(um urlMaker, bucket, object, params string) *url.URL - -type urlMaker struct { - Scheme string - NetLoc string - Type int - IsProxy bool -} diff --git a/pkg/common/db/s3/oss/oss.go b/pkg/common/db/s3/oss/oss.go deleted file mode 100644 index 5ca72fb47..000000000 --- a/pkg/common/db/s3/oss/oss.go +++ /dev/null @@ -1,382 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package oss - -import ( - "context" - "crypto/hmac" - "crypto/sha1" - "encoding/base64" - "encoding/json" - "errors" - "fmt" - "io" - "net/http" - "net/url" - "reflect" - "strconv" - "strings" - "time" - - "github.com/aliyun/aliyun-oss-go-sdk/oss" - "github.com/openimsdk/open-im-server/v3/pkg/common/db/s3" - "github.com/openimsdk/tools/errs" -) - -const ( - minPartSize int64 = 1024 * 1024 * 1 // 1MB - maxPartSize int64 = 1024 * 1024 * 1024 * 5 // 5GB - maxNumSize int64 = 10000 -) - -const ( - imagePng = "png" - imageJpg = "jpg" - imageJpeg = "jpeg" - imageGif = "gif" - imageWebp = "webp" -) - -const successCode = http.StatusOK - -type Config struct { - Endpoint string - Bucket string - BucketURL string - AccessKeyID string - AccessKeySecret string - SessionToken string - PublicRead bool -} - -func NewOSS(conf Config) (s3.Interface, error) { - if conf.BucketURL == "" { - return nil, errs.Wrap(errors.New("bucket url is empty")) - } - client, err := oss.New(conf.Endpoint, conf.AccessKeyID, conf.AccessKeySecret) - if err != nil { - return nil, err - } - bucket, err := client.Bucket(conf.Bucket) - if err != nil { - return nil, errs.WrapMsg(err, "ali-oss bucket error") - } - if conf.BucketURL[len(conf.BucketURL)-1] != '/' { - conf.BucketURL += "/" - } - return &OSS{ - bucketURL: conf.BucketURL, - bucket: bucket, - credentials: client.Config.GetCredentials(), - um: *(*urlMaker)(reflect.ValueOf(bucket.Client.Conn).Elem().FieldByName("url").UnsafePointer()), - publicRead: conf.PublicRead, - }, nil -} - -type OSS struct { - bucketURL string - bucket *oss.Bucket - credentials oss.Credentials - um urlMaker - publicRead bool -} - -func (o *OSS) Engine() string { - return "ali-oss" -} - -func (o *OSS) PartLimit() *s3.PartLimit { - return &s3.PartLimit{ - MinPartSize: minPartSize, - MaxPartSize: maxPartSize, - MaxNumSize: maxNumSize, - } -} - -func (o *OSS) InitiateMultipartUpload(ctx context.Context, name string) (*s3.InitiateMultipartUploadResult, error) { - result, err := o.bucket.InitiateMultipartUpload(name) - if err != nil { - return nil, err - } - return &s3.InitiateMultipartUploadResult{ - UploadID: result.UploadID, - Bucket: result.Bucket, - Key: result.Key, - }, nil -} - -func (o *OSS) CompleteMultipartUpload(ctx context.Context, uploadID string, name string, parts []s3.Part) (*s3.CompleteMultipartUploadResult, error) { - ossParts := make([]oss.UploadPart, len(parts)) - for i, part := range parts { - ossParts[i] = oss.UploadPart{ - PartNumber: part.PartNumber, - ETag: strings.ToUpper(part.ETag), - } - } - result, err := o.bucket.CompleteMultipartUpload(oss.InitiateMultipartUploadResult{ - UploadID: uploadID, - Bucket: o.bucket.BucketName, - Key: name, - }, ossParts) - if err != nil { - return nil, err - } - return &s3.CompleteMultipartUploadResult{ - Location: result.Location, - Bucket: result.Bucket, - Key: result.Key, - ETag: strings.ToLower(strings.ReplaceAll(result.ETag, `"`, ``)), - }, nil -} - -func (o *OSS) PartSize(ctx context.Context, size int64) (int64, error) { - if size <= 0 { - return 0, errs.Wrap(errors.New("size must be greater than 0")) - } - if size > maxPartSize*maxNumSize { - return 0, errs.Wrap(errors.New("size must be less than the maximum allowed limit")) - } - if size <= minPartSize*maxNumSize { - return minPartSize, nil - } - partSize := size / maxNumSize - if size%maxNumSize != 0 { - partSize++ - } - return partSize, nil -} - -func (o *OSS) AuthSign(ctx context.Context, uploadID string, name string, expire time.Duration, partNumbers []int) (*s3.AuthSignResult, error) { - result := s3.AuthSignResult{ - URL: o.bucketURL + name, - Query: url.Values{"uploadId": {uploadID}}, - Header: make(http.Header), - Parts: make([]s3.SignPart, len(partNumbers)), - } - for i, partNumber := range partNumbers { - rawURL := fmt.Sprintf(`%s%s?partNumber=%d&uploadId=%s`, o.bucketURL, name, partNumber, uploadID) - request, err := http.NewRequest(http.MethodPut, rawURL, nil) - if err != nil { - return nil, err - } - if o.credentials.GetSecurityToken() != "" { - request.Header.Set(oss.HTTPHeaderOssSecurityToken, o.credentials.GetSecurityToken()) - } - now := time.Now().UTC().Format(http.TimeFormat) - request.Header.Set(oss.HTTPHeaderHost, request.Host) - request.Header.Set(oss.HTTPHeaderDate, now) - request.Header.Set(oss.HttpHeaderOssDate, now) - signHeader(*o.bucket.Client.Conn, request, fmt.Sprintf(`/%s/%s?partNumber=%d&uploadId=%s`, o.bucket.BucketName, name, partNumber, uploadID)) - delete(request.Header, oss.HTTPHeaderDate) - result.Parts[i] = s3.SignPart{ - PartNumber: partNumber, - Query: url.Values{"partNumber": {strconv.Itoa(partNumber)}}, - URL: request.URL.String(), - Header: request.Header, - } - } - return &result, nil -} - -func (o *OSS) PresignedPutObject(ctx context.Context, name string, expire time.Duration) (string, error) { - return o.bucket.SignURL(name, http.MethodPut, int64(expire/time.Second)) -} - -func (o *OSS) StatObject(ctx context.Context, name string) (*s3.ObjectInfo, error) { - header, err := o.bucket.GetObjectMeta(name) - if err != nil { - return nil, err - } - res := &s3.ObjectInfo{Key: name} - if res.ETag = strings.ToLower(strings.ReplaceAll(header.Get("ETag"), `"`, ``)); res.ETag == "" { - return nil, errs.Wrap(errors.New("StatObject etag not found")) - } - if contentLengthStr := header.Get("Content-Length"); contentLengthStr == "" { - return nil, errors.New("StatObject content-length not found") - } else { - res.Size, err = strconv.ParseInt(contentLengthStr, 10, 64) - if err != nil { - return nil, errs.WrapMsg(err, "StatObject content-length parse error") - } - if res.Size < 0 { - return nil, errs.Wrap(errors.New("StatObject content-length must be greater than 0")) - } - } - if lastModified := header.Get("Last-Modified"); lastModified == "" { - return nil, errs.Wrap(errors.New("StatObject last-modified not found")) - } else { - res.LastModified, err = time.Parse(http.TimeFormat, lastModified) - if err != nil { - return nil, errs.WrapMsg(err, "StatObject last-modified parse error") - } - } - return res, nil -} - -func (o *OSS) DeleteObject(ctx context.Context, name string) error { - return o.bucket.DeleteObject(name) -} - -func (o *OSS) CopyObject(ctx context.Context, src string, dst string) (*s3.CopyObjectInfo, error) { - result, err := o.bucket.CopyObject(src, dst) - if err != nil { - return nil, errs.WrapMsg(err, "CopyObject error") - } - return &s3.CopyObjectInfo{ - Key: dst, - ETag: strings.ToLower(strings.ReplaceAll(result.ETag, `"`, ``)), - }, nil -} - -func (o *OSS) IsNotFound(err error) bool { - switch e := errs.Unwrap(err).(type) { - case oss.ServiceError: - return e.StatusCode == http.StatusNotFound || e.Code == "NoSuchKey" - case *oss.ServiceError: - return e.StatusCode == http.StatusNotFound || e.Code == "NoSuchKey" - default: - return false - } -} - -func (o *OSS) AbortMultipartUpload(ctx context.Context, uploadID string, name string) error { - return o.bucket.AbortMultipartUpload(oss.InitiateMultipartUploadResult{ - UploadID: uploadID, - Key: name, - Bucket: o.bucket.BucketName, - }) -} - -func (o *OSS) ListUploadedParts(ctx context.Context, uploadID string, name string, partNumberMarker int, maxParts int) (*s3.ListUploadedPartsResult, error) { - result, err := o.bucket.ListUploadedParts(oss.InitiateMultipartUploadResult{ - UploadID: uploadID, - Key: name, - Bucket: o.bucket.BucketName, - }, oss.MaxUploads(100), oss.MaxParts(maxParts), oss.PartNumberMarker(partNumberMarker)) - if err != nil { - return nil, errs.WrapMsg(err, "ListUploadedParts error") - } - res := &s3.ListUploadedPartsResult{ - Key: result.Key, - UploadID: result.UploadID, - MaxParts: result.MaxParts, - UploadedParts: make([]s3.UploadedPart, len(result.UploadedParts)), - } - res.NextPartNumberMarker, _ = strconv.Atoi(result.NextPartNumberMarker) - for i, part := range result.UploadedParts { - res.UploadedParts[i] = s3.UploadedPart{ - PartNumber: part.PartNumber, - LastModified: part.LastModified, - ETag: part.ETag, - Size: int64(part.Size), - } - } - return res, nil -} - -func (o *OSS) AccessURL(ctx context.Context, name string, expire time.Duration, opt *s3.AccessURLOption) (string, error) { - var opts []oss.Option - if opt != nil { - if opt.Image != nil { - // Docs Address: https://help.aliyun.com/zh/oss/user-guide/resize-images-4?spm=a2c4g.11186623.0.0.4b3b1e4fWW6yji - var format string - switch opt.Image.Format { - case - imagePng, - imageJpg, - imageJpeg, - imageGif, - imageWebp: - format = opt.Image.Format - default: - opt.Image.Format = imageJpg - } - // https://oss-console-img-demo-cn-hangzhou.oss-cn-hangzhou.aliyuncs.com/example.jpg?x-oss-process=image/resize,h_100,m_lfit - process := "image/resize,m_lfit" - if opt.Image.Width > 0 { - process += ",w_" + strconv.Itoa(opt.Image.Width) - } - if opt.Image.Height > 0 { - process += ",h_" + strconv.Itoa(opt.Image.Height) - } - process += ",format," + format - opts = append(opts, oss.Process(process)) - } - if !o.publicRead { - if opt.ContentType != "" { - opts = append(opts, oss.ResponseContentType(opt.ContentType)) - } - if opt.Filename != "" { - opts = append(opts, oss.ResponseContentDisposition(`attachment; filename=`+strconv.Quote(opt.Filename))) - } - } - } - if expire <= 0 { - expire = time.Hour * 24 * 365 * 99 // 99 years - } else if expire < time.Second { - expire = time.Second - } - if !o.publicRead { - return o.bucket.SignURL(name, http.MethodGet, int64(expire/time.Second), opts...) - } - rawParams, err := oss.GetRawParams(opts) - if err != nil { - return "", errs.WrapMsg(err, "AccessURL error") - } - params := getURLParams(*o.bucket.Client.Conn, rawParams) - return getURL(o.um, o.bucket.BucketName, name, params).String(), nil -} - -func (o *OSS) FormData(ctx context.Context, name string, size int64, contentType string, duration time.Duration) (*s3.FormData, error) { - // https://help.aliyun.com/zh/oss/developer-reference/postobject?spm=a2c4g.11186623.0.0.1cb83cebkP55nn - expires := time.Now().Add(duration) - conditions := []any{ - map[string]string{"bucket": o.bucket.BucketName}, - map[string]string{"key": name}, - } - if size > 0 { - conditions = append(conditions, []any{"content-length-range", 0, size}) - } - policy := map[string]any{ - "expiration": expires.Format("2006-01-02T15:04:05.000Z"), - "conditions": conditions, - } - policyJson, err := json.Marshal(policy) - if err != nil { - return nil, errs.WrapMsg(err, "Marshal json error") - } - policyStr := base64.StdEncoding.EncodeToString(policyJson) - h := hmac.New(sha1.New, []byte(o.credentials.GetAccessKeySecret())) - if _, err := io.WriteString(h, policyStr); err != nil { - return nil, errs.WrapMsg(err, "WriteString error") - } - fd := &s3.FormData{ - URL: o.bucketURL, - File: "file", - Expires: expires, - FormData: map[string]string{ - "key": name, - "policy": policyStr, - "OSSAccessKeyId": o.credentials.GetAccessKeyID(), - "success_action_status": strconv.Itoa(successCode), - "signature": base64.StdEncoding.EncodeToString(h.Sum(nil)), - }, - SuccessCodes: []int{successCode}, - } - if contentType != "" { - fd.FormData["x-oss-content-type"] = contentType - } - return fd, nil -} diff --git a/pkg/common/db/s3/s3.go b/pkg/common/db/s3/s3.go deleted file mode 100644 index d3dd90ae9..000000000 --- a/pkg/common/db/s3/s3.go +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package s3 - -import ( - "context" - "net/http" - "net/url" - "time" -) - -type PartLimit struct { - MinPartSize int64 `json:"minPartSize"` - MaxPartSize int64 `json:"maxPartSize"` - MaxNumSize int64 `json:"maxNumSize"` -} - -type InitiateMultipartUploadResult struct { - Bucket string `json:"bucket"` - Key string `json:"key"` - UploadID string `json:"uploadID"` -} - -type MultipartUploadRequest struct { - UploadID string `json:"uploadId"` - Bucket string `json:"bucket"` - Key string `json:"key"` - Method string `json:"method"` - URL string `json:"url"` - Query url.Values `json:"query"` - Header http.Header `json:"header"` - PartKey string `json:"partKey"` - PartSize int64 `json:"partSize"` - FirstPart int `json:"firstPart"` -} - -type Part struct { - PartNumber int `json:"partNumber"` - ETag string `json:"etag"` -} - -type CompleteMultipartUploadResult struct { - Location string `json:"location"` - Bucket string `json:"bucket"` - Key string `json:"key"` - ETag string `json:"etag"` -} - -type SignResult struct { - Parts []SignPart `json:"parts"` -} - -type ObjectInfo struct { - ETag string `json:"etag"` - Key string `json:"name"` - Size int64 `json:"size"` - LastModified time.Time `json:"lastModified"` -} - -type CopyObjectInfo struct { - Key string `json:"name"` - ETag string `json:"etag"` -} - -type FormData struct { - URL string `json:"url"` - File string `json:"file"` - Header http.Header `json:"header"` - FormData map[string]string `json:"form"` - Expires time.Time `json:"expires"` - SuccessCodes []int `json:"successActionStatus"` -} - -type SignPart struct { - PartNumber int `json:"partNumber"` - URL string `json:"url"` - Query url.Values `json:"query"` - Header http.Header `json:"header"` -} - -type AuthSignResult struct { - URL string `json:"url"` - Query url.Values `json:"query"` - Header http.Header `json:"header"` - Parts []SignPart `json:"parts"` -} - -type InitiateUpload struct { - UploadID string `json:"uploadId"` - Bucket string `json:"bucket"` - Key string `json:"key"` - Method string `json:"method"` - URL string `json:"url"` - Query url.Values `json:"query"` - Header http.Header `json:"header"` - PartKey string `json:"partKey"` - PartSize int64 `json:"partSize"` - FirstPart int `json:"firstPart"` -} - -type UploadedPart struct { - PartNumber int `json:"partNumber"` - LastModified time.Time `json:"lastModified"` - ETag string `json:"etag"` - Size int64 `json:"size"` -} - -type ListUploadedPartsResult struct { - Key string `xml:"Key"` - UploadID string `xml:"UploadId"` - NextPartNumberMarker int `xml:"NextPartNumberMarker"` - MaxParts int `xml:"MaxParts"` - UploadedParts []UploadedPart `xml:"Part"` -} - -type Image struct { - Format string `json:"format"` - Width int `json:"width"` - Height int `json:"height"` -} - -type AccessURLOption struct { - ContentType string `json:"contentType"` - Filename string `json:"filename"` - Image *Image `json:"image"` -} - -type Interface interface { - Engine() string - PartLimit() *PartLimit - - InitiateMultipartUpload(ctx context.Context, name string) (*InitiateMultipartUploadResult, error) - CompleteMultipartUpload(ctx context.Context, uploadID string, name string, parts []Part) (*CompleteMultipartUploadResult, error) - - PartSize(ctx context.Context, size int64) (int64, error) - AuthSign(ctx context.Context, uploadID string, name string, expire time.Duration, partNumbers []int) (*AuthSignResult, error) - - PresignedPutObject(ctx context.Context, name string, expire time.Duration) (string, error) - - DeleteObject(ctx context.Context, name string) error - - CopyObject(ctx context.Context, src string, dst string) (*CopyObjectInfo, error) - - StatObject(ctx context.Context, name string) (*ObjectInfo, error) - - IsNotFound(err error) bool - - AbortMultipartUpload(ctx context.Context, uploadID string, name string) error - ListUploadedParts(ctx context.Context, uploadID string, name string, partNumberMarker int, maxParts int) (*ListUploadedPartsResult, error) - - AccessURL(ctx context.Context, name string, expire time.Duration, opt *AccessURLOption) (string, error) - - FormData(ctx context.Context, name string, size int64, contentType string, duration time.Duration) (*FormData, error) -}