コード例 #1
0
ファイル: pubsub_tcp.go プロジェクト: ming-hai/appmsgsrv
// 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
}
コード例 #2
0
// 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
}