go websocket

import (
	"encoding/json"
	"fmt"
	"github.com/gorilla/websocket"
	"shopeecallback/service"
)

type User struct {
	Conn *websocket.Conn
	UserId int64
	Msg chan []byte
}

type Message struct {
	UserId    int64 `json:"user_id, omitempty"`
	ShopId    int64 `json:"shop_id, omitempty"`
	Content   string `json:"content, omitempty"`
}

type ClientHandle struct {
	UserList   map[*User]bool
	Register   chan *User
	Unregister chan *User
}



//初始化处理中心,以便调用
var WsClient = &ClientHandle{
	UserList:    make(map[*User]bool),
	Register:    make(chan *User),
	Unregister:  make(chan *User),
}


func (hand *ClientHandle)Run() {
	for {
		select {
		case user := <-hand.Register:
			hand.UserList[user] = true
			list, err2 := service.Message.GetMessages(user.UserId)
			if err2 == nil {
				for _, msg := range list {
					jsonMessage, _ := json.Marshal(&Message{ShopId: msg.ShopId, UserId: user.UserId, Content: msg.Msg})
					//发送消息
					user.Msg <- jsonMessage
				}
			}
		case user := <-hand.Unregister:
			//从注销列表中取数据,判断用户列表中是否存在这个用户,存在就删掉
			if _, ok := hand.UserList[user]; ok {
				delete(hand.UserList, user)
			}
		}
	}
}


func ReadMsg(user *User) {
	for {
		_, msg, err := user.Conn.ReadMessage()
		if err != nil {
			fmt.Println("用户退出:",user.Conn.RemoteAddr().String())
			WsClient.Unregister<-user
			user.Conn.Close()
			break
		}
		if string(msg) == "ping" {
			jsonMessage, _ := json.Marshal(&Message{ShopId: 0, UserId: user.UserId, Content: "pong"})
			user.Msg <- jsonMessage
		}
	}
}


func WriteMsg(user *User) {
	for {
		select {
		//从send里读消息
		case message, ok := <-user.Msg:
			if ok {
				// 发送完后就修改读取状态,正常情况下,应该是用户读了才修改状态
				var res Message
				err := json.Unmarshal(message, &res)
				if err == nil {
					go func() {
						service.Message.UpdateMessageStateByShopAndUser(res.UserId, res.ShopId)
					}()
				}
				//发送给web端
				user.Conn.WriteMessage(websocket.TextMessage, message)
			}

		}
	}
}

启动socket

global.Socket = websocket.Upgrader{
		//
		ReadBufferSize: 1023,
		//
		WriteBufferSize: 1023,
		//允许跨域
		CheckOrigin: func(r *http.Request) bool {
			/*if r.Method != "GET" {
				return false
			}
			if r.URL.Path != "/callback" {
				return false
			}*/
			return true
		},
	}

	go wsocket.WsClient.Run()

用户登录

func (it *MessageApi) Callback(c *gin.Context) {
	/*ws, err := global.Socket.Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		return
	}
	defer ws.Close()

	for {

		mt, message, err := ws.ReadMessage()
		if err != nil {
			ws.WriteMessage(mt, []byte("socket连接错误"))
		}
		var req request.RequestPushMessage
		err = json.Unmarshal(message, &req)
		if err != nil {
			ws.WriteMessage(mt, []byte("参数错误"))
		}
		if list, err2 := service.Message.GetMessages(req.UserId); err2 == nil {
			for _, msg := range list {
				ws.WriteJSON(msg)
			}
			// 更新状态
			service.Message.UpdateMessagesState(req.UserId)
		} else {
			ws.WriteMessage(mt, []byte("无数据"))
		}

	}*/
	//wsocket.SocketHandle(c.Writer, c.Request, 1)

	conn, err := (&websocket.Upgrader{CheckOrigin: func(r *http.Request) bool { return true }}).Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		return
	}

	var req request.RequestPushMessage
	err = c.ShouldBindQuery(&req)
	if err != nil {
		return
	}
	userId := req.UserId
	user := &wsocket.User{UserId: userId, Conn: conn, Msg: make(chan []byte)}
	//注册一个新的链接
	wsocket.WsClient.Register <- user

	go wsocket.ReadMsg(user)
	//启动协程把消息返回给web端
	go wsocket.WriteMsg(user)

}

 

店铺发送消息

func (it *ShopeeApi) Callback(c *gin.Context) {
	uuid := uuid.New().String()
	jsonReq := make(map[string]interface{}) //注意该结构接受的内容
	//err := c.BindJSON(&json)
	var req request.RequestShopeeMessage
	//err := c.ShouldBindJSON(&req)
	err := c.ShouldBindBodyWith(&jsonReq, binding.JSON)
	err = c.ShouldBindBodyWith(&req, binding.JSON)


	if err != nil {
		global.FailWithMessage(uuid, "参数错误" + err.Error(), c)
		return
	}
	var errMsg = "店铺未定义"
	if req.ShopId > 0 {
		// 根据shop_id 获取user_id
		err, userIds := service.Buyer.GetBuyersByShop(req.ShopId)
		// 有数据则插入到message表
		fmt.Println(userIds)
		if err == nil {
			jsonStr , _ := json.Marshal(jsonReq)
			jsonStrng := string(jsonStr)

			go func() {
				for _, uid := range userIds {
					//写入数据库
					_, err = service.Message.CreateMessage(req.ShopId, uid, jsonStrng, uuid)
					if err == nil {
						// 发送消息
						for uclient, hasClient := range wsocket.WsClient.UserList {
							if hasClient && uclient.UserId == uid {
								jsonMessage, _ := json.Marshal(&wsocket.Message{ShopId: req.ShopId, UserId: uclient.UserId, Content: jsonStrng})
								uclient.Msg <- jsonMessage
								go wsocket.WriteMsg(uclient)
							}
						}
					}
				}
			}()
			errMsg = "记录消息完成"
		} else {
			errMsg = "店铺没有用户"
		}
	}

	global.FailWithMessage(uuid, errMsg, c)
	return
}

 

 

js websocket

$(document).ready(function() {
       
    
        var wsurl = "ws://127.0.0.1:8080/api/v1/callback?user_id=1";
        var websocket; //用于存放客户端创建的Socket对象
        var timer;
        var lockReconnect = false;
        createSocket();

        function createSocket() {
          try {
            websocket = new WebSocket(wsurl);
            initSocket();
          } catch(e) {
            alert("不支持websocket")
          }
        }

        function initSocket() {
          websocket.onopen = function() {
            heartCheck.start();
            $('#showMessage').append("<p>conneted success!</p>");
          }

          websocket.onmessage = function() {
            heartCheck.start();
            var msg = JSON.parse(event.data);
      
            var shopId = msg.shop_id;
            var content = msg.content;
            var state = msg.state;
            $('#showMessage').append("<p>" + shopId + ":" + content + "</p>");
          }

          websocket.onerror = function() {
            reconnect(wsurl)
          }

          websocket.onclose = function() {
            reconnect(wsurl)
          }
        }

        function reconnect(url) {
            if(lockReconnect) return;
            lockReconnect = true;
            setTimeout(function () {     //没连接上会一直重连,设置延迟避免请求过多
              createSocket(url);
              lockReconnect = false;
            }, 2000);
        }

        var heartCheck = {
            timeout: 540000,        //9分钟发一次心跳
            timeoutObj: null,
            serverTimeoutObj: null,
            reset: function(){
                clearTimeout(this.timeoutObj);
                clearTimeout(this.serverTimeoutObj);
                return this;
            },
            start: function(){
                var self = this;
                this.timeoutObj = setTimeout(function(){
                    //这里发送一个心跳,后端收到后,返回一个心跳消息,
                    //onmessage拿到返回的心跳就说明连接正常
                    ws.send("ping");
                    console.log("ping!")
                    self.serverTimeoutObj = setTimeout(function(){//如果超过一定时间还没重置,说明后端主动断开了
                        ws.close();     //如果onclose会执行reconnect,我们执行ws.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次
                    }, self.timeout)
                }, this.timeout)
            }
        }
      })

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值