package oss import ( "encoding/json" "errors" "eta/eta_mini_crm_ht/utils" "fmt" "github.com/aliyun/alibaba-cloud-sdk-go/services/sts" "github.com/aliyun/aliyun-oss-go-sdk/oss" "github.com/gabriel-vasile/mimetype" "io" "os" "strings" "time" ) type STSToken struct { AccessKeyId string AccessKeySecret string SecurityToken string ExpiredTime string RegionId string Bucketname string Endpoint string Imghost string Sign string } type OssClient interface { UploadFile(string, string, string) (string, error) GetUploadToken() (OssToken, error) GetFile(filePath, savePath string) (path string, err error) GetExt(string) (string, error) MultiUploadFile() error } func NewOssClient() OssClient { switch utils.ObjectStorageClient { case utils.STORAGESOURCE_OSS_NAME: return new(AliOss) default: // 默认使用minio return new(MinioOss) } } // OssToken 此处为了兼容前端那边所以有重复的 type OssToken struct { AccessKeyId string SecretKeyId string RegionId string Bucketname string Endpoint string ImgHost string UseSSL string Port string //AccessKeyId string AccessKeySecret string SecurityToken string ExpiredTime string //RegionId string //Bucketname string //Endpoint string Imghost string S3ForceStyle bool S3Protocol string } // GetOssSTSToken 获取STSToken func GetOssSTSToken() (item *STSToken, err error) { defer func() { if err != nil { utils.FileLog.Info(err.Error()) } }() item = new(STSToken) // 获取缓存中的Token recent, _ := utils.Rc.RedisString(utils.STSTokenCacheKey) if recent != "" { lastToken := new(STSToken) if e := json.Unmarshal([]byte(recent), &lastToken); e != nil { err = errors.New("GetOssSTSToken lastToken Unmarshal Err: " + e.Error()) return } // 未防止正在上传大文件时Token过期, 将判定的过期时间提前10分钟 afterTime := time.Now().Local().Add(10 * time.Minute) expired, e := time.ParseInLocation(utils.FormatDateTime, lastToken.ExpiredTime, time.Local) if e != nil { err = errors.New("GetOssSTSToken expiredTime Parse Err: " + e.Error()) return } if expired.After(afterTime) { item.AccessKeyId = lastToken.AccessKeyId item.AccessKeySecret = lastToken.AccessKeySecret item.SecurityToken = lastToken.SecurityToken item.ExpiredTime = lastToken.ExpiredTime item.RegionId = utils.RegionId item.Bucketname = utils.Bucketname item.Endpoint = utils.Imghost item.Imghost = utils.Imghost return } } // 已过期则获取新的token newToken, e := NewSTSToken() if e != nil { err = errors.New("GetOssSTSToken NewSTSToken Err: " + e.Error()) return } newTokenJson, e := json.Marshal(newToken) if e != nil { err = errors.New("GetOssSTSToken NewToken JSON Err: " + e.Error()) return } // 覆盖缓存 if e := utils.Rc.Put(utils.STSTokenCacheKey, newTokenJson, time.Hour); e != nil { err = errors.New("GetOssSTSToken SetRedis Err: " + e.Error()) return } item = newToken return } // NewSTSToken 获取一个新的STSToken func NewSTSToken() (item *STSToken, err error) { defer func() { if err != nil { utils.FileLog.Info(err.Error()) } }() item = new(STSToken) client, e := sts.NewClientWithAccessKey("cn-shanghai", utils.RAMAccessKeyId, utils.RAMAccessKeySecret) if e != nil { err = errors.New("NewSTSToken NewClient Err: " + e.Error()) return } request := sts.CreateAssumeRoleRequest() request.Scheme = utils.AliStsScheme request.RegionId = utils.RegionId request.RoleArn = utils.RoleArn now := time.Now().Format(utils.FormatDateTimeUnSpace) request.RoleSessionName = utils.RoleSessionName + now request.DurationSeconds = "3600" request.ConnectTimeout = 300 * time.Second request.ReadTimeout = 300 * time.Second response, e := client.AssumeRole(request) if e != nil { err = errors.New("NewSTSToken AssumeRole Err: " + e.Error()) return } if response != nil { item.AccessKeyId = response.Credentials.AccessKeyId item.AccessKeySecret = response.Credentials.AccessKeySecret item.SecurityToken = response.Credentials.SecurityToken t, _ := time.Parse(time.RFC3339, response.Credentials.Expiration) expiration := t.In(time.Local) item.ExpiredTime = expiration.Format(utils.FormatDateTime) item.RegionId = utils.RegionId item.Bucketname = utils.Bucketname item.Endpoint = utils.Imghost item.Imghost = utils.Imghost } return } type AliOss struct{} func (m *AliOss) GetExt(ossPath string) (ext string, err error) { if utils.AccessKeyId == `` { return "0", errors.New("阿里云信息未配置") } client, err := oss.New(utils.Endpoint, utils.AccessKeyId, utils.AccessKeySecret) if err != nil { return } bucket, err := client.Bucket(utils.Bucketname) if err != nil { return } objectKey := ossPath[strings.Index(ossPath, utils.RESOURCE_DIR):] metaInfo, err := bucket.GetObjectMeta(objectKey) if err != nil { return } ext = GetFileExtensionFromContentType(metaInfo["Content-Type"][0]) return } // UploadFile 上传文件 func (m *AliOss) UploadFile(fileName, filePath, savePath string) (string, error) { if utils.AccessKeyId == `` { return "0", errors.New("阿里云信息未配置") } client, err := oss.New(utils.Endpoint, utils.AccessKeyId, utils.AccessKeySecret) if err != nil { return "1", err } bucket, err := client.Bucket(utils.Bucketname) if err != nil { return "2", err } path := savePath if savePath == "" { path = utils.UploadDir + time.Now().Format("200601/20060102/") + fileName } err = bucket.PutObjectFromFile(path, filePath) if err != nil { return "3", err } resourceUrl := utils.Imghost + path return resourceUrl, err } func (m *AliOss) GetUploadToken() (token OssToken, err error) { stsToken, e := GetOssSTSToken() if e != nil { err = fmt.Errorf("GetOssSTSToken err: %s", e.Error()) return } token.AccessKeyId = stsToken.AccessKeyId token.AccessKeySecret = stsToken.AccessKeySecret token.SecurityToken = stsToken.SecurityToken token.ExpiredTime = stsToken.ExpiredTime token.RegionId = stsToken.RegionId token.Bucketname = stsToken.Bucketname token.Endpoint = stsToken.Endpoint token.Imghost = stsToken.Imghost return } func (m *AliOss) MultiUploadFile() (err error) { return } func (m *AliOss) GetFile(filePath, savePath string) (path string, err error) { if utils.AccessKeyId == `` { return "", errors.New("阿里云信息未配置") } client, err := oss.New(utils.Endpoint, utils.AccessKeyId, utils.AccessKeySecret) if err != nil { return } bucket, err := client.Bucket(utils.Bucketname) if err != nil { return } objectKey := filePath[strings.Index(filePath, utils.RESOURCE_DIR):] reader, err := bucket.GetObject(objectKey) if err != nil { return } buffer := make([]byte, 512) n, err := reader.Read(buffer) if err != nil && err != io.EOF { return "", fmt.Errorf("Error reading object: %s", err) } mime := mimetype.Detect(buffer[:n]) fileExt := mime.Extension() path = savePath + fileExt defer reader.Close() // 打开或创建本地文件 localFile, err := os.Create(path) if err != nil { utils.FileLog.Info("处理原始图片信息失败:Error create local dir: %s", err) return } defer localFile.Close() // 将io.ReadCloser中的数据复制到本地文件 _, err = localFile.Write(buffer[:n]) if err != nil { utils.FileLog.Info("处理原始图片信息失败:Error writing to local file: %s", err) return } _, err = io.Copy(localFile, reader) return } func GetFileExtensionFromContentType(contentType string) string { switch contentType { case "image/jpeg": return ".jpg" case "image/png": return ".png" case "application/pdf": return ".pdf" case "application/msword": return ".doc" case "application/vnd.openxmlformats-officedocument.wordprocessingml.document": return ".docx" case "application/vnd.ms-excel": return ".xls" case "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": return ".xlsx" case "text/plain": return ".txt" case "application/json": return ".json" case "application/octet-stream": return ".bin" default: return "" } }