ソースを参照

feat: Material 增加 AddMaterialFromReader 与 AddVideoFromReader 方法 (#780)

* feat: Material 增加 AddMaterialFromReader 与 AddVideoFromReader 方法

* update: 调整 PostFileFromReader 参数。
sam 1 年間 前
コミット
6b3532cc2d
2 ファイル変更67 行追加22 行削除
  1. 33 8
      officialaccount/material/material.go
  2. 34 14
      util/http.go

+ 33 - 8
officialaccount/material/material.go

@@ -4,6 +4,8 @@ import (
 	"encoding/json"
 	"errors"
 	"fmt"
+	"io"
+	"os"
 
 	"github.com/silenceper/wechat/v2/officialaccount/context"
 	"github.com/silenceper/wechat/v2/util"
@@ -160,8 +162,8 @@ type resAddMaterial struct {
 	URL     string `json:"url"`
 }
 
-// AddMaterial 上传永久性素材(处理视频需要单独上传)
-func (material *Material) AddMaterial(mediaType MediaType, filename string) (mediaID string, url string, err error) {
+// AddMaterialFromReader 上传永久性素材(处理视频需要单独上传),从 io.Reader 中读取
+func (material *Material) AddMaterialFromReader(mediaType MediaType, filename string, reader io.Reader) (mediaID string, url string, err error) {
 	if mediaType == MediaTypeVideo {
 		err = errors.New("永久视频素材上传使用 AddVideo 方法")
 		return
@@ -174,7 +176,7 @@ func (material *Material) AddMaterial(mediaType MediaType, filename string) (med
 
 	uri := fmt.Sprintf("%s?access_token=%s&type=%s", addMaterialURL, accessToken, mediaType)
 	var response []byte
-	response, err = util.PostFile("media", filename, uri)
+	response, err = util.PostFileFromReader("media", filename, uri, reader)
 	if err != nil {
 		return
 	}
@@ -192,13 +194,24 @@ func (material *Material) AddMaterial(mediaType MediaType, filename string) (med
 	return
 }
 
+// AddMaterial 上传永久性素材(处理视频需要单独上传)
+func (material *Material) AddMaterial(mediaType MediaType, filename string) (mediaID string, url string, err error) {
+	f, err := os.Open(filename)
+	if err != nil {
+		return
+	}
+	defer func() { _ = f.Close() }()
+
+	return material.AddMaterialFromReader(mediaType, filename, f)
+}
+
 type reqVideo struct {
 	Title        string `json:"title"`
 	Introduction string `json:"introduction"`
 }
 
-// AddVideo 永久视频素材文件上传
-func (material *Material) AddVideo(filename, title, introduction string) (mediaID string, url string, err error) {
+// AddVideoFromReader 永久视频素材文件上传,从 io.Reader 中读取
+func (material *Material) AddVideoFromReader(filename, title, introduction string, reader io.Reader) (mediaID string, url string, err error) {
 	var accessToken string
 	accessToken, err = material.GetAccessToken()
 	if err != nil {
@@ -219,9 +232,10 @@ func (material *Material) AddVideo(filename, title, introduction string) (mediaI
 
 	fields := []util.MultipartFormField{
 		{
-			IsFile:    true,
-			Fieldname: "media",
-			Filename:  filename,
+			IsFile:     true,
+			Fieldname:  "media",
+			Filename:   filename,
+			FileReader: reader,
 		},
 		{
 			IsFile:    false,
@@ -250,6 +264,17 @@ func (material *Material) AddVideo(filename, title, introduction string) (mediaI
 	return
 }
 
+// AddVideo 永久视频素材文件上传
+func (material *Material) AddVideo(filename, title, introduction string) (mediaID string, url string, err error) {
+	f, err := os.Open(filename)
+	if err != nil {
+		return "", "", err
+	}
+	defer func() { _ = f.Close() }()
+
+	return material.AddVideoFromReader(filename, title, introduction, f)
+}
+
 type reqDeleteMaterial struct {
 	MediaID string `json:"media_id"`
 }

+ 34 - 14
util/http.go

@@ -158,12 +158,26 @@ func PostFile(fieldName, filename, uri string) ([]byte, error) {
 	return PostMultipartForm(fields, uri)
 }
 
+// PostFileFromReader 上传文件,从 io.Reader 中读取
+func PostFileFromReader(filedName, fileName, uri string, reader io.Reader) ([]byte, error) {
+	fields := []MultipartFormField{
+		{
+			IsFile:     true,
+			Fieldname:  filedName,
+			Filename:   fileName,
+			FileReader: reader,
+		},
+	}
+	return PostMultipartForm(fields, uri)
+}
+
 // MultipartFormField 保存文件或其他字段信息
 type MultipartFormField struct {
-	IsFile    bool
-	Fieldname string
-	Value     []byte
-	Filename  string
+	IsFile     bool
+	Fieldname  string
+	Value      []byte
+	Filename   string
+	FileReader io.Reader
 }
 
 // PostMultipartForm 上传文件或其他多个字段
@@ -182,15 +196,21 @@ func PostMultipartForm(fields []MultipartFormField, uri string) (respBody []byte
 				return
 			}
 
-			fh, e := os.Open(field.Filename)
-			if e != nil {
-				err = fmt.Errorf("error opening file , err=%v", e)
-				return
-			}
-			defer fh.Close()
-
-			if _, err = io.Copy(fileWriter, fh); err != nil {
-				return
+			if field.FileReader == nil {
+				fh, e := os.Open(field.Filename)
+				if e != nil {
+					err = fmt.Errorf("error opening file , err=%v", e)
+					return
+				}
+				_, err = io.Copy(fileWriter, fh)
+				_ = fh.Close()
+				if err != nil {
+					return
+				}
+			} else {
+				if _, err = io.Copy(fileWriter, field.FileReader); err != nil {
+					return
+				}
 			}
 		} else {
 			partWriter, e := bodyWriter.CreateFormField(field.Fieldname)
@@ -215,7 +235,7 @@ func PostMultipartForm(fields []MultipartFormField, uri string) (respBody []byte
 	}
 	defer resp.Body.Close()
 	if resp.StatusCode != http.StatusOK {
-		return nil, err
+		return nil, fmt.Errorf("http code error : uri=%v , statusCode=%v", uri, resp.StatusCode)
 	}
 	respBody, err = io.ReadAll(resp.Body)
 	return