package task import ( "bufio" "bytes" "context" "crypto/md5" "encoding/hex" "errors" "fmt" "github.com/qiniu/api.v7/v7/auth/qbox" "github.com/qiniu/api.v7/v7/storage" "go.uber.org/zap" "gorm.io/gorm" "io" "log-server/global" "log-server/model/common/request" "log-server/model/task" taskReq "log-server/model/task/request" "log-server/model/task/response" "log-server/utils" "mime/multipart" "path" "strconv" "strings" "time" ) type TaskConfService struct { } //添加数据库记录 func (e *TaskConfService) Upload(file response.UploadFileResponse) error { c := context.Background() key := fmt.Sprintf(SCRIPTDOWNLOADCHECK, file.TaskID) //添加redis缓存 err := global.GVA_REDIS.Set(c, key, file.Md5String, 0).Err() if err != nil { global.GVA_LOG.Info("添加脚本md5值缓存失败:" + err.Error() + time.Now().Format("2006-01-02 15:04:05")) } return global.GVA_DB.Table("upload_file").Create(&file).Error } const ACCESSKEY string = "B81Gsvry2StqKVE3txS-7v9GBBfqykC9zhebmxnW" const SECRETKEY string = "YEZJuYcdeF7vRvzffxpopAVR-jMPZg9pZ-4IKTVW" const BUCKET string = "pinaishop" const SCRIPTDOWNLOADCHECK string = "script:%d" //更改的上传文件函数 func (e *TaskConfService) UploadFileFunc(file *multipart.FileHeader, taskId string) (string, string, string, error) { // 读取文件后缀 ext := path.Ext(file.Filename) // 读取文件名并加密 name := strings.TrimSuffix(file.Filename, ext) name = utils.MD5V([]byte(name)) // 拼接新文件名 filename := name + "_" + time.Now().Format("20060102150405") + ext key := "shuyou/script/" + taskId + "/" + filename // 尝试创建此路径 //mkdirErr := os.MkdirAll(global.GVA_CONFIG.Local.ScriptPath, os.ModePerm) //if mkdirErr != nil { // global.GVA_LOG.Error("function os.MkdirAll() Filed", zap.Any("err", mkdirErr.Error())) // return "", "", "", errors.New("function os.MkdirAll() Filed, err:" + mkdirErr.Error()) //} // 拼接路径和文件名 //p := global.GVA_CONFIG.Local.ScriptPath + "/" + filename //filepath := global.GVA_CONFIG.Local.ScriptPath + "/" + filename uploadErr := e.UploadFileToQiNiu(filename, taskId, file) if uploadErr != nil { global.GVA_LOG.Error("function UploadFileToQiNiu Filed", zap.Any("err", uploadErr.Error())) return "", "", "", errors.New("function UploadFileToQiNiu Filed, err:" + uploadErr.Error()) } //f, openError := file.Open() // 读取文件 f1, openErr := file.Open() // 读取文件生成MD5值 if openErr != nil { global.GVA_LOG.Error("function file.Open() Filed", zap.Any("err", openErr.Error())) return "", "", "", errors.New("function file.Open() Filed, err:" + openErr.Error()) } //defer f.Close() // 创建文件 defer 关闭 defer f1.Close() //生成md5值 md5h := md5.New() io.Copy(md5h, f1) md5String := hex.EncodeToString(md5h.Sum(nil)) // //out, createErr := os.Create(p) //if createErr != nil { // global.GVA_LOG.Error("function os.Create() Filed", zap.Any("err", createErr.Error())) // // return "", "", "", errors.New("function os.Create() Filed, err:" + createErr.Error()) //} //defer out.Close() // 创建文件 defer 关闭 //_, copyErr := io.Copy(out, f) // 传输(拷贝)文件 //fmt.Println("拷贝文件") //if copyErr != nil { // global.GVA_LOG.Error("function io.Copy() Filed", zap.Any("err", copyErr.Error())) // return "", "", "", errors.New("function io.Copy() Filed, err:" + copyErr.Error()) //} return key, filename, md5String, nil } func (e *TaskConfService) UploadFileToQiNiu(fileName string, taskId string, file *multipart.FileHeader) error { accessKey := "B81Gsvry2StqKVE3txS-7v9GBBfqykC9zhebmxnW" secretKey := "YEZJuYcdeF7vRvzffxpopAVR-jMPZg9pZ-4IKTVW" mac := qbox.NewMac(accessKey, secretKey) bucket := "pinaishop" putPolicy := storage.PutPolicy{ Scope: bucket, } key := "shuyou/script/" + taskId + "/" + fileName upToken := putPolicy.UploadToken(mac) cfg := storage.Config{} // 空间对应的机房 cfg.Region = &storage.ZoneHuanan // 是否使用https域名 cfg.UseHTTPS = true // 上传是否使用CDN上传加速 cfg.UseCdnDomains = false formUploader := storage.NewFormUploader(&cfg) ret := storage.PutRet{} putExtra := storage.PutExtra{ //Params: map[string]string{ // "x:name": "github logo", //}, } // Get the file size fileSize := file.Size f, openError := file.Open() // 读取文件 if openError != nil { global.GVA_LOG.Error("function file.Open() Filed", zap.Any("err", openError.Error())) return errors.New("function file.Open() Filed, err:" + openError.Error()) } defer f.Close() // Read the file into a byte slice bs := make([]byte, fileSize) _, err := bufio.NewReader(f).Read(bs) if err != nil && err != io.EOF { fmt.Println(err) return errors.New("文件转化成字节数组错误, err:" + err.Error()) } err = formUploader.Put(context.Background(), &ret, upToken, key, bytes.NewReader(bs), fileSize, &putExtra) if err != nil { fmt.Println(err) return errors.New("上传七牛云错误, err:" + err.Error()) } fmt.Println(ret.Key, ret.Hash) return nil } //上传文件 func (e *TaskConfService) UploadFile(taskId int, user string, header *multipart.FileHeader) (file response.UploadFileResponse, err error) { //查询数据库记录数 var count int64 //获取最后一条记录 var lastRecord response.UploadFileResponse var version int //定义下载前缀 var prefix string = "http://cdn.pinaishop.kfzs.com/" global.GVA_DB.Table("upload_file").Where("task_id = ?", taskId).Count(&count) if count == 0 { version = 1 } else { fmt.Println(count) global.GVA_DB.Table("upload_file").Where("task_id = ?", taskId).Order("id desc").Limit(1).Find(&lastRecord) fmt.Println(lastRecord) version = lastRecord.Version + 1 recordArr := []response.UploadFileResponse{} global.GVA_DB.Table("upload_file").Where("task_id = ?", taskId).Find(&recordArr) fmt.Println(recordArr) } filePath, key, md5String, uploadErr := e.UploadFileFunc(header, strconv.Itoa(taskId)) if uploadErr != nil { panic(err) } s := strings.Split(header.Filename, ".") f := response.UploadFileResponse{ TaskID: taskId, ResponsiblePerson: user, Url: prefix + filePath, Name: header.Filename, Tag: s[len(s)-1], Key: key, Version: version, Md5String: md5String, State: 1, } return f, e.Upload(f) } //下载文件 func (e *TaskConfService) DownloadFile(taskId int, md5String string) (info response.DownloadFile, err error) { var file response.UploadFileResponse //改由存储至数据库的时候拼接前缀 //var prefix string = global.GVA_CONFIG.PrefixUrl.PrefixLocal //数据库中无记录,即不需要更新 //err = global.GVA_DB.Table("upload_file").Where("task_id = ? and state = 1", taskId).Order("id desc").First(&file).Error //if errors.Is(err, gorm.ErrRecordNotFound) { // info = response.DownloadFile{ // Url: "", // Md5String: "", // Flag: false, // } // return info, errors.New("无对应脚本") //} // //if file.Md5String == md5String { // info = response.DownloadFile{ // Url: "", // Md5String: "", // Flag: false, // } // return info, errors.New("不需要更新") //} else { // fullUrl := file.Url // info = response.DownloadFile{ // Url: fullUrl, // Md5String: file.Md5String, // Flag: true, // } //} //先对比缓存中的md5string,如果缓存中没有,返回无对应脚本;如果缓存中md5一致,则返回不需要更新 //最后更新的时候再查询数据库 c := context.Background() key := fmt.Sprintf(SCRIPTDOWNLOADCHECK, taskId) existMd5, err := global.GVA_REDIS.Get(c, key).Result() if err != nil { //不存在脚本 return info, errors.New("无对应脚本") } if existMd5 == "无数据" { //脚本不存在 return info, errors.New("脚本不存在") } if existMd5 == md5String { //不需要更新 return info, errors.New("不需要更新") } err = global.GVA_DB.Table("upload_file").Where("task_id = ? and state = 1", taskId).Order("id desc").First(&file).Error if err != nil { return info, err } else { fullUrl := file.Url info = response.DownloadFile{ Url: fullUrl, Md5String: file.Md5String, Flag: true, } } //将查找出来的md5值重新加回去 err = global.GVA_REDIS.Set(c, key, file.Md5String, 0).Err() if err != nil { global.GVA_LOG.Info("添加脚本md5值缓存失败:" + err.Error() + time.Now().Format("2006-01-02 15:04:05")) } return info, err } //条件查询脚本列表 func (e *TaskConfService) GetScriptList(script task.GameScriptResponse, info request.PageInfo, order string, desc bool) (list interface{}, total int64, err error) { //获取分页数据 limit := info.PageSize offset := (info.Page - 1) * info.PageSize //绑定操作结构体 db := global.GVA_DB.Table("upload_file").Model(&task.GameScriptResponse{}) var scriptList []task.GameScriptResponse //条件查询 if script.ResponsiblePerson != "" { db = db.Where("responsible_person = ?", script.ResponsiblePerson) } if script.TaskID != 0 { db = db.Where("task_id = ?", script.TaskID) } //先过滤在排序 if err = db.Count(&total).Error; err != nil { return scriptList, total, err } else { //分页 db.Limit(limit).Offset(offset) //判断是否有排序字段 if order != "" { var orderStr string orderMap := make(map[string]bool, 1) orderMap["create_time"] = true orderMap["task_id"] = true orderMap["name"] = true orderMap["responsible_person"] = true orderMap["version"] = true if orderMap[order] { //合法排序字符 if desc { orderStr = order + " desc" } else { orderStr = order } } else { //传入排序字段非法 err = fmt.Errorf("传入非法字段 %v", order) return scriptList, total, err } err = db.Order(orderStr).Find(&scriptList).Error } else { //默认按照名字升序排序 err = db.Order("id desc").Find(&scriptList).Error } } return scriptList, total, err } //更改脚本状态 func (e *TaskConfService) UpdateScriptStatus(c taskReq.UpdateScriptStatusRequest) (err error) { var entity response.UploadFileResponse err = global.GVA_DB.Table("upload_file").Where("id = ?", c.Id).First(&entity).Error if errors.Is(err, gorm.ErrRecordNotFound) { return errors.New("请传入正确的Id") } //更新数据库记录 err = global.GVA_DB.Table("upload_file").Where("id = ?", c.Id).Update("state", c.State).Error //更新缓存状态 err1 := e.UpdateRedisCache(entity.TaskID) if err1 != nil { global.GVA_LOG.Info("更新脚本缓存失败:" + err1.Error() + time.Now().Format("2006-01-02 15:04:05")) } return err } //更改推送标准 func (e *TaskConfService) JudgeOperate(taskConf task.TaskConf) (err error) { //查找数据库中是否有这条记录 var entity task.TaskConf err = global.GVA_DB.Model(&task.TaskConf{}).Where("task_id = ?", taskConf.TaskId).First(&entity).Error //如果没有,创建 if errors.Is(err, gorm.ErrRecordNotFound) { return global.GVA_DB.Model(&task.TaskConf{}).Create(&taskConf).Error } //如果有,更新 return global.GVA_DB.Model(&task.TaskConf{}).Where("task_id = ?", taskConf.TaskId).Omit("task_id", "user").Updates(map[string]interface{}{"add_fee_notice": taskConf.AddFeeNotice, "simulator_type": taskConf.SimulatorType}).Error } //删除上传脚本 func (e *TaskConfService) DeleteScript(file task.GameScriptResponse) (err error) { //七牛云删除所需要的条件 mac := qbox.NewMac(ACCESSKEY, SECRETKEY) cfg := storage.Config{ // 是否使用https域名进行资源管理 UseHTTPS: true, } // 指定空间所在的区域,如果不指定将自动探测 // 如果没有特殊需求,默认不需要指定 //cfg.Region=&storage.ZoneHuabei bucketManager := storage.NewBucketManager(mac, &cfg) //删除数据库记录 var entity task.GameScriptResponse err = global.GVA_DB.Table("upload_file").Where("id", file.Id).First(&entity).Error if errors.Is(err, gorm.ErrRecordNotFound) { return errors.New("无此条脚本记录") } key := file.Url[30:] fmt.Println(key) err = global.GVA_DB.Table("upload_file").Delete(&entity).Error if err != nil { return err } //更新缓存状态 err = e.UpdateRedisCache(entity.TaskID) if err != nil { global.GVA_LOG.Info("更新脚本缓存失败:" + err.Error() + time.Now().Format("2006-01-02 15:04:05")) } //删除七牛云的记录 //删除七牛云之前先做判断 if key == "" { return errors.New("请传入正确的key!") } if key[:13] != "shuyou/script" { return errors.New("请传入正确的key!") } err = bucketManager.Delete(BUCKET, key) fmt.Println(err) return err } //批量删除脚本 func (e *TaskConfService) BulkDeleteScript(ids []int) (err error) { var total int64 var scriptList []task.GameScriptResponse taskIdMap := make(map[int]int) db := global.GVA_DB.Table("upload_file").Where("id in ?", ids) err = db.Count(&total).Error if err != nil { return err } err = db.Find(&scriptList).Error if err != nil { return } keys := make([]string, len(scriptList)) //获取key数组 及task_id的map for k,_ := range scriptList { fmt.Println(scriptList[k].Url[30:]) keys[k] = scriptList[k].Url[30:] if taskIdMap[scriptList[k].TaskID] != 0 { taskIdMap[scriptList[k].TaskID]++ } else { taskIdMap[scriptList[k].TaskID] = 1 } } fmt.Println(keys) //批量删除脚本数据库记录 err = global.GVA_DB.Model(&task.GameScriptResponse{}).Delete("id in ?", ids).Error if err != nil { return err } //遍历taskIdMap 更新缓存状态 for k,_ := range taskIdMap { err := e.UpdateRedisCache(k) if err != nil { global.GVA_LOG.Info("更新脚本md5值缓存失败:" + err.Error() + time.Now().Format("2006-01-02 15:04:05")) return err } } return //批量删除七牛云脚本记录 } //更新缓存状态 func (e *TaskConfService) UpdateRedisCache (taskId int) (err error) { var file response.UploadFileResponse contexts := context.Background() //查找合格的file key := fmt.Sprintf(SCRIPTDOWNLOADCHECK, taskId) err = global.GVA_DB.Table("upload_file").Where("task_id = ? and state = 1", taskId).Order("id desc").First(&file).Error if errors.Is(err, gorm.ErrRecordNotFound) { //已无符合条件脚本 //删除redis缓存,并且打印日志说明 fmt.Println("无可用脚本,尝试删除") err := global.GVA_REDIS.Set(contexts, key, "无数据", time.Second * 1).Err() if err != nil { global.GVA_LOG.Info("删除脚本md5值缓存失败:" + err.Error() + time.Now().Format("2006-01-02 15:04:05")) return err } } else { //找到了数据库记录,更新缓存 fmt.Println("更新缓存记录") err := global.GVA_REDIS.Set(contexts, key, file.Md5String, 0).Err() if err != nil { global.GVA_LOG.Info("更新脚本md5值缓存失败:" + err.Error() + time.Now().Format("2006-01-02 15:04:05")) return err } } return err } func (e *TaskConfService) BulkDeleteQiNiuYunScript(keys []string) (err error) { //七牛云删除所需要的条件 mac := qbox.NewMac(ACCESSKEY, SECRETKEY) cfg := storage.Config{ // 是否使用https域名进行资源管理 UseHTTPS: true, } // 指定空间所在的区域,如果不指定将自动探测 // 如果没有特殊需求,默认不需要指定 //cfg.Region=&storage.ZoneHuabei bucketManager := storage.NewBucketManager(mac, &cfg) //每个batch的操作数量不可以超过1000个,如果总数量超过1000,需要分批发送 bucket := BUCKET //验证keys安全性 for _,v := range keys { //删除七牛云之前先做判断 if v == "" { return errors.New("请传入正确的key!") } if v[:13] != "shuyou/script" { return errors.New("请传入正确的key!") } } deleteOps := make([]string, 0, len(keys)) for _, key := range keys { deleteOps = append(deleteOps, storage.URIDelete(bucket, key)) } rets, err := bucketManager.Batch(deleteOps) if len(rets) == 0 { // 处理错误 if e, ok := err.(*storage.ErrorInfo); ok { fmt.Printf("batch error, code:%s", e.Code) } else { fmt.Printf("batch error, %s", err) } return } // 返回 rets,先判断 rets 是否 for _, ret := range rets { // 200 为成功 if ret.Code == 200 { fmt.Printf("%d\n", ret.Code) } else { err = errors.New(ret.Data.Error) fmt.Printf("%s\n", ret.Data.Error) } } return err }