// 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() }
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 } } }
// 从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() }
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: } } }
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) } }
// 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 }
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 } } } }
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 }
// 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 }
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, ®ister); 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 = ®ister.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 = ®ister.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) } } } }
// 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") }
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 } } }
// 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 }
// 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 } } } }
// 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 }