// Write received messages from a channel to the websocket client func FrameServer(conn *websocket.Conn) { // Set the PayloadType to binary conn.PayloadType = websocket.BinaryFrame client := NewClient() registerClient <- client defer func() { unregisterClient <- client }() // Write the header as the first message to the client (MPEG size etc.) conn.SetWriteDeadline(time.Now().Add(ClientWriteTimeout * time.Second)) if _, err := conn.Write(*headerMessage); err != nil { return } // Continuously read messages from the queue and write to the client, stop on error for msg := range client.queue { conn.SetWriteDeadline(time.Now().Add(ClientWriteTimeout * time.Second)) if _, err := conn.Write(*msg); err != nil { return } } }
func WsBuildServer(ws *websocket.Conn) { defer ws.Close() var err error clientMsg := new(Message) if err = websocket.JSON.Receive(ws, &clientMsg); err != nil { Debugf("read json error: %v", err) return } addr := clientMsg.Data name := ws.RemoteAddr().String() log.Println("handle request project:", addr, name) proj := NewProject(addr, name) defer proj.Close() firstMsg := &Message{ Data: proj.BufferStr, } err = websocket.JSON.Send(ws, firstMsg) if err != nil { Debugf("send first msg error: %v", err) return } // send the rest outputs buf := make([]byte, 100) msg := new(Message) for { n, err := proj.Reader.Read(buf) if n > 0 { msg.Data = string(buf[:n]) deadline := time.Now().Add(time.Second * 1) ws.SetWriteDeadline(deadline) if er := websocket.JSON.Send(ws, msg); er != nil { log.Println("write failed timeout, user logout") return } } if err != nil { return } } log.Println(addr, "loop ends") }
func (t *Server) HandleWebsocket(conn *websocket.Conn) { defer conn.Close() log.Debug("turnpike: received websocket connection") tid, err := uuid.NewV4() if err != nil { log.Error("turnpike: could not create unique id, refusing client connection") return } id := tid.String() log.Info("turnpike: client connected: %s", id) arr, err := CreateWelcome(id, TURNPIKE_SERVER_IDENT) if err != nil { log.Error("turnpike: error encoding welcome message") return } log.Debug("turnpike: sending welcome message: %s", arr) err = websocket.Message.Send(conn, string(arr)) if err != nil { log.Error("turnpike: error sending welcome message, aborting connection: %s", err) return } c := make(chan string, serverBacklog) t.clients[id] = c failures := 0 go func() { for msg := range c { log.Trace("turnpike: sending message: %s", msg) conn.SetWriteDeadline(time.Now().Add(CLIENT_CONN_TIMEOUT * time.Second)) err := websocket.Message.Send(conn, msg) if err != nil { if nErr, ok := err.(net.Error); ok && (nErr.Timeout() || nErr.Temporary()) { log.Warn("Network error: %s", nErr) failures++ if failures > CLIENT_MAX_FAILURES { break } } else { log.Error("turnpike: error sending message: %s", err) break } } } log.Info("Client %s disconnected", id) t.subLock.Lock() rooms := t.Rooms.FindClient(id) t.subLock.Unlock() for r := rooms.Front(); r != nil; r = r.Next() { room := r.Value.(*Room) room.RemoveClientByID(id) log.Debug("Removing client %s from room", id) } conn.Close() }() for { var rec string err := websocket.Message.Receive(conn, &rec) if err != nil { if err != io.EOF { log.Error("turnpike: error receiving message, aborting connection: %s", err) } break } log.Trace("turnpike: message received: %s", rec) data := []byte(rec) switch typ := ParseType(rec); typ { case PREFIX: var msg PrefixMsg err := json.Unmarshal(data, &msg) if err != nil { log.Error("turnpike: error unmarshalling prefix message: %s", err) continue } t.handlePrefix(id, msg) case CALL: var msg CallMsg err := json.Unmarshal(data, &msg) if err != nil { log.Error("turnpike: error unmarshalling call message: %s", err) continue } t.handleCall(id, msg) case SUBSCRIBE: var msg SubscribeMsg err := json.Unmarshal(data, &msg) if err != nil { log.Error("turnpike: error unmarshalling subscribe message: %s", err) continue } // Check access t.handleSubscribe(id, msg) case UNSUBSCRIBE: var msg UnsubscribeMsg err := json.Unmarshal(data, &msg) if err != nil { log.Error("turnpike: error unmarshalling unsubscribe message: %s", err) continue } t.handleUnsubscribe(id, msg) case PUBLISH: var msg PublishMsg err := json.Unmarshal(data, &msg) if err != nil { log.Error("turnpike: error unmarshalling publish message: %s", err) continue } // check master room, r := t.Rooms.Contains(msg.TopicURI) if !r { log.Error("turnpike: Room does not exist: %s", msg.TopicURI) return } if !room.IsMaster(id) { if room.Auth(id) { if !jsonDataCheck(msg.Event.(map[string]interface{}), "type", "echo") { log.Trace("NOT ECHO Message") continue } log.Debug("ECHO Message Sent from client %s", id) } else { log.Warn("Client %s not authenticated", id) continue } } t.handlePublish(id, msg) case AUTH: var msg AuthMsg err := json.Unmarshal(data, &msg) if err != nil { log.Error("turnpike AUTH: error unmarshalling publish message: %s", err) continue } t.handleAuth(id, msg) case WELCOME, CALLRESULT, CALLERROR, EVENT: log.Error("turnpike: server -> client message received, ignored: %s", TypeString(typ)) default: log.Error("turnpike: invalid message format, message dropped: %s", data) } } delete(t.clients, id) close(c) }
// 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") }
// HandleWebsocket implements the go.net/websocket.Handler interface. func (t *Server) HandleWebsocket(conn *websocket.Conn) { defer conn.Close() if debug { log.Print("turnpike: received websocket connection") } tid, err := uuid.NewV4() if err != nil { if debug { log.Print("turnpike: could not create unique id, refusing client connection") } return } id := tid.String() if debug { log.Printf("turnpike: client connected: %s", id) } arr, err := createWelcome(id, turnpikeServerIdent) if err != nil { if debug { log.Print("turnpike: error encoding welcome message") } return } if debug { log.Printf("turnpike: sending welcome message: %s", arr) } err = websocket.Message.Send(conn, string(arr)) if err != nil { if debug { log.Printf("turnpike: error sending welcome message, aborting connection: %s", err) } return } c := make(chan string, serverBacklog) t.clients[id] = c if t.sessionOpenCallback != nil { t.sessionOpenCallback(id) } failures := 0 go func() { for msg := range c { if debug { log.Printf("turnpike: sending message: %s", msg) } conn.SetWriteDeadline(time.Now().Add(clientConnTimeout * time.Second)) err := websocket.Message.Send(conn, msg) if err != nil { if nErr, ok := err.(net.Error); ok && (nErr.Timeout() || nErr.Temporary()) { log.Printf("Network error: %s", nErr) failures++ if failures > clientMaxFailures { break } } else { if debug { log.Printf("turnpike: error sending message: %s", err) } break } } } if debug { log.Printf("Client %s disconnected", id) } conn.Close() }() for { var rec string err := websocket.Message.Receive(conn, &rec) if err != nil { if err != io.EOF { if debug { log.Printf("turnpike: error receiving message, aborting connection: %s", err) } } break } if debug { log.Printf("turnpike: message received: %s", rec) } data := []byte(rec) switch typ := parseMessageType(rec); typ { case msgPrefix: var msg prefixMsg err := json.Unmarshal(data, &msg) if err != nil { if debug { log.Printf("turnpike: error unmarshalling prefix message: %s", err) } continue } t.handlePrefix(id, msg) case msgCall: var msg callMsg err := json.Unmarshal(data, &msg) if err != nil { if debug { log.Printf("turnpike: error unmarshalling call message: %s", err) } continue } t.handleCall(id, msg) case msgSubscribe: var msg subscribeMsg err := json.Unmarshal(data, &msg) if err != nil { if debug { log.Printf("turnpike: error unmarshalling subscribe message: %s", err) } continue } t.handleSubscribe(id, msg) case msgUnsubscribe: var msg unsubscribeMsg err := json.Unmarshal(data, &msg) if err != nil { if debug { log.Printf("turnpike: error unmarshalling unsubscribe message: %s", err) } continue } t.handleUnsubscribe(id, msg) case msgPublish: var msg publishMsg err := json.Unmarshal(data, &msg) if err != nil { if debug { log.Printf("turnpike: error unmarshalling publish message: %s", err) } continue } t.handlePublish(id, msg) case msgWelcome, msgCallResult, msgCallError, msgEvent: if debug { log.Printf("turnpike: server -> client message received, ignored: %s", messageTypeString(typ)) } default: if debug { log.Printf("turnpike: invalid message format, message dropped: %s", data) } } } delete(t.clients, id) close(c) }