Пример #1
0
// wsHandler is a WebSocket server that handles requests from the WebSocket client in the form of:
// 1. { 'cmd': 'register', 'roomid': $ROOM, 'clientid': $CLIENT' },
// which binds the WebSocket client to a client ID and room ID.
// A client should send this message only once right after the connection is open.
// or
// 2. { 'cmd': 'send', 'msg': $MSG }, which sends the message to the other client of the room.
// It should be sent to the server only after 'regiser' has been sent.
// The message may be cached by the server if the other client has not joined.
//
// Unexpected messages will cause the WebSocket connection to be closed.
func (c *Collider) wsHandler(ws *websocket.Conn) {
	var rid, cid string

	registered := false

	var msg wsClientMsg
loop:
	for {
		err := ws.SetReadDeadline(time.Now().Add(time.Duration(wsReadTimeoutSec) * time.Second))
		if err != nil {
			c.wsError("ws.SetReadDeadline error: "+err.Error(), ws)
			break
		}

		err = websocket.JSON.Receive(ws, &msg)
		if err != nil {
			if err.Error() != "EOF" {
				c.wsError("websocket.JSON.Receive error: "+err.Error(), ws)
			}
			break
		}

		switch msg.Cmd {
		case "register":
			if registered {
				c.wsError("Duplicated register request", ws)
				break loop
			}
			if msg.RoomID == "" || msg.ClientID == "" {
				c.wsError("Invalid register request: missing 'clientid' or 'roomid'", ws)
				break loop
			}
			if err = c.roomTable.register(msg.RoomID, msg.ClientID, ws); err != nil {
				c.wsError(err.Error(), ws)
				break loop
			}
			registered, rid, cid = true, msg.RoomID, msg.ClientID
			c.dash.incrWs()

			defer c.roomTable.deregister(rid, cid)
			break
		case "send":
			if !registered {
				c.wsError("Client not registered", ws)
				break loop
			}
			if msg.Msg == "" {
				c.wsError("Invalid send request: missing 'msg'", ws)
				break loop
			}
			c.roomTable.send(rid, cid, msg.Msg)
			break
		default:
			c.wsError("Invalid message: unexpected 'cmd'", ws)
			break
		}
	}
	// This should be unnecessary but just be safe.
	ws.Close()
}
Пример #2
0
func handleViewer(conn *websocket.Conn) {
	conn.SetReadDeadline(time.Now().Add(10 * time.Second))
	var viewId string
	if err := websocket.Message.Receive(conn, &viewId); err != nil {
		return
	}

	slideId := index.getSlideId(viewId)
	if slideId == "" {
		return
	}

	listener := &slideListener{ch: make(chan int)}
	registry.addListener(slideId, listener)

	for {
		slide := listener.get(1 * time.Minute)
		if slide != 0 {
			conn.SetDeadline(time.Now().Add(10 * time.Second))
			if err := websocket.Message.Send(conn, fmt.Sprintf("%d", slide)); err != nil {
				registry.removeListener(slideId, listener)
				return
			}

			continue
		}

		if err := ping(conn); err != nil {
			registry.removeListener(slideId, listener)
			return
		}
	}
}
Пример #3
0
// 从WebSocket客户端接收信号
func WaitSignal(ws *websocket.Conn, notify_stop_chan chan<- bool, timer **time.Timer,
	pause *bool, resume_chan chan bool, elapsed *int64, mutex *sync.Mutex) {

	var start_time int64
	var end_time int64

	for {
		// 设置Read Deadline为24小时
		ws.SetReadDeadline(time.Now().Add(86400 * time.Second))

		buf := make([]byte, 8)
		_, err := ws.Read(buf)

		if err != nil {
			log.Println("Playback Server: Read data from client failed: ", err)
			mutex.Lock()
			if (*timer) != nil {
				(*timer).Reset(time.Duration(time.Nanosecond))
			}
			mutex.Unlock()
			notify_stop_chan <- true
			goto end
		}

		data, _ := strconv.Atoi(string(recorder.GetValidByte(buf)))
		if data == 800 { // 关闭
			// 如果执行了暂停,首先取消暂停
			if *pause == true {
				resume_chan <- true
			}
			// 取消定时器,发送结束信号
			mutex.Lock()
			if (*timer) != nil {
				(*timer).Reset(time.Duration(time.Nanosecond))
			}
			mutex.Unlock()
			notify_stop_chan <- true
			goto end
		} else if data == 801 { // 暂停
			if *pause == false {
				// 设置暂停标志,记录暂停开始时间
				*pause = true
				start_time = getNowMillisecond()
			}
		} else if data == 802 { // 恢复
			if *pause == true {
				// 记录暂停结束时间,向恢复的channel发送信号
				end_time = getNowMillisecond()
				*elapsed += (end_time - start_time)
				*pause = false
				resume_chan <- true
			}
		}
	}

end:
	ws.Close()
}
Пример #4
0
func (server *Server) newConn(socket *ws.Conn) {
	readyChan := make(chan bool, 1)
	stopChan := make(chan bool, 1)

	if err := socket.SetReadDeadline(time.Now().Add(30 * time.Second)); err != nil {
		if err := socket.Close(); err != nil {
			// ...
		}
	}

	server.waitGroup.Add(1)
	defer server.waitGroup.Done()

	conn := &Conn{
		Socket:      socket,
		Server:      server,
		messageChan: make(chan *Message, 50),
		readyChan:   readyChan,
		stopChan:    stopChan,
	}

	doneChan := make(chan bool)
	go func() {
		defer close(doneChan)
		state := ConnState(readHelo).Timeout(10 * time.Second)
		for state != nil {
			next, err := state(conn)
			if err != nil {
				_ = conn.Close()
				return
			}
			state = next
		}
	}()

	for ok := true; ok; {
		select {
		case <-readyChan:
			server.addConn(conn)
		case <-conn.stopChan:
			server.removeConn(conn)
			if err := conn.Close(); err != nil {
				return
			}
			ok = false
		case <-conn.messageChan:
			// TODO: Forward messages to the IR.
			continue
		case _, ok = <-doneChan:
		}
	}
}
Пример #5
0
func handlePresenter(conn *websocket.Conn) {
	conn.SetReadDeadline(time.Now().Add(10 * time.Second))
	var slideIdParam string
	if err := websocket.Message.Receive(conn, &slideIdParam); err != nil {
		return
	}

	slideId, _ := index.getIdPair(slideIdParam)
	if slideId == "" {
		return
	}

	for {
		var slide string

		conn.SetDeadline(time.Now().Add(15 * time.Minute))
		if err := websocket.Message.Receive(conn, &slide); err != nil {
			return
		}

		curSlide, _ := strconv.Atoi(slide)
		registry.setSlide(slideId, curSlide)
	}
}
Пример #6
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)
		Log.Warn("<%s> key param error", addr)
		return
	}
	// get heartbeat second
	heartbeatStr := params.Get("heartbeat")
	i, err := strconv.Atoi(heartbeatStr)
	if err != nil {
		ws.Write(ParamReply)
		Log.Error("<%s> user_key:\"%s\" heartbeat argument error(%s)", addr, key, err)
		return
	}
	if i < minHearbeatSec {
		ws.Write(ParamReply)
		Log.Warn("<%s> user_key:\"%s\" heartbeat argument error, less than %d", addr, key, minHearbeatSec)
		return
	}
	heartbeat := i + delayHeartbeatSec
	token := params.Get("token")
	Log.Info("<%s> subscribe to key = %s, heartbeat = %d, token = %s", addr, key, heartbeat, token)
	// fetch subscriber from the channel
	c, err := UserChannel.Get(key, true)
	if err != nil {
		ws.Write(ChannelReply)
		Log.Error("<%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)
		Log.Error("<%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})
	if err != nil {
		Log.Error("<%s> user_key:\"%s\" add conn error(%s)", addr, key, err)
		return
	}
	// 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 {
				Log.Error("<%s> user_key:\"%s\" websocket.SetReadDeadline() error(%s)", addr, key, err)
				break
			}
			begin = end
		}
		if err = websocket.Message.Receive(ws, &reply); err != nil {
			Log.Error("<%s> user_key:\"%s\" websocket.Message.Receive() error(%s)", addr, key, err)
			break
		}
		if reply == Heartbeat {
			if _, err = ws.Write(HeartbeatReply); err != nil {
				Log.Error("<%s> user_key:\"%s\" write heartbeat to client error(%s)", addr, key, err)
				break
			}
			Log.Debug("<%s> user_key:\"%s\" receive heartbeat", addr, key)
		} else {
			Log.Warn("<%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 {
		Log.Error("<%s> user_key:\"%s\" remove conn error(%s)", addr, key, err)
	}
	return
}
Пример #7
0
func Subscribe(ws *websocket.Conn) {
	var (
		result = map[string]interface{}{}
		key    string
	)

	defer recoverFunc()
	// cleanup on server side
	//defer func() {
	//	if err := ws.Close(); err != nil {
	//		Log.Printf("wc.Close() failed (%s)", err.Error())
	//	}
	//}()
	// set read deadline
	err := ws.SetReadDeadline(time.Now().Add(time.Duration(Conf.LongpollingTimeout) * time.Second))
	if err != nil {
		Log.Printf("ws.SetReadDeadline() failed (%s)", err.Error())
		return
	}
	// get key
	if err = websocket.Message.Receive(ws, &key); err != nil {
		Log.Printf("websocket.Message.Receive failed (%s)", err.Error())
		return
	}
	// Auth
	if !pusher.Auth(key) {
		if err = responseWriter(ws, AuthErr, result); err != nil {
			Log.Printf("responseWriter failed (%s)", err.Error())
		}

		return
	}
	// Generate Key
	key = pusher.Key(key)
	Log.Printf("Client (%s) subscribe to key %s", ws.Request().RemoteAddr, key)
	// check multi cli connected
	if Conf.MaxSubscriberPerKey > 0 {
		ok, err := multiCliCheck(key)
		if err != nil {
			if err = responseWriter(ws, InternalErr, result); err != nil {
				Log.Printf("responseWriter failed (%s)", err.Error())
			}

			return
		}

		defer func() {
			if err = RedisDecr(ConnectedKey, key); err != nil {
				Log.Printf("RedisDecr(\"%s\", \"%s\") failed (%s)", ConnectedKey, key, err.Error())
			}
		}()

		if !ok {
			if err = responseWriter(ws, MultiCliErr, result); err != nil {
				Log.Printf("responseWriter failed (%s)", err.Error())
			}

			return
		}
	}
	// redis routine for receive pub message or error
	redisC, psc, err := RedisSub(key)
	if err != nil {
		Log.Printf("RedisSub(\"%s\") failed (%s)", key, err.Error())
		if err = responseWriter(ws, InternalErr, result); err != nil {
			Log.Printf("responseWriter failed (%s)", err.Error())
		}

		return
	}
	// unsub redis
	defer func() {
		if err := RedisUnSub(key, psc); err != nil {
			Log.Printf("RedisUnSub(\"%s\", psc) failed (%s)", key, err.Error())
		}
	}()
	// create a routine wait for client read(only closed or error) return a channel
	netC := netRead(ws)
	for {
		select {
		case err := <-netC:
			Log.Printf("websocket.Message.Receive faild (%s)", err.Error())
			return
		case msg := <-redisC:
			if rmsg, ok := msg.(string); ok {
				result["data"] = rmsg
				if err = responseWriter(ws, OK, result); err != nil {
					Log.Printf("responseWriter failed (%s)", err.Error())
					// Restore the unsent message
					if err = RedisRestore(key, rmsg); err != nil {
						Log.Printf("RedisRestore(\"%s\", \"%s\") failed", key, msg)
						return
					}

					return
				}
			} else if err, ok := msg.(error); ok {
				// DEBUG
				Log.Printf("Subscribe() failed (%s)", err.Error())
				return
			} else {
				Log.Printf("Unknown msg in RedisSub")
				return
			}
		}
	}
}
Пример #8
0
func SubscribeHandle(ws *websocket.Conn) {
	defer recoverFunc()

	params := ws.Request().URL.Query()
	// get subscriber key
	key := params.Get("key")
	// get lastest message id
	midStr := params.Get("mid")
	mid, err := strconv.ParseInt(midStr, 10, 64)
	if err != nil {
		Log.Printf("mid argument error (%s)", err.Error())
		return
	}

	// get heartbeat second
	heartbeat := Conf.HeartbeatSec
	heartbeatStr := params.Get("heartbeat")
	if heartbeatStr != "" {
		i, err := strconv.Atoi(heartbeatStr)
		if err != nil {
			Log.Printf("heartbeat argument error (%s)", err.Error())
			return
		}

		heartbeat = i
	}

	heartbeat *= 2
	if heartbeat <= 0 {
		Log.Printf("heartbeat argument error, less than 0")
		return
	}

	// get auth token
	token := params.Get("token")
	Log.Printf("client %s subscribe to key = %s, mid = %d, token = %s, heartbeat = %d", ws.Request().RemoteAddr, key, mid, token, heartbeat)
	// fetch subscriber from the channel
	c, err := channel.Get(key)
	if err != nil {
		if Conf.Auth == 0 {
			c, err = channel.New(key)
			if err != nil {
				Log.Printf("device %s: can't create channle", key)
				return
			}
		} else {
			Log.Printf("device %s: can't get a channel (%s)", key, err.Error())
			return
		}
	}

	// auth
	if Conf.Auth == 1 {
		if err = c.AuthToken(token, key); err != nil {
			Log.Printf("device %s: auth token failed \"%s\" (%s)", key, token, err.Error())
			return
		}
	}

	// send stored message, and use the last message id if sent any
	if err = c.SendMsg(ws, mid, key); err != nil {
		Log.Printf("device %s: send offline message failed (%s)", key, err.Error())
		return
	}

	// add a conn to the channel
	if err = c.AddConn(ws, mid, key); err != nil {
		Log.Printf("device %s: add conn failed (%s)", key, err.Error())
		return
	}

	// remove exists conn
	defer func() {
		if err := c.RemoveConn(ws, mid, key); err != nil {
			Log.Printf("device %s: remove conn failed (%s)", key, err.Error())
		}
	}()

	// blocking wait client heartbeat
	reply := ""
	for {
		ws.SetReadDeadline(time.Now().Add(time.Second * time.Duration(heartbeat)))
		if err = websocket.Message.Receive(ws, &reply); err != nil {
			Log.Printf("websocket.Message.Receive() failed (%s)", err.Error())
			return
		}

		if reply == heartbeatMsg {
			if _, err = ws.Write(heartbeatBytes); err != nil {
				Log.Printf("device %s: write heartbeat to client failed (%s)", key, err.Error())
				return
			}

			Log.Printf("device %s: receive heartbeat", key)
		} else {
			Log.Printf("device %s: unknown heartbeat protocol", key)
			return
		}
	}

	return
}
Пример #9
0
// Subscriber Handle is the websocket handle for sub request
func SubscribeHandle(ws *websocket.Conn) {
	params := ws.Request().URL.Query()
	// get subscriber key
	key := params.Get("key")
	// get lastest message id
	midStr := params.Get("mid")
	mid, err := strconv.ParseInt(midStr, 10, 64)
	if err != nil {
		LogError(LogLevelErr, "mid argument error (%s)", err.Error())
		return
	}

	// get heartbeat second
	heartbeat := Conf.HeartbeatSec
	heartbeatStr := params.Get("heartbeat")
	if heartbeatStr != "" {
		i, err := strconv.Atoi(heartbeatStr)
		if err != nil {
			LogError(LogLevelErr, "heartbeat argument error (%s)", err.Error())
			return
		}

		heartbeat = i
	}

	heartbeat *= 2
	if heartbeat <= 0 {
		LogError(LogLevelErr, "heartbeat argument error, less than 0")
		return
	}

	// get auth token
	token := params.Get("token")
	LogError(LogLevelInfo, "client:%s subscribe to key = %s, mid = %d, token = %s, heartbeat = %d", ws.Request().RemoteAddr, key, mid, token, heartbeat)
	// fetch subscriber from the channel
	c, err := channel.Get(key)
	if err != nil {
		if Conf.Auth == 0 {
			c, err = channel.New(key)
			if err != nil {
				LogError(LogLevelErr, "device:%s can't create channle (%s)", key, err.Error())
				return
			}
		} else {
			LogError(LogLevelErr, "device:%s can't get a channel (%s)", key, err.Error())
			return
		}
	}

	// auth
	if Conf.Auth == 1 {
		if err = c.AuthToken(token, key); err != nil {
			LogError(LogLevelErr, "device:%s auth token failed \"%s\" (%s)", key, token, err.Error())
			return
		}
	}

	// send first heartbeat to tell client service is ready for accept heartbeat
	if _, err = ws.Write(heartbeatBytes); err != nil {
		LogError(LogLevelErr, "device:%s write first heartbeat to client failed (%s)", key, err.Error())
		return
	}

	// send stored message, and use the last message id if sent any
	if err = c.SendMsg(ws, mid, key); err != nil {
		LogError(LogLevelErr, "device:%s send offline message failed (%s)", key, err.Error())
		return
	}

	// add a conn to the channel
	if err = c.AddConn(ws, mid, key); err != nil {
		LogError(LogLevelErr, "device:%s add conn failed (%s)", key, err.Error())
		return
	}

	// blocking wait client heartbeat
	reply := ""
	begin := time.Now().UnixNano()
	end := begin + oneSecond
	for {
		// more then 1 sec, reset the timer
		if end-begin >= oneSecond {
			if err = ws.SetReadDeadline(time.Now().Add(time.Second * time.Duration(heartbeat))); err != nil {
				LogError(LogLevelErr, "device:%s websocket.SetReadDeadline() failed (%s)", key, err.Error())
				break
			}

			begin = end
		}

		if err = websocket.Message.Receive(ws, &reply); err != nil {
			LogError(LogLevelErr, "device:%s websocket.Message.Receive() failed (%s)", key, err.Error())
			break
		}

		if reply == heartbeatMsg {
			if _, err = ws.Write(heartbeatBytes); err != nil {
				LogError(LogLevelErr, "device:%s write heartbeat to client failed (%s)", key, err.Error())
				break
			}

			LogError(LogLevelInfo, "device:%s receive heartbeat", key)
		} else {
			LogError(LogLevelWarn, "device:%s unknown heartbeat protocol", key)
			break
		}

		end = time.Now().UnixNano()
	}

	// remove exists conn
	if err := c.RemoveConn(ws, mid, key); err != nil {
		LogError(LogLevelErr, "device:%s remove conn failed (%s)", key, err.Error())
	}

	return
}
Пример #10
0
func (c *WebSocket) chat(ws *websocket.Conn) {
	//ws.SetReadDeadline(time.Now().Add(3 * time.Second))
	var register RegisterMsg
	var err error
	if err = websocket.JSON.Receive(ws, &register); err != nil {
		ERROR.Println(err)
		return
	}

	if register.Type != LoginMsgType || register.Id == 0 {
		ws.Write(LoginAlterJsonBytes)
		ERROR.Println("please login first")
		return
	}
	if register.DevType != 0x1 && register.DevType != 0x2 {
		ws.Write(UnknownDevicesJsonBytes)
		ERROR.Println("unknown devices")
		return
	}

	if _, err = ws.Write(OkJsonBytes); err != nil {
		ERROR.Println(err)
		return
	}

	client := NewChatClient(ws, register.Id, register.DevType)
	if err = hub.AddClient(client); err != nil {
		ERROR.Println(err)
		if redirect, ok := err.(*pmsg.RedirectError); ok {
			client.Redirect(redirect.HubId)
		}
		return
	}
	go client.SendMsgLoop()
	defer func() {
		if err := recover(); err != nil {
			ERROR.Println(err)
		}
		client.CloseChannel()
		hub.RemoveClient(client)
	}()

	var msgType byte = pmsg.RouteMsgType
	for {
		var msg Msg
		ws.SetReadDeadline(time.Now().Add(1 * time.Minute))
		if err := websocket.JSON.Receive(ws, &msg); err != nil {
			if err == io.EOF {
				INFO.Println(ws.Request().RemoteAddr, "closed")
			} else {
				ERROR.Println(err)
			}
			return
		}
		if msg.SourceType == 1 && (msg.To == nil || *msg.To == 0) {
			ws.Write(InvaildParameters)
			return
		}
		if msg.SourceType == 3 && (msg.Gid == nil || *msg.Gid == 0) {
			ws.Write(InvaildParameters)
			return
		}
		if err = validateMsg(&msg); err != nil {
			ERROR.Println(err)
			ws.Write(JsonFormatErrorJsonBytes)
			return
		}
		now := time.Now()
		switch msg.Type {
		case PingMsgType:
			//ping, don't reply
			continue
		case TokenRegisterMsgType:
			if msg.MsgId == "" || msg.Token == nil {
				ws.Write(ErrorMsgIdJsonFormatJsonBytes)
				return
			}
			reply := &ReplyMsg{
				Type:  ReplyMsgType,
				Time:  now.UnixNano() / 1000000,
				MsgId: msg.MsgId,
				Code:  0,
			}
			if err = registerToken(client.clientId, msg.Dev, *msg.Token); err != nil {
				reply.Code = -1
				reply.Msg = err.Error()
				ws.Write(reply.Bytes())
				return
			}
			client.SendMsg(reply)
			continue
		case TokenUnregisterMsgType:
			if msg.MsgId == "" || msg.Token == nil {
				ws.Write(ErrorMsgIdJsonFormatJsonBytes)
				return
			}
			reply := &ReplyMsg{
				Type:  ReplyMsgType,
				Time:  now.UnixNano() / 1000000,
				MsgId: msg.MsgId,
				Code:  0,
			}
			if err = unregisterToken(client.clientId, msg.Dev, *msg.Token); err != nil {
				reply.Code = -1
				reply.Msg = err.Error()
				ws.Write(reply.Bytes())
				return
			}
			client.SendMsg(reply)
			continue
		case ReadedMsgType:
			msg.From = client.clientId
		case TextMsgType, ImageMsgType, FileMsgType, SoundMsgType, StickMsgType, LocationMsgType:
			if msg.MsgId == "" {
				ws.Write(ErrorMsgIdJsonFormatJsonBytes)
				return
			}
			msg.From = client.clientId
			if len(register.Name) > 0 {
				msg.Sender = &register.Name
			}
			msg.Time = now.UnixNano() / 1000000

			reply := NewReplySuccessMsg(client.clientId, msg.MsgId, now.UnixNano())
			msg.MsgId = reply.NewMsgId
			client.SendMsg(reply)
		case GroupMemberDelMsgType, GroupRemoveMsgType, GroupAddMsgType:
			msg.From = client.clientId
			if len(register.Name) > 0 {
				msg.Sender = &register.Name
			}
			now := time.Now()
			msg.Time = now.UnixNano() / 1000000
		default:
			ERROR.Println("unknown message type, close client")
			ws.Write(UnknownMsgTypeJsonBytes)
			return
		}

		if msg.SourceType == 3 {
			//clone msg
			if err = sendGroupMsg(&msg, msgType); err != nil {
				ERROR.Println(err)
				ws.Write(ErrorJsonFormatJsonBytes)
			}
		} else {
			if err = sendMsg(&msg, msgType); err != nil {
				ERROR.Println(err)
				ws.Write(ErrorJsonFormatJsonBytes)
			}
		}
	}
}
Пример #11
0
// WSSendRecv is the handler for websocket client connections.  It loops
// forever (until disconnected), reading JSON-RPC requests and sending
// sending responses and notifications.
func (s *server) WSSendRecv(ws *websocket.Conn, remoteAddr string, authenticated bool) {
	// Clear the read deadline set before the websocket hijacked
	// the connection.
	ws.SetReadDeadline(time.Time{})

	// Add client context so notifications duplicated to each
	// client are received by this client.
	recvQuit := make(chan struct{})
	sendQuit := make(chan struct{})
	cc := clientContext{
		send: make(chan []byte, 1), // buffer size is number of initial notifications
		quit: make(chan struct{}),
	}
	go func() {
		select {
		case <-recvQuit:
		case <-sendQuit:
		}
		log.Infof("Disconnected websocket client %s", remoteAddr)
		close(cc.quit)
	}()
	log.Infof("New websocket client %s", remoteAddr)

	NotifyBtcdConnection(cc.send) // TODO(jrick): clients should explicitly request this.
	addClient <- cc

	// received passes all received messages from the currently connected
	// frontend to the for-select loop.  It is closed when reading a
	// message from the websocket connection fails (presumably due to
	// a disconnected client).
	recvQueueIn := make(chan string)

	// Receive messages from websocket and send across jsonMsgs until
	// connection is lost
	go func() {
		for {
			var m string
			if err := websocket.Message.Receive(ws, &m); err != nil {
				select {
				case <-sendQuit:
					// Do not log error.

				default:
					if err != io.EOF {
						log.Warnf("Websocket receive failed from client %s: %v",
							remoteAddr, err)
					}
				}
				close(recvQueueIn)
				close(recvQuit)
				return
			}
			recvQueueIn <- m
		}
	}()

	// Manage queue of received messages for LIFO processing.
	recvQueueOut := make(chan string)
	go stringQueue(recvQueueIn, recvQueueOut, cc.quit)

	badAuth := make(chan struct{})
	sendResp := make(chan []byte)
	go func() {
	out:
		for m := range recvQueueOut {
			resp, err := s.ReplyToFrontend([]byte(m), true, authenticated)
			if err == ErrBadAuth {
				select {
				case badAuth <- struct{}{}:
				case <-cc.quit:
				}
				break out
			}

			// Authentication passed.
			authenticated = true

			select {
			case sendResp <- resp:
			case <-cc.quit:
				break out
			}
		}
		close(sendResp)
	}()

	const deadline time.Duration = 2 * time.Second

out:
	for {
		var m []byte
		var ok bool

		select {
		case <-badAuth:
			// Bad auth. Disconnect.
			log.Warnf("Disconnecting unauthorized websocket client %s", remoteAddr)
			break out

		case m = <-cc.send: // sends from external writers.  never closes.
		case m, ok = <-sendResp:
			if !ok {
				// Nothing left to send.  Return so the handler exits.
				break out
			}
		case <-cc.quit:
			break out
		}

		err := ws.SetWriteDeadline(time.Now().Add(deadline))
		if err != nil {
			log.Errorf("Cannot set write deadline on client %s: %v", remoteAddr, err)
			break out
		}
		err = websocket.Message.Send(ws, string(m))
		if err != nil {
			log.Warnf("Websocket send failed to client %s: %v", remoteAddr, err)
			break out
		}
	}
	close(sendQuit)
	log.Tracef("Leaving function WSSendRecv")
}
Пример #12
0
func Chat(ws *websocket.Conn) {
	ws.SetReadDeadline(time.Now().Add(15 * time.Second))
	var loginMsg LoginMsg
	var user *UserInfo
	var err error
	if err = websocket.JSON.Receive(ws, &loginMsg); err != nil {
		ERROR.Println(err)
		return
	}

	if loginMsg.Type != LoginMsgType || loginMsg.Id == 0 {
		ws.Write(LoginAlterJsonBytes)
		ERROR.Println("please login first")
		return
	}

	if loginMsg.DevType != 0x1 && loginMsg.DevType != 0x2 {
		ws.Write(UnknownDevicesJsonBytes)
		ERROR.Println("unknown devices")
		return
	}
	if user, err = GetUserById(loginMsg.Id); err != nil {
		ws.Write(LoginFailJsonBytes)
		ERROR.Println(err)
		return
	}

	if user.Password != loginMsg.Password {
		ERROR.Println("login fail")
		ws.Write(LoginFailJsonBytes)
		return
	}
	if _, err = ws.Write(OkJsonBytes); err != nil {
		ERROR.Println(err)
		return
	}

	client := NewChatClient(ws, user.Id, loginMsg.DevType)
	if err = hub.AddClient(client); err != nil {
		ERROR.Println(err)
		if redirect, ok := err.(*pmsg.RedirectError); ok {
			client.Redirect(redirect.HubId)
		}
		return
	}
	go client.SendMsgLoop()
	defer func() {
		if err := recover(); err != nil {
			ERROR.Println(err)
		}
		client.CloseChannel()
		hub.RemoveClient(client)
	}()

	var pmsgType byte = pmsg.RouteMsgType
	for {
		message := map[string]json.RawMessage{}
		ws.SetReadDeadline(time.Now().Add(1 * time.Minute))
		if err := websocket.JSON.Receive(ws, &message); err != nil {
			if err == io.EOF {
				INFO.Println(ws.Request().RemoteAddr, "closed")
			} else {
				ERROR.Println(err)
			}
			return
		}
		var msgId string
		var msgType byte

		if err = ParseField(message, "type", &msgType); err != nil {
			ws.Write(UnknownDevicesJsonBytes)
			ERROR.Println("parse type error.", err)
			return
		}
		if err = ParseField(message, "id", &msgId); err != nil {
			ws.Write(UnknownDevicesJsonBytes)
			ERROR.Println("parse msgId error.", err)
			return
		}
		if msgType == PingMsgType {
			//ping, don't reply
			continue
		}

		var msg *Msg

		if msg, err = ConvertMsg(message); err != nil {
			ws.Write(UnknownDevicesJsonBytes)
			ERROR.Println(err)
			return
		}
		if msgId == "" {
			ws.Write(ErrorMsgIdJsonFormatJsonBytes)
			ERROR.Println("msgId is empty")
			return
		}

		msg.From = client.clientId
		if len(user.Name) > 0 {
			msg.Sender = &user.Name
		}
		now := time.Now()
		msg.Time = now.UnixNano() / 1000000
		msg.Type = msgType

		reply := NewReplySuccessMsg(client.clientId, msgId, now.UnixNano())
		msg.Id = reply.NId
		client.SendMsg(reply)

		if msg.Type == 2 {
			//clone msg
			if err = sendGroupMsg(msg, pmsgType); err != nil {
				ERROR.Println(err)
			}
		} else if msg.Type == 1 {
			if err = sendMsg(msg, pmsgType); err != nil {
				ERROR.Println(err)
			}
		} else {
			ERROR.Println("Unkown msg type:", msg.Type)
			return
		}
	}
}
Пример #13
0
// Subscriber Handle is the websocket handle for sub request.
func SubscribeHandle(ws *websocket.Conn) {
	params := ws.Request().URL.Query()
	// get subscriber key
	key := params.Get("key")
	if key == "" {
		Log.Warn("client:%s key param error", ws.Request().RemoteAddr)
		return
	}

	// get heartbeat second
	heartbeat := Conf.HeartbeatSec
	heartbeatStr := params.Get("heartbeat")
	if heartbeatStr != "" {
		i, err := strconv.Atoi(heartbeatStr)
		if err != nil {
			Log.Error("user_key:\"%s\" heartbeat argument error (%s)", key, err.Error())
			return
		}

		heartbeat = i
	}

	heartbeat *= 2
	if heartbeat <= 0 {
		Log.Error("user_key \"%s\" heartbeat argument error, less than 0", key)
		return
	}

	token := params.Get("token")
	Log.Info("client:%s subscribe to key = %s, heartbeat = %d, token = %s", ws.Request().RemoteAddr, key, heartbeat, token)
	// fetch subscriber from the channel
	c, err := UserChannel.Get(key)
	if err != nil {
		Log.Error("user_key:\"%s\" can't get a channel (%s)", key, err.Error())
		return
	}

	// auth token
	if Conf.Auth == 1 {
		if err = c.AuthToken(token, key); err != nil {
			Log.Error("user_key:\"%s\" auth token failed (%s)", key, err.Error())
			return
		}
	}

	// add a conn to the channel
	connElem, err := c.AddConn(ws, key)
	if err != nil {
		Log.Error("user_key:\"%s\" add conn failed (%s)", key, err.Error())
		return
	}

	// send first heartbeat to tell client service is ready for accept heartbeat
	if _, err = ws.Write(websocketHeartbeatReply); err != nil {
		Log.Error("user_key:\"%s\" write first heartbeat to client failed (%s)", key, err.Error())
		if err := c.RemoveConn(connElem, key); err != nil {
			Log.Error("user_key:\"%s\" remove conn failed (%s)", key, err.Error())
		}

		return
	}

	// 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 {
				Log.Error("user_key:\"%s\" websocket.SetReadDeadline() failed (%s)", key, err.Error())
				break
			}

			begin = end
		}

		if err = websocket.Message.Receive(ws, &reply); err != nil {
			Log.Error("user_key:\"%s\" websocket.Message.Receive() failed (%s)", key, err.Error())
			break
		}

		if reply == Heartbeat {
			if _, err = ws.Write(websocketHeartbeatReply); err != nil {
				Log.Error("user_key:\"%s\" write heartbeat to client failed (%s)", key, err.Error())
				break
			}

			Log.Debug("user_key:\"%s\" receive heartbeat", key)
		} else {
			Log.Warn("user_key:\"%s\" unknown heartbeat protocol", key)
			break
		}

		end = time.Now().UnixNano()
	}

	// remove exists conn
	if err := c.RemoveConn(connElem, key); err != nil {
		Log.Error("user_key:\"%s\" remove conn failed (%s)", key, err.Error())
	}

	return
}
Пример #14
0
// walletReqsNotifications is the handler function for websocket
// connections from a btcwallet instance.  It reads messages from wallet and
// sends back replies, as well as notififying wallets of chain updates.
func (s *rpcServer) walletReqsNotifications(ws *websocket.Conn, authenticated bool) {
	// Clear the read deadline that was set before the websocket hijacked
	// the connection.
	ws.SetReadDeadline(timeZeroVal)

	// Add wallet notification channel so this handler receives btcd chain
	// notifications.
	n := make(ntfnChan)
	rc := &requestContexts{
		authenticated:   authenticated,
		txRequests:      make(map[string]struct{}),
		spentRequests:   make(map[btcwire.OutPoint]struct{}),
		minedTxRequests: make(map[btcwire.ShaHash]struct{}),
	}
	s.AddWalletListener(n, rc)
	defer s.RemoveWalletListener(n)

	// Channel for responses.
	r := make(chan *btcjson.Reply)

	// Channels for websocket handlers.
	disconnected := make(chan struct{})
	hc := handlerChans{
		n:            n,
		disconnected: disconnected,
	}

	// msgs is a channel for all messages received over the websocket.
	msgs := make(chan string)

	// Receive messages from websocket and send across reqs until the
	// connection is lost.
	go func() {
		for {
			select {
			case <-s.quit:
				return

			default:
				var m string
				if err := websocket.Message.Receive(ws, &m); err != nil {
					// Only close disconnected if not closed yet.
					select {
					case <-disconnected:
						// nothing

					default:
						close(disconnected)
					}
					return
				}
				msgs <- m
			}
		}
	}()

	for {
		select {
		case <-s.quit:
			// Server closed.  Closing disconnected signals handlers to stop
			// and flushes all channels handlers may write to.
			select {
			case <-disconnected:
				// nothing

			default:
				close(disconnected)
			}

		case <-disconnected:
			for {
				select {
				case <-msgs:
				case <-r:
				case <-n:
				default:
					return
				}
			}

		case m := <-msgs:
			// This function internally spawns a new goroutine to
			// the handle request after validating authentication.
			// Responses and notifications are read by channels in
			// this for-select loop.
			if !rc.disconnecting {
				err := s.websocketJSONHandler(r, hc, m)
				if err == ErrBadAuth {
					rc.disconnecting = true
					close(disconnected)
					ws.Close()
				}
			}

		case response := <-r:
			// Marshal and send response.
			mresp, err := json.Marshal(response)
			if err != nil {
				rpcsLog.Errorf("Error unmarshaling response: %v", err)
				continue
			}
			if err := websocket.Message.Send(ws, string(mresp)); err != nil {
				// Only close disconnected if not closed yet.
				select {
				case <-disconnected:
					// nothing

				default:
					close(disconnected)
				}
				return
			}

		case ntfn := <-n:
			// Marshal and send notification.
			mntfn, err := ntfn.MarshalJSON()
			if err != nil {
				rpcsLog.Errorf("Error unmarshaling notification: %v", err)
				continue
			}
			if err := websocket.Message.Send(ws, string(mntfn)); err != nil {
				// Only close disconnected if not closed yet.
				select {
				case <-disconnected:
					// nothing

				default:
					close(disconnected)
				}
				return
			}
		}
	}
}
Пример #15
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
}