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 }