package service import ( "StuAcaWorksAI/dao" "StuAcaWorksAI/proto" "StuAcaWorksAI/worker" "crypto/md5" "encoding/base64" "errors" "fmt" "github.com/gin-gonic/gin" "github.com/google/uuid" "io" "log" "mime/multipart" "os" "path" "regexp" "strings" "time" ) // 检查path是否存在当前日期文件夹如(2024-08-09),不存在则path下当前日期文件夹创建,存在则返回 func GetFilePath(path string) string { //当前日期,格式为2024-08-09 date := time.Now().Format("2006-01-02") //拼接文件路径 filePath := path + "/" + date //判断文件夹是否存在 _, err := os.Stat(filePath) if err != nil { //不存在则创建 os.MkdirAll(filePath, os.ModePerm) } return filePath } func SaveFile(c *gin.Context, file *multipart.FileHeader, uploadType string) (string, string, error) { //获取文件后缀 fileSuffix := path.Ext(file.Filename) //生成文件名 fileStoreName := uuid.NewString() + fileSuffix //生成文件路径 path_ := GetFilePath(proto.FILE_BASE_DIR) filePath := path_ + "/" + fileStoreName //保存文件 if err := c.SaveUploadedFile(file, filePath); err != nil { return "", "", err } if uploadType == "2" { worker.PushRedisList("video_need_handle", filePath) } return path_, fileStoreName, nil } func CalculateFileMd5(file io.Reader) string { hash := md5.New() if _, err := io.Copy(hash, file); err != nil { return "" } return fmt.Sprintf("%x", hash.Sum(nil)) } func CheckUploadRequestParameters(req *proto.FileUploadReq) error { var err error if req.AuthType == "" { err = fmt.Errorf("auth_type is empty") } if req.UploadType == "" { req.UploadType = "1" } if req.UploadType != "1" { req.UploadType = "2" } if proto.File_Type[req.Type] == 0 { err = fmt.Errorf("file type is invalid") } return err } func CreateConfigFile(req *proto.AddConfigFileReq, userId int) error { var err error user := GetUserByIDWithCache(userId) if user.ID == 0 || user.Role != "admin" { err = fmt.Errorf("user not found or no permission") return err } if req.FileName == "" || req.FilePath == "" { err = fmt.Errorf("file name or file path is empty") return err } //查看系统中是否存在文件,不存在则创建 file := req.FilePath + "/" + req.FileName //正则判断文件名是否合法 pattern := `^/([^/:\*?]+/)*([^/:\*?]+)?$` reg := regexp.MustCompile(pattern) if reg.MatchString(file) == false { err = fmt.Errorf("file path is invalid") return err } _, fileErr := os.Stat(file) if fileErr != nil { //创建文件 f, err2 := os.Create(file) if err2 != nil { err = err2 return err } defer func(f *os.File) { err := f.Close() if err != nil { fmt.Println("Error closing file") } }(f) } //创建 configFile := dao.ConfigFile{FilePath: req.FilePath, FileName: req.FileName, AuthID: userId} _, err3 := dao.CreateConfigFile(configFile) if err3 != nil { err = err3 return err } return err } func DeleteConfigFile(req *proto.ConfigFileReq, userId int) error { var err error user := GetUserByIDWithCache(userId) if user.ID == 0 || user.Role != "admin" { err = fmt.Errorf("user not found or no permission") return err } //删除文件 config_file := dao.FindConfigFileByID(req.ID, userId) if config_file.ID == 0 { err = fmt.Errorf("config file not found") return err } err = dao.DeleteConfigFileByID(req.ID) if req.DelFile { file := config_file.FilePath + "/" + config_file.FileName err = os.Remove(file) if err != nil { return err } } //删除数据库记录 return err } type ConfigFileService struct { } func (c *ConfigFileService) UpdateConfigFile(req *proto.ConfigFileReq, userId int) error { var err error user := GetUserByIDWithCache(userId) if user.ID == 0 || user.Role != "admin" { err = fmt.Errorf("user not found or no permission") return err } config_file := dao.FindConfigFileByID(req.ID, userId) if config_file.ID == 0 { err = fmt.Errorf("config file not found") return err } //修改文件名 if req.FileName != "" { file := config_file.FilePath + "/" + config_file.FileName new_file := config_file.FilePath + "/" + req.FileName err = os.Rename(file, new_file) if err != nil { return err } err = dao.UpdateConfigFileByID(req.ID, dao.ConfigFile{FileName: req.FileName}) } if req.Content != "" { file := config_file.FilePath + "/" + config_file.FileName f, err2 := os.OpenFile(file, os.O_WRONLY|os.O_TRUNC, 0644) //打开文件,清空文件内容,写入新内容,不存在则创建 if err2 != nil { err = err2 return err } defer func(f *os.File) { err3 := f.Close() if err3 != nil { fmt.Println("Error closing file") } }(f) _, err = f.WriteString(req.Content) if err != nil { return err } } return err } func (c *ConfigFileService) SearchOneConfigFile(req *proto.ConfigFileReq, userId int) ([]proto.SearchOneConfigFileResp, error) { user := GetUserByIDWithCache(userId) if user.ID == 0 || user.Role != "admin" { return []proto.SearchOneConfigFileResp{}, fmt.Errorf("user not found or no permission") } config_file := dao.FindConfigFileByID(req.ID, userId) if config_file.ID == 0 { return []proto.SearchOneConfigFileResp{}, fmt.Errorf("config file not found") } file := config_file.FilePath + "/" + config_file.FileName content, err2 := os.ReadFile(file) if err2 != nil { return []proto.SearchOneConfigFileResp{}, err2 } resp := []proto.SearchOneConfigFileResp{{ID: config_file.ID, FilePath: config_file.FilePath, FileName: config_file.FileName, Content: string(content), CreatedAt: config_file.CreatedAt, UpdatedAt: config_file.UpdatedAt}} return resp, nil } func (c *ConfigFileService) SearchAllConfigFile(userId int) ([]dao.ConfigFile, error) { user := GetUserByIDWithCache(userId) if user.ID == 0 || user.Role != "admin" { return []dao.ConfigFile{}, fmt.Errorf("user not found or no permission") } config_files := dao.FindConfigFileByAuthID(userId) return config_files, nil } func UpdateUserFile(userID int, fileAuthID int, fileAuthName string) error { fileAuth := dao.FindFileAuthByID(fileAuthID) if fileAuth.ID == 0 { return errors.New("file auth not found") } if fileAuth.AuthID != userID { return errors.New("no permission") } fileAuth.UserFileName = fileAuthName err := dao.UpdateFileAuthByID(fileAuthID, fileAuth) return err } func DeleteUserFile(userID, fileAuthID int) error { fileAuth := dao.FindFileAuthByID(fileAuthID) if fileAuth.ID == 0 { return errors.New("file auth not found") } if fileAuth.AuthID != userID { return errors.New("no permission") } err := dao.DeleteFileAuthByID(fileAuthID) return err } func CreateUserFile(userID int, fileAuthName string, fileID int, UploadType string) dao.FileAuth { //先查fileAuthName是否存在 fileAuth := dao.FindFileAuthByName(fileAuthName, userID) if fileAuth.ID != 0 { log.Println("file auth name already exist, please change another name: ", fileAuthName) //将要保存的文件名改为fileAuthName+uuid strs := strings.Split(fileAuth.UserFileName, ".") //当前时间戳 timestamp := time.Now().Unix() timestampStr := fmt.Sprintf("%d", timestamp) fileAuthName = strs[0] + "_" + timestampStr + "." + strs[1] //return fileAuth } fileAuth_ := dao.CreateFileAuth(userID, fileID, fileAuthName, UploadType, 1, "") return fileAuth_ } func FindUserFileList(userID int, uploadType string) []dao.UserFileListResp { fileList, files := dao.FileUserFileList(userID, uploadType) filesM := make(map[uint]dao.File) for _, file := range files { filesM[file.ID] = file } var res []dao.UserFileListResp for _, file := range fileList { fileStoreName := filesM[uint(file.FileID)].FileStoreName r := dao.UserFileListResp{FileAuth: file, FileStoreName: fileStoreName} res = append(res, r) } log.Println("FindUserFileList res:", len(res)) return res } func CreateUserFileAfterUnique() { } func FindFileContent(userID int, userReq *proto.FileContentReq) ([]dao.FileContent, error) { fileAuth := dao.FindFileAuthByID(userReq.UserFileID) if fileAuth.ID == 0 { return nil, errors.New("file auth not found") } if fileAuth.AuthID != userID { return nil, errors.New("no permission") } //获取文件基础信息 file := dao.FindFileByID(fileAuth.FileID, userID) //判断文件类型\ fileType := strings.Split(file.FileStoreName, ".")[1] //如果文件类型是图片 if fileType == "jpg" || fileType == "png" || fileType == "jpeg" || fileType == "gif" { return nil, errors.New("file type is image") } //获取文件内容 fileContents := dao.FindFileContentByFileID(fileAuth.FileID) if len(fileContents) == 0 { //直接读取文件内容 filePath := file.FilePath + "/" + file.FileStoreName fileContentStr, err := readFileContent(filePath) if err != nil { return nil, err } var fileContent dao.FileContent fileContent.FileID = -1 fileContent.FileContent = fileContentStr fileContents = append(fileContents, fileContent) } return fileContents, nil } func CreateFileContent(userID, fileID int, fileContent string) (uint, error) { user := GetUserByIDWithCache(userID) if user.Role != "admin" { return 0, errors.New("no permission") } //查找文件是否存在 fileContentC, err := dao.FindFileContentByFileIDAndContentID(fileID) if err != nil { return 0, err } //如果文件存在,则更新文件内容 if fileContentC.ID != 0 { return dao.UpdateFileContentByID(fileContentC.ID, fileContent) } return dao.CreateFileContent(fileID, fileContent) } func GetFileWillConvertContentFileList(userID int) ([]dao.File, error) { user := GetUserByIDWithCache(userID) if user.Role != "admin" { return nil, errors.New("no permission") } files, err2 := dao.GetFileWillConvertContentFileList() if err2 != nil { return nil, err2 } var res []dao.File for _, file := range files { fileType := strings.Split(file.FileStoreName, ".")[1] //如果文件类型是图片则不需要返回 if fileType == "jpg" || fileType == "png" || fileType == "jpeg" || fileType == "gif" { continue } //如果文件类型是视频则不需要返回 if fileType == "mp4" || fileType == "avi" || fileType == "rmvb" || fileType == "mkv" { continue } //如果文件类型是音频则不需要返回 if fileType == "mp3" || fileType == "wav" || fileType == "wma" { continue } //如果文件类型是压缩包则不需要返回 if fileType == "zip" || fileType == "rar" || fileType == "7z" { continue } res = append(res, file) } return res, nil } func readFileContent(filePath string) (string, error) { file, err := os.Open(filePath) if err != nil { return "", err } defer file.Close() content, err := io.ReadAll(file) if err != nil { return "", err } return string(content), nil } func FindFileContentV2(fileID, userID int) ([]dao.FileContent, error) { //获取文件基础信息 file := dao.FindFileByID(fileID, userID) //判断文件类型\ fileType := strings.Split(file.FileStoreName, ".")[1] //如果文件类型是图片 if fileType == "jpg" || fileType == "png" || fileType == "jpeg" || fileType == "gif" { return nil, errors.New("file type is image") } //获取文件内容 fileContents := dao.FindFileContentByFileID(fileID) if len(fileContents) == 0 { //直接读取文件内容 filePath := file.FilePath + "/" + file.FileStoreName fileContentStr, err := readFileContent(filePath) if err != nil { return nil, err } var fileContent dao.FileContent fileContent.FileID = -1 fileContent.FileContent = fileContentStr fileContents = append(fileContents, fileContent) } return fileContents, nil } func FindImageFileContent(fileID, userID int) (string, error) { //获取文件基础信息 file := dao.FindFileByID(fileID, userID) //判断文件类型\ fileType := strings.Split(file.FileStoreName, ".")[1] //如果文件类型是图片 if fileType != "jpg" && fileType != "png" && fileType != "jpeg" && fileType != "gif" { return "", errors.New("file type is not image") } //直接读取文件内容 filePath := file.FilePath + "/" + file.FileStoreName base64Str, err := readImageFile(filePath) if err != nil { return "", err } return base64Str, nil } // readImageFile 函数用于读取指定路径的图片文件并将其内容转换为 Base64 编码字符串 func readImageFile(filePath string) (string, error) { // 打开图片文件 file, err := os.Open(filePath) if err != nil { return "", fmt.Errorf("无法打开文件: %w", err) } // 确保文件在函数结束时关闭 defer file.Close() // 读取图片文件内容 imageData, err := io.ReadAll(file) if err != nil { return "", fmt.Errorf("无法读取文件内容: %w", err) } // 将图片数据进行 Base64 编码 base64Encoded := base64.StdEncoding.EncodeToString(imageData) return base64Encoded, nil }