diff --git a/server/upload/internal/handler/routes.go b/server/upload/internal/handler/routes.go index 8d5b0aa0..e33dc5a8 100644 --- a/server/upload/internal/handler/routes.go +++ b/server/upload/internal/handler/routes.go @@ -52,6 +52,11 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { Path: "/api/upload/up-logo", Handler: UploadLogoHandler(serverCtx), }, + { + Method: http.MethodPost, + Path: "/api/upload/upload-file-base", + Handler: UploadFileBaseHandler(serverCtx), + }, }, ) } diff --git a/server/upload/internal/handler/uploadfilebasehandler.go b/server/upload/internal/handler/uploadfilebasehandler.go new file mode 100644 index 00000000..21c9e02f --- /dev/null +++ b/server/upload/internal/handler/uploadfilebasehandler.go @@ -0,0 +1,35 @@ +package handler + +import ( + "net/http" + "reflect" + + "fusenapi/utils/basic" + + "fusenapi/server/upload/internal/logic" + "fusenapi/server/upload/internal/svc" + "fusenapi/server/upload/internal/types" +) + +func UploadFileBaseHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + + var req types.UploadFileBaseReq + userinfo, err := basic.RequestParse(w, r, svcCtx, &req) + if err != nil { + return + } + + // 创建一个业务逻辑层实例 + l := logic.NewUploadFileBaseLogic(r.Context(), svcCtx) + + rl := reflect.ValueOf(l) + basic.BeforeLogic(w, r, rl) + + resp := l.UploadFileBase(&req, userinfo) + + if !basic.AfterLogic(w, r, rl, resp) { + basic.NormalAfterLogic(w, r, resp) + } + } +} diff --git a/server/upload/internal/logic/uploadfilebaselogic.go b/server/upload/internal/logic/uploadfilebaselogic.go new file mode 100644 index 00000000..28a8ae1c --- /dev/null +++ b/server/upload/internal/logic/uploadfilebaselogic.go @@ -0,0 +1,156 @@ +package logic + +import ( + "encoding/base64" + "fmt" + "fusenapi/model/gmodel" + "fusenapi/utils/auth" + "fusenapi/utils/basic" + "fusenapi/utils/hash" + "strings" + "time" + + "context" + + "fusenapi/server/upload/internal/svc" + "fusenapi/server/upload/internal/types" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/service/s3" + "github.com/zeromicro/go-zero/core/logx" +) + +type UploadFileBaseLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewUploadFileBaseLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UploadFileBaseLogic { + return &UploadFileBaseLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +// 处理进入前逻辑w,r +// func (l *UploadFileBaseLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) { +// } + +// 处理逻辑后 w,r 如:重定向, resp 必须重新处理 +// func (l *UploadFileBaseLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) { +// // httpx.OkJsonCtx(r.Context(), w, resp) +// } + +func (l *UploadFileBaseLogic) UploadFileBase(req *types.UploadFileBaseReq, userinfo *auth.UserInfo) (resp *basic.Response) { + // 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data) + // userinfo 传入值时, 一定不为null + // 定义用户ID和S3键名格式 + var uid int64 + var userId int64 + var guestId int64 + + // 检查用户是否是游客 + if userinfo.IsGuest() { + // 如果是,使用游客ID和游客键名格式 + guestId = userinfo.GuestId + uid = guestId + } else { + // 否则,使用用户ID和用户键名格式 + userId = userinfo.UserId + uid = userId + } + + guestId = req.GuestId + userId = req.UserId + + // 定义存储桶名称 + var bucketName *string + var apiType int64 = 2 + + // 根据类别选择存储桶 + switch req.UploadBucket { + case 2: + bucketName = basic.TempfileBucketName + default: + bucketName = basic.StorageBucketName + } + + // 设置AWS会话的区域 + l.svcCtx.AwsSession.Config.Region = aws.String("us-west-1") + + // 创建新的S3服务实例 + svc := s3.New(l.svcCtx.AwsSession) + + // 定义S3请求和当前时间 + var s3req *request.Request + + var resourceId string = hash.JsonHashKey(fmt.Sprintf("%s%d", req.FileKey, uid)) + + var uploadUrl = UploadUrl{} + resourceModel := gmodel.NewFsResourceModel(l.svcCtx.MysqlConn) + resourceInfo, err := resourceModel.FindOneById(l.ctx, resourceId) + if err == nil && resourceInfo.ResourceId != "" { + uploadUrl.Status = 1 + uploadUrl.ResourceId = resourceId + uploadUrl.ResourceUrl = *resourceInfo.ResourceUrl + } else { + RBase64Point := strings.LastIndex(req.FileData, ";base64,") + 8 + req.FileData = req.FileData[RBase64Point:] + dist, err := base64.StdEncoding.DecodeString(req.FileData) + + if err != nil { + logx.Error(err) + } + + // 创建S3对象存储请求 + s3req, _ = svc.PutObjectRequest( + &s3.PutObjectInput{ + Bucket: bucketName, + Key: &resourceId, + }, + ) + + // 设置请求体为文件数据 + s3req.SetBufferBody(dist) + + // 发送请求 + err = s3req.Send() + + // 检查是否有错误 + if err != nil { + logx.Error(err) + uploadUrl.Status = 0 + } else { + var url = s3req.HTTPRequest.URL.String() + // 打印请求URL + logx.Info(url) + uploadUrl.Status = 1 + uploadUrl.ResourceId = resourceId + uploadUrl.ResourceUrl = url + var version string = "0.0.1" + var nowTime = time.Now() + _, err = resourceModel.Create(l.ctx, &gmodel.FsResource{ + ResourceId: resourceId, + UserId: &userId, + GuestId: &guestId, + ResourceType: &req.FileType, + ResourceUrl: &url, + Version: &version, + UploadedAt: &nowTime, + Metadata: &req.Metadata, + ApiType: &apiType, + }) + if err != nil { + logx.Error(err) + } + } + } + + // 返回成功的响应和上传URL + return resp.SetStatus(basic.CodeOK, map[string]interface{}{ + "upload_data": uploadUrl, + }) +} diff --git a/server/upload/internal/logic/uploadfilesbackendlogic.go b/server/upload/internal/logic/uploadfilesbackendlogic.go index 74a7ba00..9d30f2ae 100644 --- a/server/upload/internal/logic/uploadfilesbackendlogic.go +++ b/server/upload/internal/logic/uploadfilesbackendlogic.go @@ -233,9 +233,11 @@ func (l *UploadFilesBackendLogic) UploadFilesBackend(req *types.UploadFilesReq, } type UploadInfo struct { - FileSize int64 `json:"file_size"` // 上传唯一标识信息 - FileKeys string `json:"file_keys"` // 上传唯一标识信息 - Metadata string `json:"meta_data"` // 上传文件额外信息 + FileSize int64 `json:"file_size"` // 上传文件大小 + FileKeys string `json:"file_keys"` // 上传文件唯一标识 + FileData *string `json:"file_data"` // 上传文件Base64 + Metadata string `json:"meta_data"` // 上传文件额外信息 + } type UploadData struct { diff --git a/server/upload/internal/types/types.go b/server/upload/internal/types/types.go index 8373d29c..c967bf42 100644 --- a/server/upload/internal/types/types.go +++ b/server/upload/internal/types/types.go @@ -5,6 +5,16 @@ import ( "fusenapi/utils/basic" ) +type UploadFileBaseReq struct { + FileType string `form:"file_type"` // 上传文件类型 + FileKey string `form:"file_key"` // 上传唯一标识信息 + FileData string `form:"file_data"` // 上传文件额外信息 + Metadata string `form:"meta_data,optional"` // 上传文件额外信息 + UserId int64 `form:"user_id,optional"` // 上传文件额外信息 + GuestId int64 `form:"guest_id,optional"` // 上传文件额外信息 + UploadBucket int64 `form:"upload_bucket,options=[1,2],default=1"` // 上传桶名:1=缓存,2=持久 +} + type UploadLogoReq struct { ResourceId string `form:"resource_id"` // 资源ID ResourceUrl string `form:"resource_url"` // 资源URL diff --git a/server_api/upload.api b/server_api/upload.api index 5524fead..a94830be 100644 --- a/server_api/upload.api +++ b/server_api/upload.api @@ -38,8 +38,24 @@ service upload { @handler UploadLogoHandler post /api/upload/up-logo(UploadLogoReq) returns (response); + // 上传文件发起--base64 + @handler UploadFileBaseHandler + post /api/upload/upload-file-base(UploadFileBaseReq) returns (response); + } +type ( + UploadFileBaseReq { + FileType string `form:"file_type"` // 上传文件类型 + FileKey string `form:"file_key"` // 上传唯一标识信息 + FileData string `form:"file_data"` // 上传文件额外信息 + Metadata string `form:"meta_data,optional"` // 上传文件额外信息 + UserId int64 `form:"user_id,optional"` // 上传文件额外信息 + GuestId int64 `form:"guest_id,optional"` // 上传文件额外信息 + UploadBucket int64 `form:"upload_bucket,options=[1,2],default=1"` // 上传桶名:1=缓存,2=持久 + } +) + type ( UploadLogoReq { ResourceId string `form:"resource_id"` // 资源ID