parent
6150419842
commit
e93425c574
@ -0,0 +1 @@
|
|||||||
|
package third
|
@ -0,0 +1,56 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"OpenIM/internal/api/a2r"
|
||||||
|
"OpenIM/pkg/common/config"
|
||||||
|
"OpenIM/pkg/proto/third"
|
||||||
|
"context"
|
||||||
|
"github.com/OpenIMSDK/openKeeper"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ context.Context // 解决goland编辑器bug
|
||||||
|
|
||||||
|
func NewThird(zk *openKeeper.ZkClient) *Third {
|
||||||
|
return &Third{zk: zk}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Third struct {
|
||||||
|
zk *openKeeper.ZkClient
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Third) client() (third.ThirdClient, error) {
|
||||||
|
conn, err := o.zk.GetConn(config.Config.RpcRegisterName.OpenImThirdName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return third.NewThirdClient(conn), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Third) ApplyPut(c *gin.Context) {
|
||||||
|
a2r.Call(third.ThirdClient.ApplyPut, o.client, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Third) GetPut(c *gin.Context) {
|
||||||
|
a2r.Call(third.ThirdClient.GetPut, o.client, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Third) ConfirmPut(c *gin.Context) {
|
||||||
|
a2r.Call(third.ThirdClient.ConfirmPut, o.client, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Third) GetSignalInvitationInfo(c *gin.Context) {
|
||||||
|
a2r.Call(third.ThirdClient.GetSignalInvitationInfo, o.client, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Third) GetSignalInvitationInfoStartApp(c *gin.Context) {
|
||||||
|
a2r.Call(third.ThirdClient.GetSignalInvitationInfoStartApp, o.client, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Third) FcmUpdateToken(c *gin.Context) {
|
||||||
|
a2r.Call(third.ThirdClient.FcmUpdateToken, o.client, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Third) SetAppBadge(c *gin.Context) {
|
||||||
|
a2r.Call(third.ThirdClient.SetAppBadge, o.client, c)
|
||||||
|
}
|
@ -1,101 +0,0 @@
|
|||||||
package third
|
|
||||||
|
|
||||||
import (
|
|
||||||
api "OpenIM/pkg/apistruct"
|
|
||||||
"OpenIM/pkg/common/config"
|
|
||||||
"OpenIM/pkg/common/constant"
|
|
||||||
"OpenIM/pkg/common/log"
|
|
||||||
"OpenIM/pkg/common/tokenverify"
|
|
||||||
"fmt"
|
|
||||||
openapi "github.com/alibabacloud-go/darabonba-openapi/client"
|
|
||||||
sts20150401 "github.com/alibabacloud-go/sts-20150401/client"
|
|
||||||
"github.com/alibabacloud-go/tea/tea"
|
|
||||||
"github.com/fatih/structs"
|
|
||||||
|
|
||||||
//"github.com/fatih/structs"
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
"net/http"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var stsClient *sts20150401.Client
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 使用AK&SK初始化账号Client
|
|
||||||
* @param accessKeyId
|
|
||||||
* @param accessKeySecret
|
|
||||||
* @return Client
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
func getStsClient() *sts20150401.Client {
|
|
||||||
if stsClient != nil {
|
|
||||||
return stsClient
|
|
||||||
}
|
|
||||||
conf := &openapi.Config{
|
|
||||||
// 您的AccessKey ID
|
|
||||||
AccessKeyId: tea.String(config.Config.Credential.Ali.AccessKeyID),
|
|
||||||
// 您的AccessKey Secret
|
|
||||||
AccessKeySecret: tea.String(config.Config.Credential.Ali.AccessKeySecret),
|
|
||||||
// Endpoint
|
|
||||||
Endpoint: tea.String(config.Config.Credential.Ali.StsEndpoint),
|
|
||||||
}
|
|
||||||
result, err := sts20150401.NewClient(conf)
|
|
||||||
if err != nil {
|
|
||||||
log.NewError("", "alists client初始化失败 ", err)
|
|
||||||
}
|
|
||||||
stsClient = result
|
|
||||||
return stsClient
|
|
||||||
}
|
|
||||||
|
|
||||||
func AliOSSCredential(c *gin.Context) {
|
|
||||||
req := api.OSSCredentialReq{}
|
|
||||||
if err := c.BindJSON(&req); err != nil {
|
|
||||||
log.NewError("0", "BindJSON failed ", err.Error())
|
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var ok bool
|
|
||||||
var userID string
|
|
||||||
var errInfo string
|
|
||||||
ok, userID, errInfo = tokenverify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID)
|
|
||||||
if !ok {
|
|
||||||
errMsg := req.OperationID + " " + "GetUserIDFromToken failed " + errInfo + " token:" + c.Request.Header.Get("token")
|
|
||||||
log.NewError(req.OperationID, errMsg)
|
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": errMsg})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
log.NewInfo(req.OperationID, "AliOSSCredential args ", userID)
|
|
||||||
|
|
||||||
stsResp, err := getStsClient().AssumeRole(&sts20150401.AssumeRoleRequest{
|
|
||||||
DurationSeconds: tea.Int64(config.Config.Credential.Ali.StsDurationSeconds),
|
|
||||||
Policy: nil,
|
|
||||||
RoleArn: tea.String(config.Config.Credential.Ali.OssRoleArn),
|
|
||||||
RoleSessionName: tea.String(fmt.Sprintf("%s-%d", userID, time.Now().Unix())),
|
|
||||||
})
|
|
||||||
|
|
||||||
resp := api.OSSCredentialResp{}
|
|
||||||
if err != nil {
|
|
||||||
resp.ErrCode = constant.ErrTencentCredential.ErrCode
|
|
||||||
resp.ErrMsg = err.Error()
|
|
||||||
} else {
|
|
||||||
resp = api.OSSCredentialResp{
|
|
||||||
CommResp: api.CommResp{},
|
|
||||||
OssData: api.OSSCredentialRespData{
|
|
||||||
Endpoint: config.Config.Credential.Ali.OssEndpoint,
|
|
||||||
AccessKeyId: *stsResp.Body.Credentials.AccessKeyId,
|
|
||||||
AccessKeySecret: *stsResp.Body.Credentials.AccessKeySecret,
|
|
||||||
Token: *stsResp.Body.Credentials.SecurityToken,
|
|
||||||
Bucket: config.Config.Credential.Ali.Bucket,
|
|
||||||
FinalHost: config.Config.Credential.Ali.FinalHost,
|
|
||||||
},
|
|
||||||
Data: nil,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.Data = structs.Map(&resp.OssData)
|
|
||||||
log.NewInfo(req.OperationID, "AliOSSCredential return ", resp)
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, resp)
|
|
||||||
}
|
|
@ -1,76 +0,0 @@
|
|||||||
package third
|
|
||||||
|
|
||||||
import (
|
|
||||||
api "OpenIM/pkg/apistruct"
|
|
||||||
"OpenIM/pkg/common/config"
|
|
||||||
"OpenIM/pkg/common/constant"
|
|
||||||
"OpenIM/pkg/common/log"
|
|
||||||
"OpenIM/pkg/common/tokenverify"
|
|
||||||
"OpenIM/pkg/utils"
|
|
||||||
"context"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go-v2/aws"
|
|
||||||
awsConfig "github.com/aws/aws-sdk-go-v2/config"
|
|
||||||
"github.com/aws/aws-sdk-go-v2/credentials"
|
|
||||||
"github.com/aws/aws-sdk-go-v2/service/sts"
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
)
|
|
||||||
|
|
||||||
func AwsStorageCredential(c *gin.Context) {
|
|
||||||
var (
|
|
||||||
req api.AwsStorageCredentialReq
|
|
||||||
resp api.AwsStorageCredentialResp
|
|
||||||
)
|
|
||||||
if err := c.BindJSON(&req); err != nil {
|
|
||||||
log.NewError("0", utils.GetSelfFuncName(), "BindJSON failed ", err.Error())
|
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req)
|
|
||||||
var ok bool
|
|
||||||
var errInfo string
|
|
||||||
ok, _, errInfo = tokenverify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID)
|
|
||||||
if !ok {
|
|
||||||
errMsg := req.OperationID + " " + "GetUserIDFromToken failed " + errInfo + " token:" + c.Request.Header.Get("token")
|
|
||||||
log.NewError(req.OperationID, errMsg)
|
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": errMsg})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//原始帐号信息
|
|
||||||
awsSourceConfig, err := awsConfig.LoadDefaultConfig(context.TODO(), awsConfig.WithRegion(config.Config.Credential.Aws.Region),
|
|
||||||
awsConfig.WithCredentialsProvider(credentials.StaticCredentialsProvider{
|
|
||||||
Value: aws.Credentials{
|
|
||||||
AccessKeyID: config.Config.Credential.Aws.AccessKeyID,
|
|
||||||
SecretAccessKey: config.Config.Credential.Aws.AccessKeySecret,
|
|
||||||
Source: "Open IM OSS",
|
|
||||||
},
|
|
||||||
}))
|
|
||||||
if err != nil {
|
|
||||||
errMsg := req.OperationID + " " + "Init AWS S3 Credential failed " + err.Error() + " token:" + c.Request.Header.Get("token")
|
|
||||||
log.NewError(req.OperationID, errMsg)
|
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": errMsg})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//帐号转化
|
|
||||||
awsStsClient := sts.NewFromConfig(awsSourceConfig)
|
|
||||||
StsRole, err := awsStsClient.AssumeRole(context.Background(), &sts.AssumeRoleInput{
|
|
||||||
RoleArn: aws.String(config.Config.Credential.Aws.RoleArn),
|
|
||||||
DurationSeconds: aws.Int32(constant.AwsDurationTimes),
|
|
||||||
RoleSessionName: aws.String(config.Config.Credential.Aws.RoleSessionName),
|
|
||||||
ExternalId: aws.String(config.Config.Credential.Aws.ExternalId),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
errMsg := req.OperationID + " " + "AWS S3 AssumeRole failed " + err.Error() + " token:" + c.Request.Header.Get("token")
|
|
||||||
log.NewError(req.OperationID, errMsg)
|
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": errMsg})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
resp.CosData.AccessKeyId = string(*StsRole.Credentials.AccessKeyId)
|
|
||||||
resp.CosData.SecretAccessKey = string(*StsRole.Credentials.SecretAccessKey)
|
|
||||||
resp.CosData.SessionToken = string(*StsRole.Credentials.SessionToken)
|
|
||||||
resp.CosData.Bucket = config.Config.Credential.Aws.Bucket
|
|
||||||
resp.CosData.RegionID = config.Config.Credential.Aws.Region
|
|
||||||
resp.CosData.FinalHost = config.Config.Credential.Aws.FinalHost
|
|
||||||
c.JSON(http.StatusOK, gin.H{"errCode": 0, "errMsg": "", "data": resp})
|
|
||||||
}
|
|
@ -1,48 +0,0 @@
|
|||||||
package third
|
|
||||||
|
|
||||||
import (
|
|
||||||
api "OpenIM/pkg/apistruct"
|
|
||||||
"OpenIM/pkg/common/log"
|
|
||||||
"OpenIM/pkg/common/tokenverify"
|
|
||||||
"OpenIM/pkg/utils"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
)
|
|
||||||
|
|
||||||
func FcmUpdateToken(c *gin.Context) {
|
|
||||||
var (
|
|
||||||
req api.FcmUpdateTokenReq
|
|
||||||
resp api.FcmUpdateTokenResp
|
|
||||||
)
|
|
||||||
if err := c.Bind(&req); err != nil {
|
|
||||||
log.NewError("0", utils.GetSelfFuncName(), "BindJSON failed ", err.Error())
|
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
log.NewInfo(req.OperationID, utils.GetSelfFuncName(), req)
|
|
||||||
|
|
||||||
ok, UserId, errInfo := tokenverify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID)
|
|
||||||
if !ok {
|
|
||||||
errMsg := req.OperationID + " " + "GetUserIDFromToken failed " + errInfo + " token:" + c.Request.Header.Get("token")
|
|
||||||
log.NewError(req.OperationID, errMsg)
|
|
||||||
resp.ErrCode = 500
|
|
||||||
resp.ErrMsg = errMsg
|
|
||||||
c.JSON(http.StatusInternalServerError, resp)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
log.NewInfo(req.OperationID, utils.GetSelfFuncName(), req, UserId)
|
|
||||||
//逻辑处理开始
|
|
||||||
err := db.DB.SetFcmToken(UserId, req.Platform, req.FcmToken, 0)
|
|
||||||
if err != nil {
|
|
||||||
errMsg := req.OperationID + " " + "SetFcmToken failed " + err.Error() + " token:" + c.Request.Header.Get("token")
|
|
||||||
log.NewError(req.OperationID, errMsg)
|
|
||||||
resp.ErrCode = 500
|
|
||||||
resp.ErrMsg = errMsg
|
|
||||||
c.JSON(http.StatusInternalServerError, resp)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//逻辑处理完毕
|
|
||||||
c.JSON(http.StatusOK, resp)
|
|
||||||
return
|
|
||||||
}
|
|
@ -1,101 +0,0 @@
|
|||||||
package third
|
|
||||||
|
|
||||||
import (
|
|
||||||
"OpenIM/pkg/common/config"
|
|
||||||
"OpenIM/pkg/common/log"
|
|
||||||
"OpenIM/pkg/utils"
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"github.com/minio/minio-go/v7"
|
|
||||||
"github.com/minio/minio-go/v7/pkg/credentials"
|
|
||||||
url2 "net/url"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
MinioClient *minio.Client
|
|
||||||
)
|
|
||||||
|
|
||||||
func MinioInit() {
|
|
||||||
operationID := utils.OperationIDGenerator()
|
|
||||||
log.NewInfo(operationID, utils.GetSelfFuncName(), "minio config: ", config.Config.Credential.Minio)
|
|
||||||
var initUrl string
|
|
||||||
if config.Config.Credential.Minio.EndpointInnerEnable {
|
|
||||||
initUrl = config.Config.Credential.Minio.EndpointInner
|
|
||||||
} else {
|
|
||||||
initUrl = config.Config.Credential.Minio.Endpoint
|
|
||||||
}
|
|
||||||
log.NewInfo(operationID, utils.GetSelfFuncName(), "use initUrl: ", initUrl)
|
|
||||||
minioUrl, err := url2.Parse(initUrl)
|
|
||||||
if err != nil {
|
|
||||||
log.NewError(operationID, utils.GetSelfFuncName(), "parse failed, please check config/config.yaml", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
opts := &minio.Options{
|
|
||||||
Creds: credentials.NewStaticV4(config.Config.Credential.Minio.AccessKeyID, config.Config.Credential.Minio.SecretAccessKey, ""),
|
|
||||||
//Region: config.Config.Credential.Minio.Location,
|
|
||||||
}
|
|
||||||
if minioUrl.Scheme == "http" {
|
|
||||||
opts.Secure = false
|
|
||||||
} else if minioUrl.Scheme == "https" {
|
|
||||||
opts.Secure = true
|
|
||||||
}
|
|
||||||
log.NewInfo(operationID, utils.GetSelfFuncName(), "Parse ok ", config.Config.Credential.Minio)
|
|
||||||
MinioClient, err = minio.New(minioUrl.Host, opts)
|
|
||||||
log.NewInfo(operationID, utils.GetSelfFuncName(), "new ok ", config.Config.Credential.Minio)
|
|
||||||
if err != nil {
|
|
||||||
log.NewError(operationID, utils.GetSelfFuncName(), "init minio client failed", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
opt := minio.MakeBucketOptions{
|
|
||||||
Region: config.Config.Credential.Minio.Location,
|
|
||||||
}
|
|
||||||
if config.Config.Credential.Minio.IsDistributedMod == true {
|
|
||||||
opt.ObjectLocking = true
|
|
||||||
}
|
|
||||||
err = MinioClient.MakeBucket(context.Background(), config.Config.Credential.Minio.Bucket, opt)
|
|
||||||
if err != nil {
|
|
||||||
log.NewInfo(operationID, utils.GetSelfFuncName(), "MakeBucket failed ", err.Error())
|
|
||||||
exists, err := MinioClient.BucketExists(context.Background(), config.Config.Credential.Minio.Bucket)
|
|
||||||
if err == nil && exists {
|
|
||||||
log.NewInfo(operationID, utils.GetSelfFuncName(), "We already own ", config.Config.Credential.Minio.Bucket)
|
|
||||||
} else {
|
|
||||||
if err != nil {
|
|
||||||
log.NewInfo(operationID, utils.GetSelfFuncName(), err.Error())
|
|
||||||
}
|
|
||||||
log.NewInfo(operationID, utils.GetSelfFuncName(), "create bucket failed and bucket not exists")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// make app bucket
|
|
||||||
err = MinioClient.MakeBucket(context.Background(), config.Config.Credential.Minio.AppBucket, opt)
|
|
||||||
if err != nil {
|
|
||||||
log.NewInfo(operationID, utils.GetSelfFuncName(), "MakeBucket failed ", err.Error())
|
|
||||||
exists, err := MinioClient.BucketExists(context.Background(), config.Config.Credential.Minio.Bucket)
|
|
||||||
if err == nil && exists {
|
|
||||||
log.NewInfo(operationID, utils.GetSelfFuncName(), "We already own ", config.Config.Credential.Minio.Bucket)
|
|
||||||
} else {
|
|
||||||
if err != nil {
|
|
||||||
log.NewInfo(operationID, utils.GetSelfFuncName(), err.Error())
|
|
||||||
}
|
|
||||||
log.NewInfo(operationID, utils.GetSelfFuncName(), "create bucket failed and bucket not exists")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
policy, err := MinioClient.GetBucketPolicy(context.Background(), config.Config.Credential.Minio.Bucket)
|
|
||||||
log.NewInfo("", utils.GetSelfFuncName(), policy)
|
|
||||||
|
|
||||||
// 自动化桶public的代码
|
|
||||||
policyJsonString := fmt.Sprintf(`{"Version": "2012-10-17","Statement": [{"Action": ["s3:GetObject","s3:PutObject"],
|
|
||||||
"Effect": "Allow","Principal": {"AWS": ["*"]},"Resource": ["arn:aws:s3:::%s/*"],"Sid": ""}]}`, config.Config.Credential.Minio.Bucket)
|
|
||||||
err = MinioClient.SetBucketPolicy(context.Background(), config.Config.Credential.Minio.Bucket, policyJsonString)
|
|
||||||
if err != nil {
|
|
||||||
log.NewInfo("", utils.GetSelfFuncName(), "SetBucketPolicy failed please set in web", err.Error())
|
|
||||||
}
|
|
||||||
policyJsonString = fmt.Sprintf(`{"Version": "2012-10-17","Statement": [{"Action": ["s3:GetObject","s3:PutObject"],
|
|
||||||
"Effect": "Allow","Principal": {"AWS": ["*"]},"Resource": ["arn:aws:s3:::%s/*"],"Sid": ""}]}`, config.Config.Credential.Minio.AppBucket)
|
|
||||||
err = MinioClient.SetBucketPolicy(context.Background(), config.Config.Credential.Minio.AppBucket, policyJsonString)
|
|
||||||
if err != nil {
|
|
||||||
log.NewInfo("", utils.GetSelfFuncName(), "SetBucketPolicy failed please set in web", err.Error())
|
|
||||||
}
|
|
||||||
log.NewInfo(operationID, utils.GetSelfFuncName(), "minio create and set policy success")
|
|
||||||
}
|
|
@ -1,276 +0,0 @@
|
|||||||
package third
|
|
||||||
|
|
||||||
import (
|
|
||||||
api "OpenIM/pkg/apistruct"
|
|
||||||
"OpenIM/pkg/common/config"
|
|
||||||
"OpenIM/pkg/common/constant"
|
|
||||||
"OpenIM/pkg/common/log"
|
|
||||||
"OpenIM/pkg/common/tokenverify"
|
|
||||||
_ "OpenIM/pkg/common/tokenverify"
|
|
||||||
"OpenIM/pkg/utils"
|
|
||||||
"context"
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
"github.com/minio/minio-go/v7"
|
|
||||||
_ "github.com/minio/minio-go/v7"
|
|
||||||
cr "github.com/minio/minio-go/v7/pkg/credentials"
|
|
||||||
"net/http"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// @Summary minio上传文件(web api)
|
|
||||||
// @Description minio上传文件(web api), 请注意本api请求为form并非json
|
|
||||||
// @Tags 第三方服务相关
|
|
||||||
// @ID MinioUploadFile
|
|
||||||
// @Accept json
|
|
||||||
// @Param token header string true "im token"
|
|
||||||
// @Param file formData file true "要上传的文件文件"
|
|
||||||
// @Param fileType formData int true "文件类型"
|
|
||||||
// @Param operationID formData string true "操作唯一ID"
|
|
||||||
// @Produce json
|
|
||||||
// @Success 0 {object} api.MinioUploadFileResp ""
|
|
||||||
// @Failure 500 {object} api.Swagger500Resp "errCode为500 一般为服务器内部错误"
|
|
||||||
// @Failure 400 {object} api.Swagger400Resp "errCode为400 一般为参数输入错误, token未带上等"
|
|
||||||
// @Router /third/minio_upload [post]
|
|
||||||
func MinioUploadFile(c *gin.Context) {
|
|
||||||
var (
|
|
||||||
req api.MinioUploadFileReq
|
|
||||||
resp api.MinioUploadFile
|
|
||||||
)
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
log.NewError(req.OperationID, utils.GetSelfFuncName(), r)
|
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": "missing file or snapShot args"})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
if err := c.Bind(&req); err != nil {
|
|
||||||
log.NewError("0", utils.GetSelfFuncName(), "BindJSON failed ", err.Error())
|
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
log.NewInfo(req.OperationID, utils.GetSelfFuncName(), req)
|
|
||||||
var ok bool
|
|
||||||
var errInfo string
|
|
||||||
ok, _, errInfo = tokenverify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID)
|
|
||||||
if !ok {
|
|
||||||
errMsg := req.OperationID + " " + "GetUserIDFromToken failed " + errInfo + " token:" + c.Request.Header.Get("token")
|
|
||||||
log.NewError(req.OperationID, errMsg)
|
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"errCode": 500, "errMsg": errMsg})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
log.NewInfo(req.OperationID, utils.GetSelfFuncName(), req)
|
|
||||||
switch req.FileType {
|
|
||||||
// videoType upload snapShot
|
|
||||||
case constant.VideoType:
|
|
||||||
snapShotFile, err := c.FormFile("snapShot")
|
|
||||||
if err != nil {
|
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": "missing snapshot arg: " + err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
snapShotFileObj, err := snapShotFile.Open()
|
|
||||||
if err != nil {
|
|
||||||
log.NewError(req.OperationID, utils.GetSelfFuncName(), "Open file error", err.Error())
|
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
snapShotNewName, snapShotNewType := utils.GetNewFileNameAndContentType(snapShotFile.Filename, constant.ImageType)
|
|
||||||
log.Debug(req.OperationID, utils.GetSelfFuncName(), snapShotNewName, snapShotNewType)
|
|
||||||
_, err = MinioClient.PutObject(context.Background(), config.Config.Credential.Minio.Bucket, snapShotNewName, snapShotFileObj, snapShotFile.Size, minio.PutObjectOptions{ContentType: snapShotNewType})
|
|
||||||
if err != nil {
|
|
||||||
log.NewError(req.OperationID, utils.GetSelfFuncName(), "PutObject snapShotFile error", err.Error())
|
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
resp.SnapshotURL = config.Config.Credential.Minio.Endpoint + "/" + config.Config.Credential.Minio.Bucket + "/" + snapShotNewName
|
|
||||||
resp.SnapshotNewName = snapShotNewName
|
|
||||||
}
|
|
||||||
file, err := c.FormFile("file")
|
|
||||||
if err != nil {
|
|
||||||
log.NewError(req.OperationID, utils.GetSelfFuncName(), "FormFile failed", err.Error())
|
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": "missing file arg: " + err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fileObj, err := file.Open()
|
|
||||||
if err != nil {
|
|
||||||
log.NewError(req.OperationID, utils.GetSelfFuncName(), "Open file error", err.Error())
|
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": "invalid file path" + err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
newName, newType := utils.GetNewFileNameAndContentType(file.Filename, req.FileType)
|
|
||||||
log.Debug(req.OperationID, utils.GetSelfFuncName(), config.Config.Credential.Minio.Bucket, newName, fileObj, file.Size, newType, MinioClient.EndpointURL())
|
|
||||||
_, err = MinioClient.PutObject(context.Background(), config.Config.Credential.Minio.Bucket, newName, fileObj, file.Size, minio.PutObjectOptions{ContentType: newType})
|
|
||||||
if err != nil {
|
|
||||||
log.NewError(req.OperationID, utils.GetSelfFuncName(), "upload file error", err.Error())
|
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "upload file error" + err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
resp.NewName = newName
|
|
||||||
resp.URL = config.Config.Credential.Minio.Endpoint + "/" + config.Config.Credential.Minio.Bucket + "/" + newName
|
|
||||||
log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp: ", resp)
|
|
||||||
c.JSON(http.StatusOK, gin.H{"errCode": 0, "errMsg": "", "data": resp})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func MinioStorageCredential(c *gin.Context) {
|
|
||||||
var (
|
|
||||||
req api.MinioStorageCredentialReq
|
|
||||||
resp api.MiniostorageCredentialResp
|
|
||||||
)
|
|
||||||
if err := c.BindJSON(&req); err != nil {
|
|
||||||
log.NewError("0", utils.GetSelfFuncName(), "BindJSON failed ", err.Error())
|
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req)
|
|
||||||
var ok bool
|
|
||||||
var errInfo string
|
|
||||||
ok, _, errInfo = tokenverify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID)
|
|
||||||
if !ok {
|
|
||||||
errMsg := req.OperationID + " " + "GetUserIDFromToken failed " + errInfo + " token:" + c.Request.Header.Get("token")
|
|
||||||
log.NewError(req.OperationID, errMsg)
|
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": errMsg})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var stsOpts cr.STSAssumeRoleOptions
|
|
||||||
stsOpts.AccessKey = config.Config.Credential.Minio.AccessKeyID
|
|
||||||
stsOpts.SecretKey = config.Config.Credential.Minio.SecretAccessKey
|
|
||||||
stsOpts.DurationSeconds = constant.MinioDurationTimes
|
|
||||||
var endpoint string
|
|
||||||
if config.Config.Credential.Minio.EndpointInnerEnable {
|
|
||||||
endpoint = config.Config.Credential.Minio.EndpointInner
|
|
||||||
} else {
|
|
||||||
endpoint = config.Config.Credential.Minio.Endpoint
|
|
||||||
}
|
|
||||||
li, err := cr.NewSTSAssumeRole(endpoint, stsOpts)
|
|
||||||
if err != nil {
|
|
||||||
log.NewError(req.OperationID, utils.GetSelfFuncName(), "NewSTSAssumeRole failed", err.Error(), stsOpts, config.Config.Credential.Minio.Endpoint)
|
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
v, err := li.Get()
|
|
||||||
if err != nil {
|
|
||||||
log.NewError(req.OperationID, utils.GetSelfFuncName(), "li.Get error", err.Error())
|
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
resp.SessionToken = v.SessionToken
|
|
||||||
resp.SecretAccessKey = v.SecretAccessKey
|
|
||||||
resp.AccessKeyID = v.AccessKeyID
|
|
||||||
resp.BucketName = config.Config.Credential.Minio.Bucket
|
|
||||||
resp.StsEndpointURL = config.Config.Credential.Minio.Endpoint
|
|
||||||
resp.StorageTime = config.Config.Credential.Minio.StorageTime
|
|
||||||
resp.IsDistributedMod = config.Config.Credential.Minio.IsDistributedMod
|
|
||||||
c.JSON(http.StatusOK, gin.H{"errCode": 0, "errMsg": "", "data": resp})
|
|
||||||
}
|
|
||||||
|
|
||||||
func UploadUpdateApp(c *gin.Context) {
|
|
||||||
var (
|
|
||||||
req api.UploadUpdateAppReq
|
|
||||||
resp api.UploadUpdateAppResp
|
|
||||||
)
|
|
||||||
if err := c.Bind(&req); err != nil {
|
|
||||||
log.NewError(req.OperationID, utils.GetSelfFuncName(), "BindJSON failed ", err.Error())
|
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req)
|
|
||||||
|
|
||||||
var yamlName string
|
|
||||||
if req.Yaml == nil {
|
|
||||||
yamlName = ""
|
|
||||||
} else {
|
|
||||||
yamlName = req.Yaml.Filename
|
|
||||||
}
|
|
||||||
fileObj, err := req.File.Open()
|
|
||||||
if err != nil {
|
|
||||||
log.NewError(req.OperationID, utils.GetSelfFuncName(), "Open file error", err.Error())
|
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": "Open file error" + err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
_, err = MinioClient.PutObject(context.Background(), config.Config.Credential.Minio.AppBucket, req.File.Filename, fileObj, req.File.Size, minio.PutObjectOptions{})
|
|
||||||
if err != nil {
|
|
||||||
log.NewError(req.OperationID, utils.GetSelfFuncName(), "PutObject file error")
|
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "PutObject file error" + err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if yamlName != "" {
|
|
||||||
yamlObj, err := req.Yaml.Open()
|
|
||||||
if err == nil {
|
|
||||||
_, err = MinioClient.PutObject(context.Background(), config.Config.Credential.Minio.AppBucket, yamlName, yamlObj, req.Yaml.Size, minio.PutObjectOptions{})
|
|
||||||
if err != nil {
|
|
||||||
log.NewError(req.OperationID, utils.GetSelfFuncName(), "PutObject yaml error")
|
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": "PutObject yaml error" + err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log.NewError(req.OperationID, utils.GetSelfFuncName(), err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err := imdb.UpdateAppVersion(req.Type, req.Version, req.ForceUpdate, req.File.Filename, yamlName, req.UpdateLog); err != nil {
|
|
||||||
log.NewError(req.OperationID, utils.GetSelfFuncName(), "UpdateAppVersion error", err.Error())
|
|
||||||
resp.ErrCode = http.StatusInternalServerError
|
|
||||||
resp.ErrMsg = err.Error()
|
|
||||||
c.JSON(http.StatusInternalServerError, resp)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
log.NewInfo(req.OperationID, utils.GetSelfFuncName())
|
|
||||||
c.JSON(http.StatusOK, resp)
|
|
||||||
}
|
|
||||||
|
|
||||||
func version2Int(version string) (int, error) {
|
|
||||||
versions := strings.Split(version, ".")
|
|
||||||
s := strings.Join(versions, "")
|
|
||||||
versionInt, err := strconv.Atoi(s)
|
|
||||||
return versionInt, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetDownloadURL(c *gin.Context) {
|
|
||||||
var (
|
|
||||||
req api.GetDownloadURLReq
|
|
||||||
resp api.GetDownloadURLResp
|
|
||||||
)
|
|
||||||
defer func() {
|
|
||||||
log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp: ", resp)
|
|
||||||
}()
|
|
||||||
if err := c.Bind(&req); err != nil {
|
|
||||||
log.NewError("0", utils.GetSelfFuncName(), "BindJSON failed ", err.Error())
|
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req)
|
|
||||||
app, err := imdb.GetNewestVersion(req.Type)
|
|
||||||
if err != nil {
|
|
||||||
log.NewError(req.OperationID, utils.GetSelfFuncName(), "getNewestVersion failed", err.Error())
|
|
||||||
}
|
|
||||||
log.Debug(req.OperationID, utils.GetSelfFuncName(), "app: ", app)
|
|
||||||
if app != nil {
|
|
||||||
appVersion, err := version2Int(app.Version)
|
|
||||||
reqVersion, err := version2Int(req.Version)
|
|
||||||
if err != nil {
|
|
||||||
log.NewError(req.OperationID, utils.GetSelfFuncName(), err.Error(), "req version", req.Version, "app version", app.Version)
|
|
||||||
}
|
|
||||||
log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "req version:", reqVersion, "app version:", appVersion)
|
|
||||||
if appVersion > reqVersion && app.Version != "" {
|
|
||||||
resp.Data.HasNewVersion = true
|
|
||||||
if app.ForceUpdate == true {
|
|
||||||
resp.Data.ForceUpdate = true
|
|
||||||
}
|
|
||||||
if app.YamlName != "" {
|
|
||||||
resp.Data.YamlURL = config.Config.Credential.Minio.Endpoint + "/" + config.Config.Credential.Minio.AppBucket + "/" + app.YamlName
|
|
||||||
}
|
|
||||||
resp.Data.FileURL = config.Config.Credential.Minio.Endpoint + "/" + config.Config.Credential.Minio.AppBucket + "/" + app.FileName
|
|
||||||
resp.Data.Version = app.Version
|
|
||||||
resp.Data.UpdateLog = app.UpdateLog
|
|
||||||
c.JSON(http.StatusOK, resp)
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
resp.Data.HasNewVersion = false
|
|
||||||
c.JSON(http.StatusOK, resp)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"errCode": 0, "errMsg": "not found app version"})
|
|
||||||
}
|
|
@ -1,95 +0,0 @@
|
|||||||
package third
|
|
||||||
|
|
||||||
import (
|
|
||||||
api "OpenIM/pkg/apistruct"
|
|
||||||
"OpenIM/pkg/common/log"
|
|
||||||
"OpenIM/pkg/common/tokenverify"
|
|
||||||
"OpenIM/pkg/utils"
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
func GetRTCInvitationInfo(c *gin.Context) {
|
|
||||||
var (
|
|
||||||
req api.GetRTCInvitationInfoReq
|
|
||||||
resp api.GetRTCInvitationInfoResp
|
|
||||||
)
|
|
||||||
if err := c.Bind(&req); err != nil {
|
|
||||||
log.NewError(req.OperationID, utils.GetSelfFuncName(), "BindJSON failed ", err.Error())
|
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req)
|
|
||||||
ok, userID, errInfo := tokenverify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID)
|
|
||||||
if !ok {
|
|
||||||
errMsg := req.OperationID + " " + "GetUserIDFromToken failed " + errInfo + " token:" + c.Request.Header.Get("token")
|
|
||||||
log.NewError(req.OperationID, errMsg)
|
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": errMsg})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var err error
|
|
||||||
invitationInfo, err := db.DB.GetSignalInfoFromCacheByClientMsgID(req.ClientMsgID)
|
|
||||||
if err != nil {
|
|
||||||
log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetSignalInfoFromCache", err.Error(), req)
|
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err := db.DB.DelUserSignalList(userID); err != nil {
|
|
||||||
log.NewError(req.OperationID, utils.GetSelfFuncName(), "DelUserSignalList result:", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.Data.OpUserID = invitationInfo.OpUserID
|
|
||||||
resp.Data.Invitation.RoomID = invitationInfo.Invitation.RoomID
|
|
||||||
resp.Data.Invitation.SessionType = invitationInfo.Invitation.SessionType
|
|
||||||
resp.Data.Invitation.GroupID = invitationInfo.Invitation.GroupID
|
|
||||||
resp.Data.Invitation.InviterUserID = invitationInfo.Invitation.InviterUserID
|
|
||||||
resp.Data.Invitation.InviteeUserIDList = invitationInfo.Invitation.InviteeUserIDList
|
|
||||||
resp.Data.Invitation.MediaType = invitationInfo.Invitation.MediaType
|
|
||||||
resp.Data.Invitation.Timeout = invitationInfo.Invitation.Timeout
|
|
||||||
resp.Data.Invitation.InitiateTime = invitationInfo.Invitation.InitiateTime
|
|
||||||
resp.Data.Invitation.PlatformID = invitationInfo.Invitation.PlatformID
|
|
||||||
resp.Data.Invitation.CustomData = invitationInfo.Invitation.CustomData
|
|
||||||
c.JSON(http.StatusOK, resp)
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetRTCInvitationInfoStartApp(c *gin.Context) {
|
|
||||||
var (
|
|
||||||
req api.GetRTCInvitationInfoStartAppReq
|
|
||||||
resp api.GetRTCInvitationInfoStartAppResp
|
|
||||||
)
|
|
||||||
if err := c.Bind(&req); err != nil {
|
|
||||||
log.NewError(req.OperationID, utils.GetSelfFuncName(), "BindJSON failed ", err.Error())
|
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req)
|
|
||||||
var ok bool
|
|
||||||
var errInfo string
|
|
||||||
ok, userID, errInfo := tokenverify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID)
|
|
||||||
if !ok {
|
|
||||||
errMsg := req.OperationID + " " + "GetUserIDFromToken failed " + errInfo + " token:" + c.Request.Header.Get("token")
|
|
||||||
log.NewError(req.OperationID, errMsg)
|
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": errMsg})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
invitationInfo, err := db.DB.GetAvailableSignalInvitationInfo(userID)
|
|
||||||
if err != nil {
|
|
||||||
log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetSignalInfoFromCache", err.Error(), req)
|
|
||||||
c.JSON(http.StatusOK, gin.H{"errCode": 0, "errMsg": err.Error(), "data": struct{}{}})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
resp.Data.OpUserID = invitationInfo.OpUserID
|
|
||||||
resp.Data.Invitation.RoomID = invitationInfo.Invitation.RoomID
|
|
||||||
resp.Data.Invitation.SessionType = invitationInfo.Invitation.SessionType
|
|
||||||
resp.Data.Invitation.GroupID = invitationInfo.Invitation.GroupID
|
|
||||||
resp.Data.Invitation.InviterUserID = invitationInfo.Invitation.InviterUserID
|
|
||||||
resp.Data.Invitation.InviteeUserIDList = invitationInfo.Invitation.InviteeUserIDList
|
|
||||||
resp.Data.Invitation.MediaType = invitationInfo.Invitation.MediaType
|
|
||||||
resp.Data.Invitation.Timeout = invitationInfo.Invitation.Timeout
|
|
||||||
resp.Data.Invitation.InitiateTime = invitationInfo.Invitation.InitiateTime
|
|
||||||
resp.Data.Invitation.PlatformID = invitationInfo.Invitation.PlatformID
|
|
||||||
resp.Data.Invitation.CustomData = invitationInfo.Invitation.CustomData
|
|
||||||
c.JSON(http.StatusOK, resp)
|
|
||||||
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
package third
|
|
||||||
|
|
||||||
import (
|
|
||||||
api "OpenIM/pkg/apistruct"
|
|
||||||
"OpenIM/pkg/common/log"
|
|
||||||
"OpenIM/pkg/common/tokenverify"
|
|
||||||
"OpenIM/pkg/utils"
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
func SetAppBadge(c *gin.Context) {
|
|
||||||
var (
|
|
||||||
req api.SetAppBadgeReq
|
|
||||||
resp api.SetAppBadgeResp
|
|
||||||
)
|
|
||||||
if err := c.Bind(&req); err != nil {
|
|
||||||
log.NewError("0", utils.GetSelfFuncName(), "BindJSON failed ", err.Error())
|
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
log.NewInfo(req.OperationID, utils.GetSelfFuncName(), req)
|
|
||||||
|
|
||||||
var ok bool
|
|
||||||
var errInfo, opUserID string
|
|
||||||
ok, opUserID, errInfo = tokenverify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID)
|
|
||||||
if !ok {
|
|
||||||
errMsg := req.OperationID + " " + "GetUserIDFromToken failed " + errInfo + " token:" + c.Request.Header.Get("token")
|
|
||||||
log.NewError(req.OperationID, errMsg)
|
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": errMsg})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !tokenverify.CheckAccess(c, opUserID, req.FromUserID) {
|
|
||||||
log.NewError(req.OperationID, "CheckAccess false ", opUserID, req.FromUserID)
|
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": "no permission"})
|
|
||||||
}
|
|
||||||
log.NewInfo(req.OperationID, utils.GetSelfFuncName(), req, opUserID)
|
|
||||||
err := db.DB.SetUserBadgeUnreadCountSum(req.FromUserID, int(req.AppUnreadCount))
|
|
||||||
if err != nil {
|
|
||||||
errMsg := req.OperationID + " " + "SetUserBadgeUnreadCountSum failed " + err.Error() + " token:" + c.Request.Header.Get("token")
|
|
||||||
log.NewError(req.OperationID, errMsg)
|
|
||||||
resp.ErrCode = 500
|
|
||||||
resp.ErrMsg = errMsg
|
|
||||||
c.JSON(http.StatusInternalServerError, resp)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c.JSON(http.StatusOK, resp)
|
|
||||||
return
|
|
||||||
}
|
|
@ -1,78 +0,0 @@
|
|||||||
package third
|
|
||||||
|
|
||||||
import (
|
|
||||||
api "OpenIM/pkg/apistruct"
|
|
||||||
"OpenIM/pkg/common/config"
|
|
||||||
"OpenIM/pkg/common/constant"
|
|
||||||
"OpenIM/pkg/common/log"
|
|
||||||
"OpenIM/pkg/common/tokenverify"
|
|
||||||
"github.com/fatih/structs"
|
|
||||||
|
|
||||||
//"github.com/fatih/structs"
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
sts "github.com/tencentyun/qcloud-cos-sts-sdk/go"
|
|
||||||
"net/http"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TencentCloudStorageCredential(c *gin.Context) {
|
|
||||||
req := api.TencentCloudStorageCredentialReq{}
|
|
||||||
if err := c.BindJSON(&req); err != nil {
|
|
||||||
log.NewError("0", "BindJSON failed ", err.Error())
|
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var ok bool
|
|
||||||
var userID string
|
|
||||||
var errInfo string
|
|
||||||
ok, userID, errInfo = tokenverify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID)
|
|
||||||
if !ok {
|
|
||||||
errMsg := req.OperationID + " " + "GetUserIDFromToken failed " + errInfo + " token:" + c.Request.Header.Get("token")
|
|
||||||
log.NewError(req.OperationID, errMsg)
|
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": errMsg})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
log.NewInfo(req.OperationID, "TencentCloudStorageCredential args ", userID)
|
|
||||||
|
|
||||||
cli := sts.NewClient(
|
|
||||||
config.Config.Credential.Tencent.SecretID,
|
|
||||||
config.Config.Credential.Tencent.SecretKey,
|
|
||||||
nil,
|
|
||||||
)
|
|
||||||
|
|
||||||
opt := &sts.CredentialOptions{
|
|
||||||
DurationSeconds: int64(time.Hour.Seconds()),
|
|
||||||
Region: config.Config.Credential.Tencent.Region,
|
|
||||||
Policy: &sts.CredentialPolicy{
|
|
||||||
Statement: []sts.CredentialPolicyStatement{
|
|
||||||
{
|
|
||||||
Action: []string{
|
|
||||||
"name/cos:PostObject",
|
|
||||||
"name/cos:PutObject",
|
|
||||||
},
|
|
||||||
Effect: "allow",
|
|
||||||
Resource: []string{
|
|
||||||
"qcs::cos:" + config.Config.Credential.Tencent.Region + ":uid/" + config.Config.Credential.Tencent.AppID + ":" + config.Config.Credential.Tencent.Bucket + "/*",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
res, err := cli.GetCredential(opt)
|
|
||||||
resp := api.TencentCloudStorageCredentialResp{}
|
|
||||||
if err != nil {
|
|
||||||
resp.ErrCode = constant.ErrTencentCredential.ErrCode
|
|
||||||
resp.ErrMsg = err.Error()
|
|
||||||
} else {
|
|
||||||
resp.CosData.Bucket = config.Config.Credential.Tencent.Bucket
|
|
||||||
resp.CosData.Region = config.Config.Credential.Tencent.Region
|
|
||||||
resp.CosData.CredentialResult = res
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.Data = structs.Map(&resp.CosData)
|
|
||||||
log.NewInfo(req.OperationID, "TencentCloudStorageCredential return ", resp)
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, resp)
|
|
||||||
}
|
|
@ -1 +1,18 @@
|
|||||||
package third
|
package third
|
||||||
|
|
||||||
|
import (
|
||||||
|
"OpenIM/pkg/proto/third"
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (t *thirdServer) ApplyPut(ctx context.Context, req *third.ApplyPutReq) (*third.ApplyPutResp, error) {
|
||||||
|
return t.s3dataBase.ApplyPut(ctx, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *thirdServer) GetPut(ctx context.Context, req *third.GetPutReq) (*third.GetPutResp, error) {
|
||||||
|
return t.s3dataBase.GetPut(ctx, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *thirdServer) ConfirmPut(ctx context.Context, req *third.ConfirmPutReq) (*third.ConfirmPutResp, error) {
|
||||||
|
return t.s3dataBase.ConfirmPut(ctx, req)
|
||||||
|
}
|
||||||
|
@ -0,0 +1,353 @@
|
|||||||
|
package controller
|
||||||
|
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"OpenIM/pkg/common/db/obj"
|
||||||
|
"OpenIM/pkg/common/db/table/relation"
|
||||||
|
"OpenIM/pkg/proto/third"
|
||||||
|
"OpenIM/pkg/utils"
|
||||||
|
"context"
|
||||||
|
"crypto/md5"
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"log"
|
||||||
|
"path"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type S3Database interface {
|
||||||
|
ApplyPut(ctx context.Context, req *third.ApplyPutReq) (*third.ApplyPutResp, error)
|
||||||
|
GetPut(ctx context.Context, req *third.GetPutReq) (*third.GetPutResp, error)
|
||||||
|
ConfirmPut(ctx context.Context, req *third.ConfirmPutReq) (*third.ConfirmPutResp, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewS3Database(obj obj.Interface, hash relation.ObjectHashModelInterface, info relation.ObjectInfoModelInterface, put relation.ObjectPutModelInterface) S3Database {
|
||||||
|
return &s3Database{
|
||||||
|
obj: obj,
|
||||||
|
hash: hash,
|
||||||
|
info: info,
|
||||||
|
put: put,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type s3Database struct {
|
||||||
|
obj obj.Interface
|
||||||
|
hash relation.ObjectHashModelInterface
|
||||||
|
info relation.ObjectInfoModelInterface
|
||||||
|
put relation.ObjectPutModelInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
// today 今天的日期
|
||||||
|
func (c *s3Database) today() string {
|
||||||
|
return time.Now().Format("20060102")
|
||||||
|
}
|
||||||
|
|
||||||
|
// fragmentName 根据序号生成文件名
|
||||||
|
func (c *s3Database) fragmentName(index int) string {
|
||||||
|
return "fragment_" + strconv.Itoa(index+1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// getFragmentNum 获取分片大小和分片数量
|
||||||
|
func (c *s3Database) getFragmentNum(fragmentSize int64, objectSize int64) (int64, int) {
|
||||||
|
if size := c.obj.MinFragmentSize(); fragmentSize < size {
|
||||||
|
fragmentSize = size
|
||||||
|
}
|
||||||
|
if fragmentSize <= 0 || objectSize <= fragmentSize {
|
||||||
|
return objectSize, 1
|
||||||
|
} else {
|
||||||
|
num := int(objectSize / fragmentSize)
|
||||||
|
if objectSize%fragmentSize > 0 {
|
||||||
|
num++
|
||||||
|
}
|
||||||
|
if n := c.obj.MaxFragmentNum(); num > n {
|
||||||
|
num = n
|
||||||
|
}
|
||||||
|
return fragmentSize, num
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *s3Database) CheckHash(hash string) error {
|
||||||
|
val, err := hex.DecodeString(hash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(val) != md5.Size {
|
||||||
|
return errors.New("hash value error")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *s3Database) urlName(name string) string {
|
||||||
|
if name[0] != '/' {
|
||||||
|
name = "/" + name
|
||||||
|
}
|
||||||
|
return "http://127.0.0.1:8080" + name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *s3Database) UUID() string {
|
||||||
|
return uuid.New().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *s3Database) HashName(hash string) string {
|
||||||
|
return path.Join("hash", hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *s3Database) isNotFound(err error) bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *s3Database) ApplyPut(ctx context.Context, req *third.ApplyPutReq) (*third.ApplyPutResp, error) {
|
||||||
|
if err := c.CheckHash(req.Hash); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := c.obj.CheckName(req.Name); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if req.CleanTime != 0 && req.CleanTime <= time.Now().UnixMilli() {
|
||||||
|
return nil, errors.New("invalid CleanTime")
|
||||||
|
}
|
||||||
|
var expirationTime *time.Time
|
||||||
|
if req.CleanTime != 0 {
|
||||||
|
expirationTime = utils.ToPtr(time.UnixMilli(req.CleanTime))
|
||||||
|
}
|
||||||
|
if hash, err := c.hash.Take(ctx, req.Hash, c.obj.Name()); err == nil {
|
||||||
|
o := relation.ObjectInfoModel{
|
||||||
|
Name: req.Name,
|
||||||
|
Hash: hash.Hash,
|
||||||
|
ExpirationTime: expirationTime,
|
||||||
|
CreateTime: time.Now(),
|
||||||
|
}
|
||||||
|
if err := c.info.SetObject(ctx, &o); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &third.ApplyPutResp{Url: c.urlName(o.Name)}, nil // 服务器已存在
|
||||||
|
} else if !c.isNotFound(err) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// 新上传
|
||||||
|
var pack int
|
||||||
|
const effective = time.Hour * 24 * 2
|
||||||
|
req.FragmentSize, pack = c.getFragmentNum(req.FragmentSize, req.Size)
|
||||||
|
put := relation.ObjectPutModel{
|
||||||
|
PutID: c.UUID(),
|
||||||
|
Hash: req.Hash,
|
||||||
|
Name: req.Name,
|
||||||
|
ObjectSize: req.Size,
|
||||||
|
FragmentSize: req.FragmentSize,
|
||||||
|
ExpirationTime: expirationTime,
|
||||||
|
EffectiveTime: time.Now().Add(effective),
|
||||||
|
}
|
||||||
|
put.Path = path.Join("upload", c.today(), req.Hash, put.PutID)
|
||||||
|
putURLs := make([]string, 0, pack)
|
||||||
|
for i := 0; i < pack; i++ {
|
||||||
|
url, err := c.obj.PresignedPutURL(ctx, &obj.ApplyPutArgs{
|
||||||
|
Bucket: c.obj.TempBucket(),
|
||||||
|
Name: path.Join(put.Path, c.fragmentName(i)),
|
||||||
|
Effective: effective,
|
||||||
|
MaxObjectSize: req.FragmentSize,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
putURLs = append(putURLs, url)
|
||||||
|
}
|
||||||
|
put.CreateTime = time.Now()
|
||||||
|
if err := c.put.Create(ctx, []*relation.ObjectPutModel{&put}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &third.ApplyPutResp{
|
||||||
|
PutID: put.PutID,
|
||||||
|
FragmentSize: put.FragmentSize,
|
||||||
|
PutURLs: putURLs,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *s3Database) GetPut(ctx context.Context, req *third.GetPutReq) (*third.GetPutResp, error) {
|
||||||
|
up, err := c.put.Take(ctx, req.PutID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if up.Complete {
|
||||||
|
return nil, errors.New("up completed")
|
||||||
|
}
|
||||||
|
_, pack := c.getFragmentNum(up.FragmentSize, up.ObjectSize)
|
||||||
|
fragments := make([]*third.GetPutFragment, pack)
|
||||||
|
for i := 0; i < pack; i++ {
|
||||||
|
name := path.Join(up.Path, c.fragmentName(i))
|
||||||
|
o, err := c.obj.GetObjectInfo(ctx, &obj.BucketObject{
|
||||||
|
Bucket: c.obj.TempBucket(),
|
||||||
|
Name: name,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
if c.obj.IsNotFound(err) {
|
||||||
|
fragments[i] = &third.GetPutFragment{}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
fragments[i] = &third.GetPutFragment{Size: o.Size, Hash: o.Hash}
|
||||||
|
}
|
||||||
|
var cleanTime int64
|
||||||
|
if up.ExpirationTime != nil {
|
||||||
|
cleanTime = up.ExpirationTime.UnixMilli()
|
||||||
|
}
|
||||||
|
return &third.GetPutResp{
|
||||||
|
FragmentSize: up.FragmentSize,
|
||||||
|
Size: up.ObjectSize,
|
||||||
|
Name: up.Name,
|
||||||
|
Hash: up.Hash,
|
||||||
|
Fragments: fragments,
|
||||||
|
CleanTime: cleanTime,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *s3Database) ConfirmPut(ctx context.Context, req *third.ConfirmPutReq) (_ *third.ConfirmPutResp, _err error) {
|
||||||
|
up, err := c.put.Take(ctx, req.PutID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
_, pack := c.getFragmentNum(up.FragmentSize, up.ObjectSize)
|
||||||
|
defer func() {
|
||||||
|
if _err == nil {
|
||||||
|
// 清理上传的碎片
|
||||||
|
for i := 0; i < pack; i++ {
|
||||||
|
name := path.Join(up.Path, c.fragmentName(i))
|
||||||
|
err := c.obj.DeleteObjet(ctx, &obj.BucketObject{
|
||||||
|
Bucket: c.obj.TempBucket(),
|
||||||
|
Name: name,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("delete fragment %d %s %s failed %s\n", i, c.obj.TempBucket(), name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
if up.Complete {
|
||||||
|
return nil, errors.New("put completed")
|
||||||
|
}
|
||||||
|
now := time.Now().UnixMilli()
|
||||||
|
if up.EffectiveTime.UnixMilli() < now {
|
||||||
|
return nil, errors.New("upload expired")
|
||||||
|
}
|
||||||
|
if up.ExpirationTime != nil && up.ExpirationTime.UnixMilli() < now {
|
||||||
|
return nil, errors.New("object expired")
|
||||||
|
}
|
||||||
|
if hash, err := c.hash.Take(ctx, up.Hash, c.obj.Name()); err == nil {
|
||||||
|
o := relation.ObjectInfoModel{
|
||||||
|
Name: up.Name,
|
||||||
|
Hash: hash.Hash,
|
||||||
|
ExpirationTime: up.ExpirationTime,
|
||||||
|
CreateTime: time.Now(),
|
||||||
|
}
|
||||||
|
if err := c.info.SetObject(ctx, &o); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// 服务端已存在
|
||||||
|
return &third.ConfirmPutResp{
|
||||||
|
Url: c.urlName(o.Name),
|
||||||
|
}, nil
|
||||||
|
} else if c.isNotFound(err) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
src := make([]obj.BucketObject, pack)
|
||||||
|
for i := 0; i < pack; i++ {
|
||||||
|
name := path.Join(up.Path, c.fragmentName(i))
|
||||||
|
o, err := c.obj.GetObjectInfo(ctx, &obj.BucketObject{
|
||||||
|
Bucket: c.obj.TempBucket(),
|
||||||
|
Name: name,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if i+1 == pack { // 最后一个
|
||||||
|
size := up.ObjectSize - up.FragmentSize*int64(i)
|
||||||
|
if size != o.Size {
|
||||||
|
return nil, fmt.Errorf("last fragment %d size %d not equal to %d hash %s", i, o.Size, size, o.Hash)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if o.Size != up.FragmentSize {
|
||||||
|
return nil, fmt.Errorf("fragment %d size %d not equal to %d hash %s", i, o.Size, up.FragmentSize, o.Hash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
src[i] = obj.BucketObject{
|
||||||
|
Bucket: c.obj.TempBucket(),
|
||||||
|
Name: name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dst := &obj.BucketObject{
|
||||||
|
Bucket: c.obj.DataBucket(),
|
||||||
|
Name: c.HashName(up.Hash),
|
||||||
|
}
|
||||||
|
if len(src) == 1 { // 未分片直接触发copy
|
||||||
|
// 检查数据完整性,避免脏数据
|
||||||
|
o, err := c.obj.GetObjectInfo(ctx, &src[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if up.ObjectSize != o.Size {
|
||||||
|
return nil, fmt.Errorf("size mismatching should %d reality %d", up.ObjectSize, o.Size)
|
||||||
|
}
|
||||||
|
if up.Hash != o.Hash {
|
||||||
|
return nil, fmt.Errorf("hash mismatching should %s reality %s", up.Hash, o.Hash)
|
||||||
|
}
|
||||||
|
if err := c.obj.CopyObjet(ctx, &src[0], dst); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tempBucket := &obj.BucketObject{
|
||||||
|
Bucket: c.obj.TempBucket(),
|
||||||
|
Name: path.Join("merge", c.today(), req.PutID, c.UUID()),
|
||||||
|
}
|
||||||
|
defer func() { // 清理合成的文件
|
||||||
|
if err := c.obj.DeleteObjet(ctx, tempBucket); err != nil {
|
||||||
|
log.Printf("delete %s %s %s failed %s\n", c.obj.Name(), tempBucket.Bucket, tempBucket.Name, err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
err := c.obj.ComposeObject(ctx, src, tempBucket)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
info, err := c.obj.GetObjectInfo(ctx, tempBucket)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if up.ObjectSize != info.Size {
|
||||||
|
return nil, fmt.Errorf("size mismatch should %d reality %d", up.ObjectSize, info.Size)
|
||||||
|
}
|
||||||
|
if up.Hash != info.Hash {
|
||||||
|
return nil, fmt.Errorf("hash mismatch should %s reality %s", up.Hash, info.Hash)
|
||||||
|
}
|
||||||
|
if err := c.obj.CopyObjet(ctx, tempBucket, dst); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
o := &relation.ObjectInfoModel{
|
||||||
|
Name: up.Name,
|
||||||
|
Hash: up.Hash,
|
||||||
|
ExpirationTime: up.ExpirationTime,
|
||||||
|
CreateTime: time.Now(),
|
||||||
|
}
|
||||||
|
h := &relation.ObjectHashModel{
|
||||||
|
Hash: up.Hash,
|
||||||
|
Size: up.ObjectSize,
|
||||||
|
Engine: c.obj.Name(),
|
||||||
|
Bucket: c.obj.DataBucket(),
|
||||||
|
Name: c.HashName(up.Hash),
|
||||||
|
CreateTime: time.Now(),
|
||||||
|
}
|
||||||
|
if err := c.hash.Create(ctx, []*relation.ObjectHashModel{h}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := c.info.SetObject(ctx, o); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := c.put.SetCompleted(ctx, up.PutID); err != nil {
|
||||||
|
log.Printf("set uploaded %s failed %s\n", up.PutID, err)
|
||||||
|
}
|
||||||
|
return &third.ConfirmPutResp{
|
||||||
|
Url: c.urlName(o.Name),
|
||||||
|
}, nil
|
||||||
|
}
|
@ -0,0 +1,183 @@
|
|||||||
|
package obj
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"github.com/minio/minio-go/v7"
|
||||||
|
"github.com/minio/minio-go/v7/pkg/s3utils"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewMinioClient() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMinioInterface() (Interface, error) {
|
||||||
|
//client, err := minio.New("127.0.0.1:9000", &minio.Options{
|
||||||
|
// Creds: credentials.NewStaticV4("minioadmin", "minioadmin", ""),
|
||||||
|
// Secure: false,
|
||||||
|
//})
|
||||||
|
|
||||||
|
return &minioImpl{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type minioImpl struct {
|
||||||
|
tempBucket string // 上传桶
|
||||||
|
permanentBucket string // 永久桶
|
||||||
|
clearBucket string // 自动清理桶
|
||||||
|
urlstr string // 访问地址
|
||||||
|
client *minio.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
//func (m *minioImpl) Init() error {
|
||||||
|
// client, err := minio.New("127.0.0.1:9000", &minio.Options{
|
||||||
|
// Creds: credentials.NewStaticV4("minioadmin", "minioadmin", ""),
|
||||||
|
// Secure: false,
|
||||||
|
// })
|
||||||
|
// if err != nil {
|
||||||
|
// return fmt.Errorf("minio client error: %w", err)
|
||||||
|
// }
|
||||||
|
// m.urlstr = "http://127.0.0.1:9000"
|
||||||
|
// m.client = client
|
||||||
|
// m.tempBucket = "temp"
|
||||||
|
// m.permanentBucket = "permanent"
|
||||||
|
// m.clearBucket = "clear"
|
||||||
|
// return nil
|
||||||
|
//}
|
||||||
|
|
||||||
|
func (m *minioImpl) Name() string {
|
||||||
|
return "minio"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *minioImpl) MinFragmentSize() int64 {
|
||||||
|
return 1024 * 1024 * 5 // 每个分片最小大小 minio.absMinPartSize
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *minioImpl) MaxFragmentNum() int {
|
||||||
|
return 1000 // 最大分片数量 minio.maxPartsCount
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *minioImpl) MinExpirationTime() time.Duration {
|
||||||
|
return time.Hour * 24
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *minioImpl) AppendHeader() http.Header {
|
||||||
|
return map[string][]string{
|
||||||
|
"x-amz-object-append": {"true"},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *minioImpl) TempBucket() string {
|
||||||
|
return m.tempBucket
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *minioImpl) DataBucket() string {
|
||||||
|
return m.permanentBucket
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *minioImpl) ClearBucket() string {
|
||||||
|
return m.clearBucket
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *minioImpl) GetURL(bucket string, name string) string {
|
||||||
|
return fmt.Sprintf("%s/%s/%s", m.urlstr, bucket, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *minioImpl) PresignedPutURL(ctx context.Context, args *ApplyPutArgs) (string, error) {
|
||||||
|
if args.Effective <= 0 {
|
||||||
|
return "", errors.New("EffectiveTime <= 0")
|
||||||
|
}
|
||||||
|
_, err := m.GetObjectInfo(ctx, &BucketObject{
|
||||||
|
Bucket: m.tempBucket,
|
||||||
|
Name: args.Name,
|
||||||
|
})
|
||||||
|
if err == nil {
|
||||||
|
return "", fmt.Errorf("minio bucket %s name %s already exists", args.Bucket, args.Name)
|
||||||
|
} else if !m.IsNotFound(err) {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
u, err := m.client.PresignedPutObject(ctx, m.tempBucket, args.Name, args.Effective)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("minio apply error: %w", err)
|
||||||
|
}
|
||||||
|
return u.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *minioImpl) GetObjectInfo(ctx context.Context, args *BucketObject) (*ObjectInfo, error) {
|
||||||
|
info, err := m.client.StatObject(ctx, args.Bucket, args.Name, minio.StatObjectOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &ObjectInfo{
|
||||||
|
URL: m.GetURL(args.Bucket, args.Name),
|
||||||
|
Size: info.Size,
|
||||||
|
Hash: info.ETag,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *minioImpl) CopyObjet(ctx context.Context, src *BucketObject, dst *BucketObject) error {
|
||||||
|
_, err := m.client.CopyObject(ctx, minio.CopyDestOptions{
|
||||||
|
Bucket: dst.Bucket,
|
||||||
|
Object: dst.Name,
|
||||||
|
}, minio.CopySrcOptions{
|
||||||
|
Bucket: src.Bucket,
|
||||||
|
Object: src.Name,
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *minioImpl) DeleteObjet(ctx context.Context, info *BucketObject) error {
|
||||||
|
return m.client.RemoveObject(ctx, info.Bucket, info.Name, minio.RemoveObjectOptions{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *minioImpl) MoveObjetInfo(ctx context.Context, src *BucketObject, dst *BucketObject) error {
|
||||||
|
if err := m.CopyObjet(ctx, src, dst); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return m.DeleteObjet(ctx, src)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *minioImpl) ComposeObject(ctx context.Context, src []BucketObject, dst *BucketObject) error {
|
||||||
|
destOptions := minio.CopyDestOptions{
|
||||||
|
Bucket: dst.Bucket,
|
||||||
|
Object: dst.Name + ".temp",
|
||||||
|
}
|
||||||
|
sources := make([]minio.CopySrcOptions, len(src))
|
||||||
|
for i, s := range src {
|
||||||
|
sources[i] = minio.CopySrcOptions{
|
||||||
|
Bucket: s.Bucket,
|
||||||
|
Object: s.Name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_, err := m.client.ComposeObject(ctx, destOptions, sources...)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return m.MoveObjetInfo(ctx, &BucketObject{
|
||||||
|
Bucket: destOptions.Bucket,
|
||||||
|
Name: destOptions.Object,
|
||||||
|
}, &BucketObject{
|
||||||
|
Bucket: dst.Bucket,
|
||||||
|
Name: dst.Name,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *minioImpl) IsNotFound(err error) bool {
|
||||||
|
if err == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
switch e := err.(type) {
|
||||||
|
case minio.ErrorResponse:
|
||||||
|
return e.StatusCode == 404 && e.Code == "NoSuchKey"
|
||||||
|
case *minio.ErrorResponse:
|
||||||
|
return e.StatusCode == 404 && e.Code == "NoSuchKey"
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *minioImpl) CheckName(name string) error {
|
||||||
|
return s3utils.CheckValidObjectName(name)
|
||||||
|
}
|
@ -0,0 +1,58 @@
|
|||||||
|
package obj
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BucketObject struct {
|
||||||
|
Bucket string `json:"bucket"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ApplyPutArgs struct {
|
||||||
|
Bucket string
|
||||||
|
Name string
|
||||||
|
Effective time.Duration // 申请有效时间
|
||||||
|
Header http.Header // header
|
||||||
|
MaxObjectSize int64
|
||||||
|
}
|
||||||
|
|
||||||
|
type ObjectInfo struct {
|
||||||
|
URL string
|
||||||
|
Size int64
|
||||||
|
Hash string
|
||||||
|
Expiration time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
type Interface interface {
|
||||||
|
// Name 存储名字
|
||||||
|
Name() string
|
||||||
|
// MinFragmentSize 最小允许的分片大小
|
||||||
|
MinFragmentSize() int64
|
||||||
|
// MaxFragmentNum 最大允许的分片数量
|
||||||
|
MaxFragmentNum() int
|
||||||
|
// MinExpirationTime 最小过期时间
|
||||||
|
MinExpirationTime() time.Duration
|
||||||
|
// TempBucket 临时桶名,用于上传
|
||||||
|
TempBucket() string
|
||||||
|
// DataBucket 永久存储的桶名
|
||||||
|
DataBucket() string
|
||||||
|
// GetURL 通过桶名和对象名返回URL
|
||||||
|
GetURL(bucket string, name string) string
|
||||||
|
// PresignedPutURL 申请上传,返回PUT的上传地址
|
||||||
|
PresignedPutURL(ctx context.Context, args *ApplyPutArgs) (string, error)
|
||||||
|
// GetObjectInfo 获取对象信息
|
||||||
|
GetObjectInfo(ctx context.Context, args *BucketObject) (*ObjectInfo, error)
|
||||||
|
// CopyObjet 复制对象
|
||||||
|
CopyObjet(ctx context.Context, src *BucketObject, dst *BucketObject) error
|
||||||
|
// DeleteObjet 删除对象
|
||||||
|
DeleteObjet(ctx context.Context, info *BucketObject) error
|
||||||
|
// ComposeObject 合并对象
|
||||||
|
ComposeObject(ctx context.Context, src []BucketObject, dst *BucketObject) error
|
||||||
|
// IsNotFound 判断是不是不存在导致的错误
|
||||||
|
IsNotFound(err error) bool
|
||||||
|
// CheckName 检查名字是否可用
|
||||||
|
CheckName(name string) error
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
package relation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"OpenIM/pkg/common/db/table/relation"
|
||||||
|
"OpenIM/pkg/common/tracelog"
|
||||||
|
"OpenIM/pkg/utils"
|
||||||
|
"context"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewObjectHash(db *gorm.DB) relation.ObjectHashModelInterface {
|
||||||
|
return &ObjectHashGorm{
|
||||||
|
DB: db,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ObjectHashGorm struct {
|
||||||
|
DB *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ObjectHashGorm) NewTx(tx any) relation.ObjectHashModelInterface {
|
||||||
|
return &ObjectHashGorm{
|
||||||
|
DB: tx.(*gorm.DB),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ObjectHashGorm) Take(ctx context.Context, hash string, engine string) (oh *relation.ObjectHashModel, err error) {
|
||||||
|
defer func() {
|
||||||
|
tracelog.SetCtxDebug(ctx, utils.GetFuncName(1), err, "hash", hash, "engine", engine, "objectHash", oh)
|
||||||
|
}()
|
||||||
|
oh = &relation.ObjectHashModel{}
|
||||||
|
return oh, utils.Wrap1(o.DB.Where("hash = ? and engine = ?", hash, engine).Take(oh).Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ObjectHashGorm) Create(ctx context.Context, h []*relation.ObjectHashModel) (err error) {
|
||||||
|
defer func() {
|
||||||
|
tracelog.SetCtxDebug(ctx, utils.GetFuncName(1), err, "objectHash", h)
|
||||||
|
}()
|
||||||
|
return utils.Wrap1(o.DB.Create(h).Error)
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
package relation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"OpenIM/pkg/common/db/table/relation"
|
||||||
|
"OpenIM/pkg/common/tracelog"
|
||||||
|
"OpenIM/pkg/utils"
|
||||||
|
"context"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewObjectInfo(db *gorm.DB) relation.ObjectInfoModelInterface {
|
||||||
|
return &ObjectInfoGorm{
|
||||||
|
DB: db,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ObjectInfoGorm struct {
|
||||||
|
DB *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ObjectInfoGorm) NewTx(tx any) relation.ObjectInfoModelInterface {
|
||||||
|
return &ObjectInfoGorm{
|
||||||
|
DB: tx.(*gorm.DB),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ObjectInfoGorm) SetObject(ctx context.Context, obj *relation.ObjectInfoModel) (err error) {
|
||||||
|
defer func() {
|
||||||
|
tracelog.SetCtxDebug(ctx, utils.GetFuncName(1), err, "objectInfo", obj)
|
||||||
|
}()
|
||||||
|
return utils.Wrap1(o.DB.Transaction(func(tx *gorm.DB) error {
|
||||||
|
if err := tx.Where("name = ?", obj.Name).Delete(&relation.ObjectInfoModel{}).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return tx.Create(obj).Error
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ObjectInfoGorm) Take(ctx context.Context, name string) (info *relation.ObjectInfoModel, err error) {
|
||||||
|
defer func() {
|
||||||
|
tracelog.SetCtxDebug(ctx, utils.GetFuncName(1), err, "name", name, "info", info)
|
||||||
|
}()
|
||||||
|
info = &relation.ObjectInfoModel{}
|
||||||
|
return info, utils.Wrap1(o.DB.Where("name = ?", name).Take(info).Error)
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
package relation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"OpenIM/pkg/common/db/table/relation"
|
||||||
|
"OpenIM/pkg/common/tracelog"
|
||||||
|
"OpenIM/pkg/utils"
|
||||||
|
"context"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewObjectPut(db *gorm.DB) relation.ObjectPutModelInterface {
|
||||||
|
return &ObjectPutGorm{
|
||||||
|
DB: db,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ObjectPutGorm struct {
|
||||||
|
DB *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ObjectPutGorm) NewTx(tx any) relation.ObjectPutModelInterface {
|
||||||
|
return &ObjectPutGorm{
|
||||||
|
DB: tx.(*gorm.DB),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ObjectPutGorm) Create(ctx context.Context, m []*relation.ObjectPutModel) (err error) {
|
||||||
|
defer func() {
|
||||||
|
tracelog.SetCtxDebug(ctx, utils.GetFuncName(1), err, "objectPut", m)
|
||||||
|
}()
|
||||||
|
return utils.Wrap1(o.DB.Create(m).Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ObjectPutGorm) Take(ctx context.Context, putID string) (put *relation.ObjectPutModel, err error) {
|
||||||
|
defer func() {
|
||||||
|
tracelog.SetCtxDebug(ctx, utils.GetFuncName(1), err, "putID", putID, "put", put)
|
||||||
|
}()
|
||||||
|
put = &relation.ObjectPutModel{}
|
||||||
|
return put, utils.Wrap1(o.DB.Where("put_id = ?", putID).Take(put).Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ObjectPutGorm) SetCompleted(ctx context.Context, putID string) (err error) {
|
||||||
|
defer func() {
|
||||||
|
tracelog.SetCtxDebug(ctx, utils.GetFuncName(1), err, "putID", putID)
|
||||||
|
}()
|
||||||
|
return utils.Wrap1(o.DB.Model(&relation.ObjectPutModel{}).Where("put_id = ?", putID).Update("complete", true).Error)
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
package relation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ObjectHashModelTableName = "object_hash"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ObjectHashModel struct {
|
||||||
|
Hash string `gorm:"column:hash;primary_key;size:32"`
|
||||||
|
Engine string `gorm:"column:engine;primary_key;size:16"`
|
||||||
|
Size int64 `gorm:"column:size"`
|
||||||
|
Bucket string `gorm:"column:bucket"`
|
||||||
|
Name string `gorm:"column:name"`
|
||||||
|
CreateTime time.Time `gorm:"column:create_time"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ObjectHashModel) TableName() string {
|
||||||
|
return ObjectHashModelTableName
|
||||||
|
}
|
||||||
|
|
||||||
|
type ObjectHashModelInterface interface {
|
||||||
|
NewTx(tx any) ObjectHashModelInterface
|
||||||
|
Take(ctx context.Context, hash string, engine string) (*ObjectHashModel, error)
|
||||||
|
Create(ctx context.Context, h []*ObjectHashModel) error
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package relation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ObjectInfoModelTableName = "object_info"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ObjectInfoModel struct {
|
||||||
|
Name string `gorm:"column:name;primary_key"`
|
||||||
|
Hash string `gorm:"column:hash"`
|
||||||
|
ExpirationTime *time.Time `gorm:"column:expiration_time"`
|
||||||
|
CreateTime time.Time `gorm:"column:create_time"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ObjectInfoModel) TableName() string {
|
||||||
|
return ObjectInfoModelTableName
|
||||||
|
}
|
||||||
|
|
||||||
|
type ObjectInfoModelInterface interface {
|
||||||
|
NewTx(tx any) ObjectInfoModelInterface
|
||||||
|
SetObject(ctx context.Context, obj *ObjectInfoModel) error
|
||||||
|
Take(ctx context.Context, name string) (*ObjectInfoModel, error)
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
package relation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ObjectPutModelTableName = "object_put"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ObjectPutModel struct {
|
||||||
|
PutID string `gorm:"column:put_id;primary_key"`
|
||||||
|
Hash string `gorm:"column:hash"`
|
||||||
|
Path string `gorm:"column:path"`
|
||||||
|
Name string `gorm:"column:name"`
|
||||||
|
ObjectSize int64 `gorm:"column:object_size"`
|
||||||
|
FragmentSize int64 `gorm:"column:fragment_size"`
|
||||||
|
Complete bool `gorm:"column:complete"`
|
||||||
|
ExpirationTime *time.Time `gorm:"column:expiration_time"`
|
||||||
|
EffectiveTime time.Time `gorm:"column:effective_time"`
|
||||||
|
CreateTime time.Time `gorm:"column:create_time"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ObjectPutModel) TableName() string {
|
||||||
|
return ObjectPutModelTableName
|
||||||
|
}
|
||||||
|
|
||||||
|
type ObjectPutModelInterface interface {
|
||||||
|
NewTx(tx any) ObjectPutModelInterface
|
||||||
|
Create(ctx context.Context, m []*ObjectPutModel) error
|
||||||
|
Take(ctx context.Context, putID string) (*ObjectPutModel, error)
|
||||||
|
SetCompleted(ctx context.Context, putID string) error
|
||||||
|
}
|
Loading…
Reference in new issue