package ws import ( "bytes" "context" "crypto/tls" "encoding/json" "errors" "fmt" "git.hlsq.asia/mmorpg/service-common/log" "git.hlsq.asia/mmorpg/service-common/proto/sc/sc_pb" "git.hlsq.asia/mmorpg/service-common/utils" "github.com/gorilla/websocket" "google.golang.org/protobuf/proto" "io" "net/http" ) type Client struct { httpAddr string websocketAddr string conn *websocket.Conn ctx context.Context cancel context.CancelFunc writeChan chan []byte USN string } func NewClient(httpAddr, websocketAddr string) *Client { c := &Client{ httpAddr: httpAddr, websocketAddr: websocketAddr, writeChan: make(chan []byte, 1024), } c.ctx, c.cancel = context.WithCancel(context.Background()) return c } func (c *Client) Start() { go func() { data := fmt.Sprintf(`{"phone": "%v", "code": "1234"}`, utils.SnowflakeInstance().Generate().String()) resp, err := http.Post(c.httpAddr+"/gw/login", "application/json", bytes.NewBufferString(data)) if err != nil { log.Errorf("POST request failed: %v\n", err) return } defer resp.Body.Close() all, err := io.ReadAll(resp.Body) if err != nil { log.Errorf("Read response body failed: %v\n", err) return } type RespJsonData struct { Code int `json:"code"` Msg string `json:"msg"` Data struct { USN string `json:"usn"` Name string `json:"name"` AccessToken string `json:"accessToken"` RefreshToken string `json:"refreshToken"` } `json:"data,omitempty"` } r := &RespJsonData{} if err = json.Unmarshal(all, r); err != nil { log.Errorf("json.Unmarshal error: %v, %v", err, string(all)) return } c.USN = r.Data.USN dialer := websocket.DefaultDialer dialer.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} conn, _, err := dialer.Dial(fmt.Sprintf("%v?token=%v", c.websocketAddr, r.Data.AccessToken), nil) if err != nil { log.Errorf("connect error %v", err.Error()) return } c.conn = conn go c.startReader() go c.startWriter() select { case <-c.ctx.Done(): c.onStop() return } }() } func (c *Client) startReader() { for { select { case <-c.ctx.Done(): return default: _, msgByte, err := c.conn.ReadMessage() if err != nil { log.Errorf("read error quit %s", err) c.Stop() return } msg := &sc_pb.Message{} if err = proto.Unmarshal(msgByte, msg); err != nil { continue } if r, ok := router[msg.ID]; ok { r.Handle(msg.Payload, c) } else { log.Errorf("no router for %v", msg.ID) } } } } func (c *Client) startWriter() { for { select { case data, ok := <-c.writeChan: if ok { if err := c.conn.WriteMessage(websocket.BinaryMessage, data); err != nil { log.Errorf("Send Buff Data error:, %s Conn Writer exit", err) return } } else { log.Errorf("msgBuffChan is Closed") } case <-c.ctx.Done(): return } } } // WriteMessage 发送消息给服务器 func (c *Client) WriteMessage(msgID sc_pb.MessageID, data proto.Message) error { d, err := proto.Marshal(data) if err != nil { return err } p := &sc_pb.Message{ ID: msgID, Payload: d, } marshal, _ := proto.Marshal(p) select { case c.writeChan <- marshal: default: return errors.New("send buff chan is full") } return nil } func (c *Client) Stop() { c.cancel() } func (c *Client) onStop() { if err := c.conn.Close(); err != nil { log.Errorf("close client error %v", err) } }