package wsclient import ( "encoding/json" "fmt" "log" "net/url" "runtime/debug" "sync" "time" "git.lxtend.com/qqbot/action" "git.lxtend.com/qqbot/constants" "git.lxtend.com/qqbot/handler" "git.lxtend.com/qqbot/model" "github.com/gorilla/websocket" ) type WebSocketClient struct { conn *websocket.Conn closed bool Done chan struct{} lock sync.Mutex } func NewWebSocketClient(scheme, host, path string) (*WebSocketClient, error) { u := url.URL{Scheme: scheme, Host: host, Path: path} log.Printf("Connecting to %s", u.String()) conn, _, err := websocket.DefaultDialer.Dial(u.String(), nil) if err != nil { return nil, err } client := &WebSocketClient{ conn: conn, closed: false, Done: make(chan struct{}), } defer func() { if r := recover(); r != nil { stack := debug.Stack() errMsg := fmt.Sprintf("[%s] Panic recovered:\nError: %v\nStack Trace:\n%s\n", time.Now().Format("2006-01-02 15:04:05"), r, stack) // 写入日志文件 log.Print(errMsg) go client.receiveMessages() } }() action.ActionManager.SetConn(conn) go client.receiveMessages() return client, nil } func (c *WebSocketClient) receiveMessages() { defer close(c.Done) for !c.closed { _, message, err := c.conn.ReadMessage() if err != nil { log.Println("Error reading message:", err) return } var event model.EventMessage if err = json.Unmarshal(message, &event); err != nil { log.Println("Error unmarshalling message:", err) return } msg := model.Message{ UserId: event.UserID, OriginMsgId: event.MessageID, RawMsg: event.RawMessage, UserNickName: event.Sender.Nickname, } if event.MessageType == constants.GROUP_MSG { msg.GroupInfo = model.GroupInfo{ IsGroupMsg: true, GroupId: event.GroupID, UserCard: event.Sender.Card, } } else { msg.GroupInfo = model.GroupInfo{ IsGroupMsg: false, GroupId: event.Sender.GroupID, } } go func() { reply := handler.MsgInHandler(msg) if reply != nil { action.ActionManager.SendMsg(reply) } }() } } func (c *WebSocketClient) SendMessage(messageType int, message []byte) error { c.lock.Lock() defer c.lock.Unlock() return c.conn.WriteMessage(messageType, message) } func (c *WebSocketClient) Close() error { c.closed = true err := c.conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")) if err != nil { return err } <-c.Done return c.conn.Close() }