// SubscribeTCPHandle handle the subscribers's connection. func SubscribeTCPHandle(conn net.Conn, args []string) { argLen := len(args) addr := conn.RemoteAddr().String() if argLen < 2 { conn.Write(ParamReply) logger.Errorf("<%s> subscriber missing argument", addr) return } // key, heartbeat key := args[0] if key == "" { conn.Write(ParamReply) logger.Warnf("<%s> key param error", addr) return } heartbeatStr := args[1] i, err := strconv.Atoi(heartbeatStr) if err != nil { conn.Write(ParamReply) logger.Errorf("<%s> user_key:\"%s\" heartbeat:\"%s\" argument error (%s)", addr, key, heartbeatStr, err) return } if i < minHearbeatSec { conn.Write(ParamReply) logger.Warnf("<%s> user_key:\"%s\" heartbeat argument error, less than %d", addr, key, minHearbeatSec) return } heartbeat := i + delayHeartbeatSec token := "" if argLen > 2 { token = args[2] } version := "" if argLen > 3 { version = args[3] } logger.Tracef("<%s> subscribe to key = %s, heartbeat = %d, token = %s, version = %s", addr, key, heartbeat, token, version) // fetch subscriber from the channel c, err := UserChannel.Get(key, true) if err != nil { logger.Warnf("<%s> user_key:\"%s\" can't get a channel (%s)", addr, key, err) conn.Write(ChannelReply) return } // auth token if ok := c.AuthToken(key, token); !ok { conn.Write(AuthReply) logger.Errorf("<%s> user_key:\"%s\" auth token \"%s\" failed", addr, key, token) return } // add a conn to the channel connElem, err := c.AddConn(key, &Connection{Conn: conn, Proto: TCPProto, Version: version}) if err != nil { logger.Errorf("<%s> user_key:\"%s\" add conn error(%v)", addr, key, err) return } //链接添加成功 {userI_id}_{device_type}-{real_device_id}@{xx} var sessionId string = "" strs := strings.Split(key, "@") isAPP := strings.HasSuffix(key, "@app") if len(strs) > 0 && !isAPP { sessionId = strs[0] tmps := strings.Split(strs[0], "_") if len(tmps) > 1 { userId := tmps[0] //此user不一定时userid 若用户为登录则时应用制定的任意数 sessionType := "" types := strings.Split(tmps[1], "-") if len(types) > 0 { sessionType = types[0] } sessionObj := &session.Session{ Id: sessionId, Type: sessionType, UserId: userId, State: session.SESSION_STATE_INIT, Created: time.Now().Local(), Updated: time.Now().Local(), } session.CreatSession(sessionObj) } } //开始定时更新会话更新时间 var tickerFlagStop = make(chan bool, 1) if !isAPP { go session.TickerTaskUpdateSession(sessionId, tickerFlagStop) } // blocking wait client heartbeat reply := []byte{0} // reply := make([]byte, HeartbeatLen) begin := time.Now().UnixNano() end := begin + Second for { // more then 1 sec, reset the timer if end-begin >= Second { if err = conn.SetReadDeadline(time.Now().Add(time.Second * time.Duration(heartbeat))); err != nil { logger.Errorf("<%s> user_key:\"%s\" conn.SetReadDeadLine() error(%v)", addr, key, err) break } begin = end } if _, err = conn.Read(reply); err != nil { if err != io.EOF { logger.Debugf("<%s> user_key:\"%s\" conn.Read() failed, read heartbeat timedout error(%v)", addr, key, err) } else { // client connection close logger.Debugf("<%s> user_key:\"%s\" client connection close error(%s)", addr, key, err) } break } if string(reply) == Heartbeat { if _, err = conn.Write(HeartbeatReply); err != nil { logger.Errorf("<%s> user_key:\"%s\" conn.Write() failed, write heartbeat to client error(%v)", addr, key, err) break } logger.Tracef("<%s> user_key:\"%s\" receive heartbeat (%s)", addr, key, reply) } else { logger.Debugf("<%s> user_key:\"%s\" unknown heartbeat protocol (%s)", addr, key, reply) break } end = time.Now().UnixNano() } // remove exists conn if err := c.RemoveConn(key, connElem); err != nil { logger.Errorf("<%s> user_key:\"%s\" remove conn error(%s)", addr, key, err) } if !isAPP { //结束定时更新会话定时任务 tickerFlagStop <- true //将会话更新为超时会话 hours, _ := time.ParseDuration("-25h") pastTime := time.Now().Local() pastTime = pastTime.Add(hours) session.UpdateSessionUpdated(sessionId, pastTime) //移除会话sessione //session.RemoveSessionById(sessionId) } return }
// Subscriber Handle is the websocket handle for sub request. func SubscribeHandle(ws *websocket.Conn) { addr := ws.Request().RemoteAddr params := ws.Request().URL.Query() // get subscriber key key := params.Get("key") if key == "" { ws.Write(ParamReply) logger.Warnf("<%s> key param error", addr) return } // get heartbeat second heartbeatStr := params.Get("heartbeat") i, err := strconv.Atoi(heartbeatStr) if err != nil { ws.Write(ParamReply) logger.Errorf("<%s> user_key:\"%s\" heartbeat argument error(%s)", addr, key, err) return } if i < minHearbeatSec { ws.Write(ParamReply) logger.Warnf("<%s> user_key:\"%s\" heartbeat argument error, less than %d", addr, key, minHearbeatSec) return } heartbeat := i + delayHeartbeatSec token := params.Get("token") version := params.Get("ver") logger.Tracef("<%s> subscribe to key = %s, heartbeat = %d, token = %s, version = %s", addr, key, heartbeat, token, version) // fetch subscriber from the channel c, err := UserChannel.Get(key, true) if err != nil { ws.Write(ChannelReply) logger.Errorf("<%s> user_key:\"%s\" can't get a channel error(%s)", addr, key, err) return } // auth token if ok := c.AuthToken(key, token); !ok { ws.Write(AuthReply) logger.Errorf("<%s> user_key:\"%s\" auth token \"%s\" failed", addr, key, token) return } // add a conn to the channel connElem, err := c.AddConn(key, &Connection{Conn: ws, Proto: WebsocketProto, Version: version}) if err != nil { logger.Errorf("<%s> user_key:\"%s\" add conn error(%s)", addr, key, err) return } //分割出userid sessionid type {userId}_{browser}-{version}-{rn}@{xx} //添加会话记录sessionID var sessionId string = "" strs := strings.Split(key, "@") isAPP := strings.HasSuffix(key, "@app") if len(strs) > 0 && !isAPP { sessionId = strs[0] tmps := strings.Split(strs[0], "_") if len(tmps) > 1 { userId := tmps[0] //此user不一定时userid 若用户为登录则时应用制定的任意数 sessionType := "" types := strings.Split(tmps[1], "-") if len(types) > 0 { sessionType = types[0] } sessionObj := &session.Session{ Id: sessionId, Type: sessionType, UserId: userId, State: session.SESSION_STATE_INIT, Created: time.Now().Local(), Updated: time.Now().Local(), } session.CreatSession(sessionObj) } } //开始定时更新会话更新时间 var tickerFlagStop = make(chan bool, 1) if !isAPP { go session.TickerTaskUpdateSession(sessionId, tickerFlagStop) } // blocking wait client heartbeat reply := "" begin := time.Now().UnixNano() end := begin + Second for { // more then 1 sec, reset the timer if end-begin >= Second { if err = ws.SetReadDeadline(time.Now().Add(time.Second * time.Duration(heartbeat))); err != nil { logger.Errorf("<%s> user_key:\"%s\" websocket.SetReadDeadline() error(%s)", addr, key, err) break } begin = end } if err = websocket.Message.Receive(ws, &reply); err != nil { logger.Errorf("<%s> user_key:\"%s\" websocket.Message.Receive() error(%s)", addr, key, err) break } if reply == Heartbeat { if _, err = ws.Write(HeartbeatReply); err != nil { logger.Errorf("<%s> user_key:\"%s\" write heartbeat to client error(%s)", addr, key, err) break } logger.Tracef("<%s> user_key:\"%s\" receive heartbeat", addr, key) } else { logger.Warnf("<%s> user_key:\"%s\" unknown heartbeat protocol", addr, key) break } end = time.Now().UnixNano() } // remove exists conn if err := c.RemoveConn(key, connElem); err != nil { logger.Errorf("<%s> user_key:\"%s\" remove conn error(%s)", addr, key, err) } if !isAPP { //结束定时更新会话定时任务 tickerFlagStop <- true //移除会话session session.RemoveSessionById(sessionId) } return }