1
0
mirror of https://github.com/fumiama/NanoBot.git synced 2026-06-05 10:40:24 +08:00
Files
NanoBot/http.go
2023-10-14 13:15:38 +09:00

179 lines
4.9 KiB
Go

package nano
import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"mime/multipart"
"net/http"
"net/url"
"os"
"reflect"
"strings"
base14 "github.com/fumiama/go-base16384"
)
// HTTPRequsetConstructer ...
type HTTPRequsetConstructer func(ep string, contenttype string, auth string, body io.Reader) (*http.Request, error)
func newHTTPEndpointRequestWithAuth(method, contenttype, ep string, auth string, body io.Reader) (req *http.Request, err error) {
req, err = http.NewRequest(method, OpenAPI+ep, body)
if err != nil {
return
}
req.Header.Add("Authorization", auth)
if contenttype == "" {
contenttype = "application/json"
}
req.Header.Add("Content-Type", contenttype)
return
}
// NewHTTPEndpointGetRequestWithAuth 新建带鉴权头的 HTTP GET 请求
func NewHTTPEndpointGetRequestWithAuth(ep string, contenttype string, auth string, body io.Reader) (*http.Request, error) {
return newHTTPEndpointRequestWithAuth("GET", contenttype, ep, auth, body)
}
// NewHTTPEndpointPutRequestWithAuth 新建带鉴权头的 HTTP PUT 请求
func NewHTTPEndpointPutRequestWithAuth(ep string, contenttype string, auth string, body io.Reader) (*http.Request, error) {
return newHTTPEndpointRequestWithAuth("PUT", contenttype, ep, auth, body)
}
// NewHTTPEndpointDeleteRequestWithAuth 新建带鉴权头的 HTTP DELETE 请求
func NewHTTPEndpointDeleteRequestWithAuth(ep string, contenttype string, auth string, body io.Reader) (*http.Request, error) {
return newHTTPEndpointRequestWithAuth("DELETE", contenttype, ep, auth, body)
}
// NewHTTPEndpointPostRequestWithAuth 新建带鉴权头的 HTTP POST 请求
func NewHTTPEndpointPostRequestWithAuth(ep string, contenttype string, auth string, body io.Reader) (*http.Request, error) {
return newHTTPEndpointRequestWithAuth("POST", contenttype, ep, auth, body)
}
// NewHTTPEndpointPatchRequestWithAuth 新建带鉴权头的 HTTP PATCH 请求
func NewHTTPEndpointPatchRequestWithAuth(ep string, contenttype string, auth string, body io.Reader) (*http.Request, error) {
return newHTTPEndpointRequestWithAuth("PATCH", contenttype, ep, auth, body)
}
// WriteHTTPQueryIfNotNil 如果非空则将请求添加到 baseurl 后
//
// ex. WriteHTTPQueryIfNotNil("http://a.com/api", "a", 0, "b", 1, "c", 2) is http://a.com/api?b=1&c=2
func WriteHTTPQueryIfNotNil(baseurl string, queries ...any) string {
if len(queries) < 2 {
return baseurl
}
hasstart := false
queryname := ""
sb := strings.Builder{}
for i, q := range queries {
if i%2 == 0 {
queryname = q.(string)
continue
}
if reflect.ValueOf(q).IsZero() {
continue
}
if !hasstart {
sb.WriteString(baseurl)
sb.WriteByte('?')
hasstart = true
}
sb.WriteString(queryname)
sb.WriteByte('=')
sb.WriteString(url.QueryEscape(fmt.Sprint(q)))
sb.WriteByte('&')
}
if sb.Len() <= 4 {
return baseurl
}
return sb.String()[:sb.Len()-1]
}
// WriteBodyFromJSON 从 json 结构体 ptr 写入 bytes.Buffer, 忽略 error (内部使用不会出错)
func WriteBodyFromJSON(ptr any) *bytes.Buffer {
buf := bytes.NewBuffer(make([]byte, 0, 1024))
_ = json.NewEncoder(buf).Encode(ptr)
return buf
}
// WriteBodyByMultipartFormData 使用 multipart/form-data 上传
func WriteBodyByMultipartFormData(params ...any) (*bytes.Buffer, string, error) {
if len(params)%2 != 0 {
panic("invalid params to " + getThisFuncName())
}
fieldname := ""
buf := bytes.NewBuffer(make([]byte, 0, 65536))
w := multipart.NewWriter(buf)
defer w.Close()
for i, x := range params {
if i%2 == 0 { // 参数
fieldname = x.(string)
continue
}
rx := reflect.ValueOf(x)
if rx.IsZero() {
continue
}
r, err := w.CreateFormField(fieldname)
if err != nil {
return nil, "", err
}
if rx.Elem().Kind() == reflect.Struct { // 使用 json 编码
err = json.NewEncoder(r).Encode(x)
if err != nil {
return nil, "", err
}
continue
}
switch o := x.(type) {
case string:
if strings.HasPrefix(o, "file:///") { // 是文件路径
f, err := os.Open(o[8:])
if err != nil {
return nil, "", err
}
defer f.Close()
_, err = io.Copy(r, f)
if err != nil {
return nil, "", err
}
continue
}
if strings.HasPrefix(o, "base64://") { // 是 base64
_, err = io.Copy(r, base64.NewDecoder(base64.StdEncoding, bytes.NewBufferString(o[9:])))
if err != nil {
return nil, "", err
}
continue
}
if strings.HasPrefix(o, "base16384://") { // 是 base16384
_, err = io.Copy(r, base14.NewDecoder(bytes.NewBufferString(o[12:])))
if err != nil {
return nil, "", err
}
continue
}
_, err = io.WriteString(r, o)
if err != nil {
return nil, "", err
}
continue
case []byte:
_, err = r.Write(o)
if err != nil {
return nil, "", err
}
continue
default:
_, err = io.WriteString(r, fmt.Sprint(o))
if err != nil {
return nil, "", err
}
continue
}
}
return buf, w.FormDataContentType(), nil
}