1
0
mirror of https://github.com/Mrs4s/go-cqhttp.git synced 2025-06-30 03:43:25 +00:00

Compare commits

..

23 Commits

Author SHA1 Message Date
bb03315930 try to support escape again. #9 2020-08-12 09:52:32 +08:00
5683db6324 fix #80. 2020-08-12 09:33:25 +08:00
f1ffa17d20 update MiraiGo. 2020-08-12 09:19:00 +08:00
69675aa0f9 fix #75. 2020-08-12 05:01:16 +08:00
782a3e2a39 add default 'http_config.post_message_format' value. 2020-08-11 17:47:16 +08:00
1967e687af fix perm error. 2020-08-11 17:38:33 +08:00
23d436972c save captcha to local file. close #71 2020-08-11 17:35:03 +08:00
129622dd24 fix reverse push issue. 2020-08-11 17:32:09 +08:00
19104d00a3 Merge pull request #78 from yyuueexxiinngg/patch-1
移除上报消息为array时的文本转义
2020-08-11 15:32:45 +08:00
6c0e78b60c Remove content escape when using array post message format. 2020-08-11 15:22:26 +08:00
a075f41a51 http post timeout setting supported. close #77 2020-08-11 15:19:54 +08:00
cdbf903361 Merge pull request #74 from Shigma/api-type-check
sendXXX api type check
2020-08-11 11:20:17 +08:00
906247fcf0 Merge pull request #70 from XYenon/master
Add support for post_message_format: array
2020-08-11 04:54:37 +08:00
72a7430841 add api type check 2020-08-10 20:43:31 +08:00
5c4f586c36 Use string format in db 2020-08-10 19:44:54 +08:00
5d2e202b0c Merge pull request #47 from purerosefallen/patch-1
Add Dockerfile
2020-08-10 16:57:34 +08:00
c27ebadbc4 Add support for post_message_format: array 2020-08-10 13:59:46 +08:00
d5a8f3ead2 Merge pull request #69 from Shigma/master
& escape should come first
2020-08-10 12:51:26 +08:00
03bfd9dd3d & escape should come first 2020-08-10 12:48:50 +08:00
0b02178402 supported voice download. 2020-08-10 12:38:58 +08:00
3819f2c2da fix #66 2020-08-10 10:31:50 +08:00
fdd517ee8c dockerignore 2020-08-07 14:36:00 +08:00
2d010326c7 Add a Dockerfile and more configurable environment variables 2020-08-07 14:34:47 +08:00
13 changed files with 246 additions and 57 deletions

5
.dockerignore Normal file
View File

@ -0,0 +1,5 @@
.gitlab-ci.yml
.dockerignore
Dockerfile
README.md
LICENSE

21
Dockerfile Normal file
View File

@ -0,0 +1,21 @@
FROM golang:1.14.2-alpine AS builder
RUN go env -w GO111MODULE=auto \
&& go env -w CGO_ENABLED=0 \
&& mkdir /build
WORKDIR /build
COPY ./ .
RUN cd /build \
&& go build -ldflags "-s -w -extldflags '-static'" -o cqhttp
FROM alpine:latest
COPY --from=builder /build/cqhttp /usr/bin/cqhttp
RUN chmod +x /usr/bin/cqhttp
WORKDIR /data
ENTRYPOINT [ "/usr/bin/cqhttp" ]

View File

@ -439,14 +439,14 @@ func (bot *CQBot) CQGetForwardMessage(resId string) MSG {
}
var r []MSG
for _, n := range m.Nodes {
checkImage(n.Message)
checkMedia(n.Message)
r = append(r, MSG{
"sender": MSG{
"user_id": n.SenderId,
"nickname": n.SenderName,
},
"time": n.Time,
"content": ToStringMessage(n.Message, 0, false),
"content": ToFormattedMessage(n.Message, 0, false),
})
}
return OK(MSG{

View File

@ -23,6 +23,76 @@ var matchReg = regexp.MustCompile(`\[CQ:\w+?.*?]`)
var typeReg = regexp.MustCompile(`\[CQ:(\w+)`)
var paramReg = regexp.MustCompile(`,([\w\-.]+?)=([^,\]]+)`)
func ToArrayMessage(e []message.IMessageElement, code int64, raw ...bool) (r []MSG) {
ur := false
if len(raw) != 0 {
ur = raw[0]
}
for _, elem := range e {
m := MSG{}
switch o := elem.(type) {
case *message.TextElement:
m = MSG{
"type": "text",
"data": map[string]string{"text": o.Content},
}
case *message.AtElement:
if o.Target == 0 {
m = MSG{
"type": "at",
"data": map[string]string{"qq": "all"},
}
} else {
m = MSG{
"type": "at",
"data": map[string]string{"qq": fmt.Sprint(o.Target)},
}
}
case *message.ReplyElement:
m = MSG{
"type": "reply",
"data": map[string]string{"id": fmt.Sprint(ToGlobalId(code, o.ReplySeq))},
}
case *message.ForwardElement:
m = MSG{
"type": "forward",
"data": map[string]string{"id": o.ResId},
}
case *message.FaceElement:
m = MSG{
"type": "face",
"data": map[string]string{"id": fmt.Sprint(o.Index)},
}
case *message.VoiceElement:
if ur {
m = MSG{
"type": "record",
"data": map[string]string{"file": o.Name},
}
} else {
m = MSG{
"type": "record",
"data": map[string]string{"file": o.Name, "url": o.Url},
}
}
case *message.ImageElement:
if ur {
m = MSG{
"type": "image",
"data": map[string]string{"file": o.Filename},
}
} else {
m = MSG{
"type": "image",
"data": map[string]string{"file": o.Filename, "url": o.Url},
}
}
}
r = append(r, m)
}
return
}
func ToStringMessage(e []message.IMessageElement, code int64, raw ...bool) (r string) {
ur := false
if len(raw) != 0 {
@ -45,12 +115,16 @@ func ToStringMessage(e []message.IMessageElement, code int64, raw ...bool) (r st
case *message.FaceElement:
r += fmt.Sprintf(`[CQ:face,id=%d]`, o.Index)
case *message.VoiceElement:
r += fmt.Sprintf(`[CQ:record,file=%s]`, o.Name)
if ur {
r += fmt.Sprintf(`[CQ:record,file=%s]`, o.Name)
} else {
r += fmt.Sprintf(`[CQ:record,file=%s,url=%s]`, o.Name, CQCodeEscapeValue(o.Url))
}
case *message.ImageElement:
if ur {
r += fmt.Sprintf(`[CQ:image,file=%s]`, o.Filename)
} else {
r += fmt.Sprintf(`[CQ:image,file=%s,url=%s]`, o.Filename, o.Url)
r += fmt.Sprintf(`[CQ:image,file=%s,url=%s]`, o.Filename, CQCodeEscapeValue(o.Url))
}
}
}
@ -71,7 +145,7 @@ func (bot *CQBot) ConvertStringMessage(m string, group bool) (r []message.IMessa
ps := paramReg.FindAllStringSubmatch(code, -1)
d := make(map[string]string)
for _, p := range ps {
d[p[1]] = p[2]
d[p[1]] = CQCodeUnescapeValue(p[2])
}
if t == "reply" && group {
if len(r) > 0 {
@ -286,6 +360,13 @@ func (bot *CQBot) ToElement(t string, d map[string]string, group bool) (message.
}
data = b
}
if global.PathExists(path.Join(global.VOICE_PATH, f)) {
b, err := ioutil.ReadFile(path.Join(global.VOICE_PATH, f))
if err != nil {
return nil, err
}
data = b
}
if !global.IsAMR(data) {
return nil, errors.New("unsupported voice file format (please use AMR file for now)")
}
@ -312,9 +393,15 @@ func (bot *CQBot) ToElement(t string, d map[string]string, group bool) (message.
func CQCodeEscapeText(raw string) string {
ret := raw
ret = strings.ReplaceAll(ret, "&", "&")
ret = strings.ReplaceAll(ret, "[", "[")
ret = strings.ReplaceAll(ret, "]", "]")
ret = strings.ReplaceAll(ret, "&", "&")
return ret
}
func CQCodeEscapeValue(value string) string {
ret := CQCodeEscapeText(value)
ret = strings.ReplaceAll(ret, ",", ",")
return ret
}
@ -325,3 +412,9 @@ func CQCodeUnescapeText(content string) string {
ret = strings.ReplaceAll(ret, "&", "&")
return ret
}
func CQCodeUnescapeValue(content string) string {
ret := CQCodeUnescapeText(content)
ret = strings.ReplaceAll(ret, ",", ",")
return ret
}

View File

@ -10,11 +10,27 @@ import (
"io/ioutil"
"path"
"strconv"
"strings"
"time"
)
var format = "string"
func SetMessageFormat(f string) {
format = f
}
func ToFormattedMessage(e []message.IMessageElement, code int64, raw ...bool) (r interface{}) {
if format == "string" {
r = ToStringMessage(e, code, raw...)
} else if format == "array" {
r = ToArrayMessage(e, code, raw...)
}
return
}
func (bot *CQBot) privateMessageEvent(c *client.QQClient, m *message.PrivateMessage) {
checkImage(m.Elements)
checkMedia(m.Elements)
cqm := ToStringMessage(m.Elements, 0, true)
log.Infof("收到好友 %v(%v) 的消息: %v", m.Sender.DisplayName(), m.Sender.Uin, cqm)
fm := MSG{
@ -23,7 +39,7 @@ func (bot *CQBot) privateMessageEvent(c *client.QQClient, m *message.PrivateMess
"sub_type": "friend",
"message_id": ToGlobalId(m.Sender.Uin, m.Id),
"user_id": m.Sender.Uin,
"message": ToStringMessage(m.Elements, 0, false),
"message": ToFormattedMessage(m.Elements, 0, false),
"raw_message": cqm,
"font": 0,
"self_id": c.Uin,
@ -39,7 +55,7 @@ func (bot *CQBot) privateMessageEvent(c *client.QQClient, m *message.PrivateMess
}
func (bot *CQBot) groupMessageEvent(c *client.QQClient, m *message.GroupMessage) {
checkImage(m.Elements)
checkMedia(m.Elements)
for _, elem := range m.Elements {
if file, ok := elem.(*message.GroupFileElement); ok {
log.Infof("群 %v(%v) 内 %v(%v) 上传了文件: %v", m.GroupName, m.GroupCode, m.Sender.DisplayName(), m.Sender.Uin, file.Name)
@ -71,7 +87,7 @@ func (bot *CQBot) groupMessageEvent(c *client.QQClient, m *message.GroupMessage)
"anonymous": nil,
"font": 0,
"group_id": m.GroupCode,
"message": ToStringMessage(m.Elements, m.GroupCode, false),
"message": ToFormattedMessage(m.Elements, m.GroupCode, false),
"message_id": id,
"message_type": "group",
"post_type": "message",
@ -117,7 +133,7 @@ func (bot *CQBot) groupMessageEvent(c *client.QQClient, m *message.GroupMessage)
}
func (bot *CQBot) tempMessageEvent(c *client.QQClient, m *message.TempMessage) {
checkImage(m.Elements)
checkMedia(m.Elements)
cqm := ToStringMessage(m.Elements, 0, true)
bot.tempMsgCache.Store(m.Sender.Uin, m.GroupCode)
log.Infof("收到来自群 %v(%v) 内 %v(%v) 的临时会话消息: %v", m.GroupName, m.GroupCode, m.Sender.DisplayName(), m.Sender.Uin, cqm)
@ -127,7 +143,7 @@ func (bot *CQBot) tempMessageEvent(c *client.QQClient, m *message.TempMessage) {
"sub_type": "group",
"message_id": m.Id,
"user_id": m.Sender.Uin,
"message": ToStringMessage(m.Elements, 0, false),
"message": ToFormattedMessage(m.Elements, 0, false),
"raw_message": cqm,
"font": 0,
"self_id": c.Uin,
@ -300,7 +316,7 @@ func (bot *CQBot) groupJoinReqEvent(c *client.QQClient, e *client.UserJoinGroupR
"sub_type": "add",
"group_id": e.GroupCode,
"user_id": e.RequesterUin,
"comment": "",
"comment": e.Message,
"flag": flag,
"time": time.Now().Unix(),
"self_id": c.Uin,
@ -346,9 +362,10 @@ func (bot *CQBot) groupDecrease(groupCode, userUin int64, operator *client.Group
}
}
func checkImage(e []message.IMessageElement) {
func checkMedia(e []message.IMessageElement) {
for _, elem := range e {
if i, ok := elem.(*message.ImageElement); ok {
switch i := elem.(type) {
case *message.ImageElement:
filename := hex.EncodeToString(i.Md5) + ".image"
if !global.PathExists(path.Join(global.IMAGE_PATH, filename)) {
_ = ioutil.WriteFile(path.Join(global.IMAGE_PATH, filename), binary.NewWriterF(func(w *binary.Writer) {
@ -359,6 +376,17 @@ func checkImage(e []message.IMessageElement) {
}), 0777)
}
i.Filename = filename
case *message.VoiceElement:
i.Name = strings.ReplaceAll(i.Name, "{", "")
i.Name = strings.ReplaceAll(i.Name, "}", "")
if !global.PathExists(path.Join(global.VOICE_PATH, i.Name)) {
b, err := global.GetBytes(i.Url)
if err != nil {
log.Warnf("语音文件 %v 下载失败: %v", i.Name, err)
continue
}
_ = ioutil.WriteFile(path.Join(global.VOICE_PATH, i.Name), b, 0777)
}
}
}
}

View File

@ -28,7 +28,8 @@ go-cqhttp 支持导入CQHTTP的配置文件, 具体步骤为:
"enabled": true,
"host": "0.0.0.0",
"port": 5700,
"post_urls": {"url:port": "secret"}
"post_urls": {"url:port": "secret"},
"post_message_format": "string"
},
"ws_config": {
"enabled": true,

View File

@ -40,10 +40,12 @@ type CQHttpApiConfig struct {
}
type GoCQHttpConfig struct {
Enabled bool `json:"enabled"`
Host string `json:"host"`
Port uint16 `json:"port"`
PostUrls map[string]string `json:"post_urls"`
Enabled bool `json:"enabled"`
Host string `json:"host"`
Port uint16 `json:"port"`
Timeout int32 `json:"timeout"`
PostUrls map[string]string `json:"post_urls"`
PostMessageFormat string `json:"post_message_format"`
}
type GoCQWebsocketConfig struct {
@ -66,10 +68,11 @@ func DefaultConfig() *JsonConfig {
ReLogin: true,
ReLoginDelay: 3,
HttpConfig: &GoCQHttpConfig{
Enabled: true,
Host: "0.0.0.0",
Port: 5700,
PostUrls: map[string]string{},
Enabled: true,
Host: "0.0.0.0",
Port: 5700,
PostUrls: map[string]string{},
PostMessageFormat: "string",
},
WSConfig: &GoCQWebsocketConfig{
Enabled: true,

View File

@ -9,6 +9,8 @@ import (
var IMAGE_PATH = path.Join("data", "images")
var VOICE_PATH = path.Join("data", "voices")
func PathExists(path string) bool {
_, err := os.Stat(path)
return err == nil || os.IsExist(err)

2
go.mod
View File

@ -3,7 +3,7 @@ module github.com/Mrs4s/go-cqhttp
go 1.14
require (
github.com/Mrs4s/MiraiGo v0.0.0-20200809221224-7a84cfae6795
github.com/Mrs4s/MiraiGo v0.0.0-20200812011522-ee1117893fad
github.com/gin-gonic/gin v1.6.3
github.com/gorilla/websocket v1.4.2
github.com/guonaihong/gout v0.1.1

4
go.sum
View File

@ -2,6 +2,10 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Mrs4s/MiraiGo v0.0.0-20200809221224-7a84cfae6795 h1:Bu4k9ZS/IIy9Shwd9lS/C2P/2I8fYUwg1OpRF91hr1w=
github.com/Mrs4s/MiraiGo v0.0.0-20200809221224-7a84cfae6795/go.mod h1:0je03wji/tSw4bUH4QCF2Z4/EjyNWjSJTyy5tliX6EM=
github.com/Mrs4s/MiraiGo v0.0.0-20200810032556-a425f9d1b98e h1:5LYDouOL9ZgTL5PwZuuSlFYSfboRQjnXqRIlhviRcGE=
github.com/Mrs4s/MiraiGo v0.0.0-20200810032556-a425f9d1b98e/go.mod h1:0je03wji/tSw4bUH4QCF2Z4/EjyNWjSJTyy5tliX6EM=
github.com/Mrs4s/MiraiGo v0.0.0-20200812011522-ee1117893fad h1:mOz8SozY2NEjXivlOrTwGPsbukcpLYpi/rv0/ASM/Hg=
github.com/Mrs4s/MiraiGo v0.0.0-20200812011522-ee1117893fad/go.mod h1:0je03wji/tSw4bUH4QCF2Z4/EjyNWjSJTyy5tliX6EM=
github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0=
github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=

34
main.go
View File

@ -36,14 +36,16 @@ func init() {
if err == nil {
log.SetOutput(io.MultiWriter(os.Stderr, w))
}
if !global.PathExists("data") {
if err := os.Mkdir("data", 0777); err != nil {
log.Fatalf("创建数据文件夹失败: %v", err)
}
if err := os.Mkdir(path.Join("data", "images"), 0777); err != nil {
if !global.PathExists(global.IMAGE_PATH) {
if err := os.MkdirAll(global.IMAGE_PATH, os.ModePerm); err != nil {
log.Fatalf("创建图片缓存文件夹失败: %v", err)
}
}
if !global.PathExists(global.VOICE_PATH) {
if err := os.MkdirAll(global.VOICE_PATH, os.ModePerm); err != nil {
log.Fatalf("创建语音缓存文件夹失败: %v", err)
}
}
if global.PathExists("cqhttp.json") {
log.Info("发现 cqhttp.json 将在五秒后尝试导入配置,按 Ctrl+C 取消.")
log.Warn("警告: 该操作会删除 cqhttp.json 并覆盖 config.json 文件.")
@ -89,10 +91,11 @@ func main() {
Uin: uin,
Password: pwd,
HttpConfig: &global.GoCQHttpConfig{
Enabled: true,
Host: "0.0.0.0",
Port: 5700,
PostUrls: map[string]string{},
Enabled: true,
Host: "0.0.0.0",
Port: 5700,
PostUrls: map[string]string{},
PostMessageFormat: "string",
},
WSConfig: &global.GoCQWebsocketConfig{
Enabled: true,
@ -127,7 +130,7 @@ func main() {
if !global.PathExists("device.json") {
log.Warn("虚拟设备信息不存在, 将自动生成随机设备.")
client.GenRandomDevice()
_ = ioutil.WriteFile("device.json", client.SystemDeviceInfo.ToJson(), 0777)
_ = ioutil.WriteFile("device.json", client.SystemDeviceInfo.ToJson(), os.ModePerm)
log.Info("已生成设备信息并保存到 device.json 文件.")
} else {
log.Info("将使用 device.json 内的设备信息运行Bot.")
@ -163,9 +166,10 @@ func main() {
if !rsp.Success {
switch rsp.Error {
case client.NeedCaptcha:
_ = ioutil.WriteFile("captcha.jpg", rsp.CaptchaImage, os.ModePerm)
img, _, _ := image.Decode(bytes.NewReader(rsp.CaptchaImage))
fmt.Println(asciiart.New("image", img).Art)
log.Warn("请输入验证码: (Enter 提交)")
log.Warn("请输入验证码 (captcha.jpg) (Enter 提交)")
text, _ := console.ReadString('\n')
rsp, err = cli.SubmitCaptcha(strings.ReplaceAll(text, "\n", ""), rsp.CaptchaSign)
continue
@ -191,8 +195,14 @@ func main() {
b := coolq.NewQQBot(cli, conf)
if conf.HttpConfig != nil && conf.HttpConfig.Enabled {
server.HttpServer.Run(fmt.Sprintf("%s:%d", conf.HttpConfig.Host, conf.HttpConfig.Port), conf.AccessToken, b)
if conf.HttpConfig.PostMessageFormat != "string" && conf.HttpConfig.PostMessageFormat != "array" {
log.Warnf("http_config.post_message_format 配置错误, 将自动使用 string")
coolq.SetMessageFormat("string")
} else {
coolq.SetMessageFormat(conf.HttpConfig.PostMessageFormat)
}
for k, v := range conf.HttpConfig.PostUrls {
server.NewHttpClient().Run(k, v, b)
server.NewHttpClient().Run(k, v, conf.HttpConfig.Timeout, b)
}
}
if conf.WSConfig != nil && conf.WSConfig.Enabled {

View File

@ -21,9 +21,10 @@ type httpServer struct {
}
type httpClient struct {
bot *coolq.CQBot
secret string
addr string
bot *coolq.CQBot
secret string
addr string
timeout int32
}
var HttpServer = &httpServer{}
@ -163,10 +164,14 @@ func NewHttpClient() *httpClient {
return &httpClient{}
}
func (c *httpClient) Run(addr, secret string, bot *coolq.CQBot) {
func (c *httpClient) Run(addr, secret string, timeout int32, bot *coolq.CQBot) {
c.bot = bot
c.secret = secret
c.addr = addr
c.timeout = timeout
if c.timeout < 5 {
c.timeout = 5
}
bot.OnEventPush(c.onBotPushEvent)
log.Infof("HTTP POST上报器已启动: %v", addr)
}
@ -184,7 +189,7 @@ func (c *httpClient) onBotPushEvent(m coolq.MSG) {
h["X-Signature"] = "sha1=" + hex.EncodeToString(mac.Sum(nil))
}
return h
}()).SetTimeout(time.Second * 5).Do()
}()).SetTimeout(time.Second * time.Duration(c.timeout)).Do()
if err != nil {
log.Warnf("上报Event数据到 %v 失败: %v", c.addr, err)
return
@ -224,6 +229,14 @@ func (s *httpServer) GetGroupMemberInfo(c *gin.Context) {
}
func (s *httpServer) SendMessage(c *gin.Context) {
if getParam(c, "message_type") == "private" {
s.SendPrivateMessage(c)
return
}
if getParam(c, "message_type") == "group" {
s.SendGroupMessage(c)
return
}
if getParam(c, "group_id") != "" {
s.SendGroupMessage(c)
return
@ -235,8 +248,8 @@ func (s *httpServer) SendMessage(c *gin.Context) {
func (s *httpServer) SendPrivateMessage(c *gin.Context) {
uid, _ := strconv.ParseInt(getParam(c, "user_id"), 10, 64)
msg := getParam(c, "message")
if gjson.Valid(msg) {
msg, t := getParamWithType(c, "message")
if t == gjson.JSON {
c.JSON(200, s.bot.CQSendPrivateMessage(uid, gjson.Parse(msg)))
return
}
@ -245,8 +258,8 @@ func (s *httpServer) SendPrivateMessage(c *gin.Context) {
func (s *httpServer) SendGroupMessage(c *gin.Context) {
gid, _ := strconv.ParseInt(getParam(c, "group_id"), 10, 64)
msg := getParam(c, "message")
if gjson.Valid(msg) {
msg, t := getParamWithType(c, "message")
if t == gjson.JSON {
c.JSON(200, s.bot.CQSendGroupMessage(gid, gjson.Parse(msg)))
return
}
@ -372,14 +385,19 @@ func getParamOrDefault(c *gin.Context, k, def string) string {
}
func getParam(c *gin.Context, k string) string {
p, _ := getParamWithType(c, k)
return p
}
func getParamWithType(c *gin.Context, k string) (string, gjson.Type) {
if q := c.Query(k); q != "" {
return q
return q, gjson.Null
}
if c.Request.Method == "POST" {
if h := c.Request.Header.Get("Content-Type"); h != "" {
if h == "application/x-www-form-urlencoded" {
if p, ok := c.GetPostForm(k); ok {
return p
return p, gjson.Null
}
}
if h == "application/json" {
@ -388,20 +406,20 @@ func getParam(c *gin.Context, k string) string {
if res.Exists() {
switch res.Type {
case gjson.JSON:
return res.Raw
return res.Raw, gjson.JSON
case gjson.String:
return res.Str
return res.Str, gjson.String
case gjson.Number:
return strconv.FormatInt(res.Int(), 10) // 似乎没有需要接受 float 类型的api
return strconv.FormatInt(res.Int(), 10), gjson.Number // 似乎没有需要接受 float 类型的api
case gjson.True:
return "true"
return "true", gjson.True
case gjson.False:
return "false"
return "false", gjson.False
}
}
}
}
}
}
return ""
return "", gjson.Null
}

View File

@ -136,7 +136,6 @@ func (c *websocketClient) connectUniversal() {
log.Warnf("连接到反向Websocket Universal服务器 %v 时出现致命错误: %v", c.conf.ReverseUrl, err)
return
}
wsConf.Dialer.Timeout = time.Second * 5
wsConf.Header["X-Client-Role"] = []string{"Universal"}
wsConf.Header["X-Self-ID"] = []string{strconv.FormatInt(c.bot.Client.Uin, 10)}
wsConf.Header["User-Agent"] = []string{"CQHttp/4.15.0"}
@ -173,6 +172,7 @@ func (c *websocketClient) listenApi(conn *wsc.Conn, u bool) {
ret["echo"] = j.Get("echo").Value()
}
c.pushLock.Lock()
log.Debugf("准备发送API %v 处理结果: %v", t, ret.ToJson())
_, _ = conn.Write([]byte(ret.ToJson()))
c.pushLock.Unlock()
}
@ -192,7 +192,6 @@ func (c *websocketClient) onBotPushEvent(m coolq.MSG) {
defer c.pushLock.Unlock()
if c.eventConn != nil {
log.Debugf("向WS服务器 %v 推送Event: %v", c.eventConn.RemoteAddr().String(), m.ToJson())
_ = c.eventConn.SetWriteDeadline(time.Now().Add(time.Second * 3))
if _, err := c.eventConn.Write([]byte(m.ToJson())); err != nil {
_ = c.eventConn.Close()
if c.conf.ReverseReconnectInterval != 0 {
@ -205,7 +204,6 @@ func (c *websocketClient) onBotPushEvent(m coolq.MSG) {
}
if c.universalConn != nil {
log.Debugf("向WS服务器 %v 推送Event: %v", c.universalConn.RemoteAddr().String(), m.ToJson())
_ = c.universalConn.SetWriteDeadline(time.Now().Add(time.Second * 3))
_, _ = c.universalConn.Write([]byte(m.ToJson()))
}
}
@ -333,6 +331,12 @@ var wsApi = map[string]func(*coolq.CQBot, gjson.Result) coolq.MSG{
)
},
"send_msg": func(bot *coolq.CQBot, p gjson.Result) coolq.MSG {
if p.Get("message_type").Str == "private" {
return bot.CQSendPrivateMessage(p.Get("user_id").Int(), p.Get("message"))
}
if p.Get("message_type").Str == "group" {
return bot.CQSendGroupMessage(p.Get("group_id").Int(), p.Get("message"))
}
if p.Get("group_id").Int() != 0 {
return bot.CQSendGroupMessage(p.Get("group_id").Int(), p.Get("message"))
}