github.com/fumiama/NanoBot@v0.0.0-20231122134259-c22d8183efca/openapi.go (about)

     1  package nano
     2  
     3  import (
     4  	"encoding/json"
     5  	"io"
     6  	"net/http"
     7  	"reflect"
     8  	"strconv"
     9  	"strings"
    10  	"unsafe"
    11  
    12  	"github.com/pkg/errors"
    13  )
    14  
    15  const (
    16  	// StandardAPI 正式环境接口域名
    17  	StandardAPI = `https://api.sgroup.qq.com`
    18  	// SandboxAPI 沙箱环境接口域名
    19  	SandboxAPI = `https://sandbox.api.sgroup.qq.com`
    20  	// AccessTokenAPI 获取接口凭证的 API
    21  	AccessTokenAPI = "https://bots.qq.com/app/getAppAccessToken"
    22  )
    23  
    24  var (
    25  	OpenAPI = StandardAPI // OpenAPI 实际使用的 API, 默认 StandardAPI, 可自行赋值配置
    26  )
    27  
    28  // CodeMessageBase 各种消息都有的 code + message 基类
    29  type CodeMessageBase struct {
    30  	C int    `json:"code"`
    31  	M string `json:"message"`
    32  }
    33  
    34  func (bot *Bot) dohttprequest(constructer HTTPRequsetConstructer, ep, contenttype string, ptr any, body io.Reader) error {
    35  	appid := ""
    36  	if bot.IsV2() {
    37  		appid = bot.AppID
    38  	}
    39  	req, err := constructer(ep, contenttype, bot.Authorization(), appid, body)
    40  	if err != nil {
    41  		return errors.Wrap(err, getCallerFuncName())
    42  	}
    43  	resp, err := bot.client.Do(req)
    44  	if err != nil {
    45  		return errors.Wrap(err, getCallerFuncName())
    46  	}
    47  	defer resp.Body.Close()
    48  	if resp.StatusCode == http.StatusNoContent {
    49  		return nil
    50  	}
    51  	errsb := strings.Builder{}
    52  	var respbase *CodeMessageBase
    53  	if resp.StatusCode >= http.StatusBadRequest {
    54  		errsb.WriteString("code: ")
    55  		errsb.WriteString(resp.Status)
    56  	}
    57  	if ptr == nil {
    58  		goto RET
    59  	}
    60  	err = json.NewDecoder(resp.Body).Decode(ptr)
    61  	if err != nil {
    62  		if errsb.Len() > 0 {
    63  			errsb.WriteString(", ")
    64  		}
    65  		errsb.WriteString("json: ")
    66  		errsb.WriteString(err.Error())
    67  		goto RET
    68  	}
    69  	if reflect.ValueOf(ptr).Elem().Kind() == reflect.Slice {
    70  		return nil
    71  	}
    72  	respbase = (*CodeMessageBase)(*(*unsafe.Pointer)(unsafe.Add(unsafe.Pointer(&ptr), unsafe.Sizeof(uintptr(0)))))
    73  	if respbase.C != 0 {
    74  		if errsb.Len() > 0 {
    75  			errsb.WriteString(", ")
    76  		}
    77  		errsb.WriteString("err: [")
    78  		errsb.WriteString(strconv.Itoa(respbase.C))
    79  		errsb.WriteString("] ")
    80  		if len([]rune(respbase.M)) > 256 {
    81  			errsb.WriteString(string([]rune(respbase.M)[:256]))
    82  			errsb.WriteString("...")
    83  		} else {
    84  			errsb.WriteString(respbase.M)
    85  		}
    86  	}
    87  RET:
    88  	if errsb.Len() > 0 {
    89  		return errors.Wrap(errors.New(errsb.String()), getCallerFuncName())
    90  	}
    91  	return nil
    92  }
    93  
    94  //go:generate go run codegen/getopenapiof/main.go ShardWSSGateway User Guild Channel Member RoleMembers GuildRoleList ChannelPermissions Message MessageSetting PinsMessage Schedule MessageReactionUsers
    95  
    96  // GetOpenAPI 从 ep 获取 json 结构化数据写到 ptr, ptr 除 Slice 外必须在开头继承 CodeMessageBase
    97  func (bot *Bot) GetOpenAPI(ep, contenttype string, ptr any) error {
    98  	return bot.dohttprequest(NewHTTPEndpointGetRequestWithAuth, ep, contenttype, ptr, nil)
    99  }
   100  
   101  // GetOpenAPIWithBody 不规范地从 ep 获取 json 结构化数据写到 ptr, ptr 除 Slice 外必须在开头继承 CodeMessageBase
   102  func (bot *Bot) GetOpenAPIWithBody(ep, contenttype string, ptr any, body io.Reader) error {
   103  	return bot.dohttprequest(NewHTTPEndpointGetRequestWithAuth, ep, contenttype, ptr, body)
   104  }
   105  
   106  //go:generate go run codegen/putopenapiof/main.go GuildRoleChannelID PinsMessage
   107  
   108  // PutOpenAPI 向 ep 发送 PUT 并获取 json 结构化数据返回写到 ptr, ptr 除 Slice 外必须在开头继承 CodeMessageBase
   109  func (bot *Bot) PutOpenAPI(ep, contenttype string, ptr any, body io.Reader) error {
   110  	return bot.dohttprequest(NewHTTPEndpointPutRequestWithAuth, ep, contenttype, ptr, body)
   111  }
   112  
   113  // DeleteOpenAPI 向 ep 发送 DELETE 请求
   114  func (bot *Bot) DeleteOpenAPI(ep, contenttype string, body io.Reader) error {
   115  	return bot.dohttprequest(NewHTTPEndpointDeleteRequestWithAuth, ep, contenttype, nil, body)
   116  }
   117  
   118  // DeleteOpenAPIWithPtr 带返回值地向 ep 发送 DELETE 请求
   119  func (bot *Bot) DeleteOpenAPIWithPtr(ep, contenttype string, ptr any, body io.Reader) error {
   120  	return bot.dohttprequest(NewHTTPEndpointDeleteRequestWithAuth, ep, contenttype, ptr, body)
   121  }
   122  
   123  //go:generate go run codegen/postopenapiof/main.go Channel GuildRoleCreate Message DMS
   124  
   125  // PostOpenAPI 从 ep 得到 json 结构化数据返回值写到 ptr, ptr 除 Slice 外必须在开头继承 CodeMessageBase
   126  func (bot *Bot) PostOpenAPI(ep, contenttype string, ptr any, body io.Reader) error {
   127  	return bot.dohttprequest(NewHTTPEndpointPostRequestWithAuth, ep, contenttype, ptr, body)
   128  }
   129  
   130  //go:generate go run codegen/patchopenapiof/main.go Channel GuildRolePatch
   131  
   132  // PatchOpenAPI 从 ep 得到 json 结构化数据返回值写到 ptr, ptr 除 Slice 外必须在开头继承 CodeMessageBase
   133  func (bot *Bot) PatchOpenAPI(ep, contenttype string, ptr any, body io.Reader) error {
   134  	return bot.dohttprequest(NewHTTPEndpointPatchRequestWithAuth, ep, contenttype, ptr, body)
   135  }