162 lines
3.4 KiB
Go
162 lines
3.4 KiB
Go
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/ss/ss_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 int64
|
|
}
|
|
|
|
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/open/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 int64 `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 := &ss_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 ss_pb.MessageID, data proto.Message) error {
|
|
d, err := proto.Marshal(data)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
p := &ss_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)
|
|
}
|
|
}
|