// Read responses from the tunnel and fulfill pending requests func wsReader(rs *remoteServer, ws *websocket.Conn, wsTimeout time.Duration, ch chan int) { var err error log_token := cutToken(rs.token) // continue reading until we get an error for { ws.SetReadDeadline(time.Time{}) // no timeout, there's the ping-pong for that // read a message from the tunnel var t int var r io.Reader t, r, err = ws.NextReader() if err != nil { break } if t != websocket.BinaryMessage { err = fmt.Errorf("non-binary message received, type=%d", t) break } // give the sender a fixed time to get us the data ws.SetReadDeadline(time.Now().Add(wsTimeout)) // get request id var id int16 _, err = fmt.Fscanf(io.LimitReader(r, 4), "%04x", &id) if err != nil { break } // read request itself, the size is limited by the SetReadLimit on the websocket var buf []byte buf, err = ioutil.ReadAll(r) if err != nil { break } rs.log.Info("WS RCV", "id", id, "ws", wsp(ws), "len", len(buf)) // try to match request rs.requestSetMutex.Lock() req := rs.requestSet[id] rs.lastActivity = time.Now() rs.requestSetMutex.Unlock() // let's see... if req != nil { rb := responseBuffer{response: bytes.NewBuffer(buf)} // try to enqueue response select { case req.replyChan <- rb: // great! default: rs.log.Info("WS RCV can't enqueue response", "id", id, "ws", wsp(ws)) } } else { rs.log.Info("%s #%d: WS RCV orphan response", "id", id, "ws", wsp(ws)) } } // print error message if err != nil { rs.log.Info("WS closing", "token", log_token, "err", err.Error(), "ws", wsp(ws)) } // close up shop ch <- 0 // notify sender time.Sleep(2 * time.Second) ws.Close() }
/** Listen for Pods. We're only interested in MODIFIED and DELETED events. */ func listen(wsConn *websocket.Conn, wsErrors chan string) { log.Println("Listening for pods") for { _, r, err := wsConn.NextReader() if err != nil { log.Printf("Error getting reader: %v", err) wsErrors <- "Error" return } dec := json.NewDecoder(r) var objmap map[string]*json.RawMessage dec.Decode(&objmap) var actionType string json.Unmarshal(*objmap["type"], &actionType) var pod api.Pod err = json.Unmarshal(*objmap["object"], &pod) switch actionType { case "MODIFIED": register(pod) case "DELETED": deletePod(pod) } } }
// Listen for Services. func svcListener(wsConn *websocket.Conn, wsErrors chan string) { log.Println("Listening for services") for { _, r, err := wsConn.NextReader() if err != nil { log.Printf("Error getting reader: %v", err) wsErrors <- "Error" return } dec := json.NewDecoder(r) var objmap map[string]*json.RawMessage dec.Decode(&objmap) // debug purpose // b,_ := json.Marshal(objmap) // log.Printf("%s", b) var actionType string json.Unmarshal(*objmap["type"], &actionType) var svc api.Service err = json.Unmarshal(*objmap["object"], &svc) switch actionType { case "ADDED": registerSvc(svc) case "DELETED": unregisterSvc(svc) } } }
func readLoop(c *websocket.Conn) { for { if _, _, err := c.NextReader(); err != nil { c.Close() break } } }
func (ws *Websocket) Reader(c *goWs.Conn, closed chan<- bool) { defer c.Close() for { messageType, _, err := c.NextReader() if err != nil || messageType == goWs.CloseMessage { break } } closed <- true }
func keepWsAlive(ws *websocket.Conn) { // We repeatedly read from the websocket connections and discard // the reader in order to process the underlying ping/pong messages // of the websocket connection for { _, _, err := ws.NextReader() if err != nil { ws.Close() break } } }
func ws_null_reader(conn *websocket.Conn, info_ptr *WsInfo) { // Apparently reading WebSocket messages from clients is mandatory. // This function also closes connections if needed. for { if _, _, err := conn.NextReader(); err != nil { remove_from_ws_client_list(info_ptr) conn.Close() return } } }
func streamWebsocketIOFromContainerizer(ws *websocket.Conn, pidChannel chan<- string, processIO garden.ProcessIO) (int, error) { defer close(pidChannel) defer func() { ws.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")) go func() { for { _, _, err := ws.NextReader() if err != nil { ws.Close() break } } }() }() receiveStream := ProcessStreamEvent{} for { err := websocket.ReadJSON(ws, &receiveStream) if err != nil { return -1, err } if receiveStream.MessageType == "pid" { pidChannel <- receiveStream.Data } if receiveStream.MessageType == "stdout" && processIO.Stdout != nil { io.WriteString(processIO.Stdout, receiveStream.Data) } if receiveStream.MessageType == "stderr" && processIO.Stderr != nil { io.WriteString(processIO.Stderr, receiveStream.Data) } if receiveStream.MessageType == "error" { return -1, errors.New(receiveStream.Data) } if receiveStream.MessageType == "close" { exitCode, err := strconv.Atoi(receiveStream.Data) if err != nil { return -1, err } return exitCode, nil } } }
func (this *Server) NewConnection(conn *websocket.Conn) (string, error) { _, reader, err := conn.NextReader() if err != nil { glog.Errorf("Error establishing new connection: %s", err.Error()) } user, err := message.GetUser(reader) if err != nil { return "", err } glog.Infof("Register conenction with uid: %s", user.Uid) this.Users[user.Uid] = NewClient(conn, user) this.Users[user.Uid].Send(user, message.MSG_USER_DATA) return user.Uid, nil }
func WebsocketRecvStream(w io.WriteCloser, conn *websocket.Conn) chan bool { ch := make(chan bool) go func(w io.WriteCloser, conn *websocket.Conn) { for { mt, r, err := conn.NextReader() if mt == websocket.CloseMessage { Debugf("Got close message for reader") break } if mt == websocket.TextMessage { Debugf("got message barrier") break } if err != nil { Debugf("Got error getting next reader %s, %s", err, w) break } buf, err := ioutil.ReadAll(r) if err != nil { Debugf("Got error writing to writer %s", err) break } if w == nil { continue } i, err := w.Write(buf) if i != len(buf) { Debugf("Didn't write all of buf") break } if err != nil { Debugf("Error writing buf %s", err) break } } ch <- true }(w, conn) return ch }
func wsReader(conn *websocket.Conn, m chan<- message, e chan<- error) { for { t, r, err := conn.NextReader() if err != nil { e <- io.EOF return } msg, err := ioutil.ReadAll(r) if err != nil { e <- err return } m <- message{ws.MsgType(t), msg} } }
func (sc *ServerConnection) read(ws *websocket.Conn) { // log.Println("Response", resp) status := new(ServerUpdate) status.ConnID = sc.ConnID for { select { case <-sc.quit: log.Println("server reader got quit message") sc.quit <- true return default: ws.SetReadDeadline(time.Now().Add(time.Second * 3)) sc.statusMsg("Ok") op, r, err := ws.NextReader() if err != nil { status := fmt.Sprintf("Error reading from server: %s", err) sc.statusErrorMsg(status) log.Println(status) return } msg, err := ioutil.ReadAll(r) // log.Println("op", op, "msg", string(msg), "err", err) if op == websocket.TextMessage { err = json.Unmarshal(msg, &status) if err != nil { log.Printf("Unmarshall err from '%s': '%s', data: '%s'\n", sc.IP.String(), err, msg) } // log.Printf("Got status: %#v\n", status) sc.updateChan <- status } else { log.Println("op", op, "msg", string(msg), "err", err) } // os.Exit(0) } } }
func processRotondePackets(conn *websocket.Conn, inChan, outChan chan interface{}) { var wg sync.WaitGroup wg.Add(1) go func() { defer wg.Done() for { select { case dispatcherPacket := <-inChan: jsonPacket, err := rotonde.ToJSON(dispatcherPacket) if err != nil { log.Warning(err) } if err := conn.WriteMessage(websocket.TextMessage, jsonPacket); err != nil { log.Fatal(err) return } } } }() wg.Add(1) go func() { defer wg.Done() for { messageType, reader, err := conn.NextReader() if err != nil { log.Fatal(err) return } if messageType == websocket.TextMessage { dispatcherPacket, err := rotonde.FromJSON(reader) if err != nil { log.Warning(err) } outChan <- dispatcherPacket } } }() log.Info("Treating messages") wg.Wait() }
// reader is the guts of this package. It takes the stdin and stdout pipes // of the cmd we created in ServeWS and pipes them between the client and server // over websockets. func reader(conn *websocket.Conn, stdout io.ReadCloser, stdin io.WriteCloser) { // Setup our connection's websocket ping/pong handlers from our const values. conn.SetReadLimit(maxMessageSize) conn.SetReadDeadline(time.Now().Add(pongWait)) conn.SetPongHandler(func(string) error { conn.SetReadDeadline(time.Now().Add(pongWait)); return nil }) tickerChan := make(chan bool) defer close(tickerChan) // make sure to close the ticker when we are done. go ticker(conn, tickerChan) for { msgType, r, err := conn.NextReader() if err != nil { if msgType == -1 { return // we got a disconnect from the client. We are good to close. } conn.WriteControl(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseGoingAway, ""), time.Time{}) return } w, err := conn.NextWriter(msgType) if err != nil { conn.WriteControl(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseGoingAway, ""), time.Time{}) return } if _, err := io.Copy(stdin, r); err != nil { conn.WriteControl(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseGoingAway, ""), time.Time{}) return } go func() { if _, err := io.Copy(w, stdout); err != nil { conn.WriteControl(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseGoingAway, ""), time.Time{}) return } if err := w.Close(); err != nil { conn.WriteControl(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseGoingAway, ""), time.Time{}) return } }() } }
func WSHandler(c *websocket.Conn) { closed := false ret := websocket.CloseError{ Code: websocket.CloseNormalClosure, } const writeWait = 10 * time.Second defer func() { log.Infof("Close websocket [%s]", ret.Error()) c.WriteControl(websocket.CloseMessage, websocket.FormatCloseMessage(ret.Code, ret.Text), time.Now().Add(writeWait)) c.Close() }() go func() { for { _, r, err := c.NextReader() if err != nil { break } io.Copy(ioutil.Discard, r) } log.Infof("Pipe closed") closed = true }() for !closed { signal := M{ "pm2.5": atomic.LoadInt32(¤tPM25), "pm10": atomic.LoadInt32(¤tPM100), } if err := c.WriteJSON(signal); err != nil && err != websocket.ErrCloseSent { if _, ok := err.(net.Error); !ok { log.Warnf("Error writing to client: %s", err.Error()) } closed = true } time.Sleep(2 * time.Second) } }
func readMessage(c *websocket.Conn, t *testing.T) Message { op, r, err := c.NextReader() if op != websocket.TextMessage { t.Error("expecting a text message") } if err != nil { t.Error("cannot create reader") } str, err := ioutil.ReadAll(r) if err != nil { t.Error("websocket read error") } msg := Message{} if err := json.Unmarshal(str, &msg); err != nil { t.Error("cannot parse websocket response") } return msg }
func (user *User) Receiver(location *Location, ws *websocket.Conn) { // receives and decodes messages from users go func() { ws.SetReadLimit(MAX_MESSAGE_SIZE) ws.SetReadDeadline(time.Now().Add(PONG_WAIT)) ws.SetPongHandler(func(string) error { ws.SetReadDeadline(time.Now().Add(PONG_WAIT)) return nil }) for { op, r, err := ws.NextReader() if err != nil { user.Kick(err.Error()) return } switch op { case websocket.BinaryMessage: data, err := ioutil.ReadAll(r) if err != nil { user.Kick(err.Error()) return } var event []interface{} err = codec.NewDecoderBytes(data, &msgpackHandle).Decode(&event) if err != nil { user.Kick(err.Error()) return } location.Message <- &UserAndEvent{user, &event} default: user.Kick(fmt.Sprintf("bad message type: %v", op)) return } } }() }
func addSlowWSSink(receivedChan chan []byte, errChan chan error, timeout time.Duration, url string) { var ws *websocket.Conn tryToConnect := func() error { var err error ws, _, err = websocket.DefaultDialer.Dial(url, http.Header{}) return err } Eventually(tryToConnect, 5).ShouldNot(HaveOccurred()) go func() { time.Sleep(timeout) _, reader, err := ws.NextReader() if err != nil { errChan <- err return } received, err := ioutil.ReadAll(reader) if err != nil { errChan <- err return } receivedChan <- received }() }
func startWebsocketConnection(conn *websocket.Conn, d *Dispatcher) { c := NewConnection() d.AddConnection(c) defer c.Close() errChan := make(chan error, 1) defer close(errChan) var wg sync.WaitGroup wg.Add(1) go func() { defer wg.Done() for { select { case dispatcherPacket := <-c.InChan: jsonPacket, err := rotonde.ToJSON(dispatcherPacket) if err != nil { log.Warning(err) } if err := conn.WriteMessage(websocket.TextMessage, jsonPacket); err != nil { log.Warning(err) return } case <-errChan: log.Warning("Got error from errChan") return } } }() wg.Add(1) go func() { defer wg.Done() for { messageType, reader, err := conn.NextReader() if err != nil { log.Warning(err) errChan <- err return } if messageType == websocket.TextMessage { dispatcherPacket, err := rotonde.FromJSON(reader) if err != nil { log.Warning(err) } c.OutChan <- dispatcherPacket } } }() log.Info("Treating messages") wg.Wait() select { case <-errChan: log.Warning("errChan was not empty") default: log.Warning("errChan was empty") } log.Info("Websocket connection end") }
// WebsocketMirror allows mirroring a reader to a websocket and taking the // result and writing it to a writer. This function allows for multiple // mirrorings and correctly negotiates stream endings. However, it means any // websocket.Conns passed to it are live when it returns, and must be closed // explicitly. func WebsocketMirror(conn *websocket.Conn, w io.WriteCloser, r io.ReadCloser) (chan bool, chan bool) { readDone := make(chan bool, 1) writeDone := make(chan bool, 1) go func(conn *websocket.Conn, w io.WriteCloser) { for { mt, r, err := conn.NextReader() if err != nil { Debugf("Got error getting next reader %s, %s", err, w) break } if mt == websocket.CloseMessage { Debugf("Got close message for reader") break } if mt == websocket.TextMessage { Debugf("Got message barrier, resetting stream") break } buf, err := ioutil.ReadAll(r) if err != nil { Debugf("Got error writing to writer %s", err) break } i, err := w.Write(buf) if i != len(buf) { Debugf("Didn't write all of buf") break } if err != nil { Debugf("Error writing buf %s", err) break } } writeDone <- true w.Close() }(conn, w) go func(conn *websocket.Conn, r io.ReadCloser) { in := ReaderToChannel(r) for { buf, ok := <-in if !ok { readDone <- true r.Close() Debugf("sending write barrier") conn.WriteMessage(websocket.TextMessage, []byte{}) return } w, err := conn.NextWriter(websocket.BinaryMessage) if err != nil { Debugf("Got error getting next writer %s", err) break } _, err = w.Write(buf) w.Close() if err != nil { Debugf("Got err writing %s", err) break } } closeMsg := websocket.FormatCloseMessage(websocket.CloseNormalClosure, "") conn.WriteMessage(websocket.CloseMessage, closeMsg) readDone <- true r.Close() }(conn, r) return readDone, writeDone }
// WebsocketMirror allows mirroring a reader to a websocket and taking the // result and writing it to a writer. func WebsocketMirror(conn *websocket.Conn, w io.WriteCloser, r io.Reader) chan bool { done := make(chan bool, 2) go func(conn *websocket.Conn, w io.WriteCloser) { for { mt, r, err := conn.NextReader() if mt == websocket.CloseMessage { Debugf("got close message for reader") break } if err != nil { Debugf("got error getting next reader %s, %s", err, w) break } buf, err := ioutil.ReadAll(r) if err != nil { Debugf("got error writing to writer %s", err) break } i, err := w.Write(buf) if i != len(buf) { Debugf("didn't write all of buf") break } if err != nil { Debugf("error writing buf %s", err) break } } done <- true w.Close() }(conn, w) go func(conn *websocket.Conn, r io.Reader) { in := ReaderToChannel(r) for { buf, ok := <-in if !ok { done <- true conn.WriteMessage(websocket.CloseMessage, []byte{}) conn.Close() return } w, err := conn.NextWriter(websocket.BinaryMessage) if err != nil { Debugf("got error getting next writer %s", err) break } _, err = w.Write(buf) w.Close() if err != nil { Debugf("got err writing %s", err) break } } closeMsg := websocket.FormatCloseMessage(websocket.CloseNormalClosure, "") conn.WriteMessage(websocket.CloseMessage, closeMsg) done <- true }(conn, r) return done }
// Stream will init a new pubsub.KafkaPublisher and pubsub.KafkaSubscriber // then upgrade the current request to a websocket connection. Any messages // consumed from Kafka will be published to the web socket and vice versa. func (s *StreamService) Stream(w http.ResponseWriter, r *http.Request) { cfg := *s.cfg cfg.Topic = topicName(web.GetInt64Var(r, "stream_id")) server.LogWithFields(r).WithField("topic", cfg.Topic).Info("new stream req") sub, err := pubsub.NewKafkaSubscriber(&cfg, zeroOffset, discardOffset) if err != nil { server.LogWithFields(r).WithField("error", err).Error("unable to create sub") http.Error(w, "unable to create subscriber: "+err.Error(), http.StatusBadRequest) return } defer func() { if err := sub.Stop(); err != nil { server.LogWithFields(r).WithField("error", err).Error("unable to stop sub") } }() var pub *pubsub.KafkaPublisher pub, err = pubsub.NewKafkaPublisher(&cfg) if err != nil { server.LogWithFields(r).WithField("error", err).Error("unable to create pub") http.Error(w, "unable to create publisher: "+err.Error(), http.StatusBadRequest) return } defer func() { if err := pub.Stop(); err != nil { server.LogWithFields(r).WithField("error", err).Error("unable to stop pub") } }() var ws *websocket.Conn ws, err = upgrader.Upgrade(w, r, nil) if err != nil { server.LogWithFields(r).WithField("error", err).Error("unable to create websocket") http.Error(w, "unable to create websocket: "+err.Error(), http.StatusBadRequest) return } defer func() { if err := ws.Close(); err != nil { server.LogWithFields(r).WithField("error", err).Error("unable to close ws") } }() // start consumer, emit to ws noopTicker := time.NewTicker(time.Second * 5) subscriberDone := make(chan bool, 1) stopSubscriber := make(chan bool, 1) go func() { defer func() { subscriberDone <- true }() var ( payload []byte msgs = sub.Start() ) for { select { case msg := <-msgs: payload = msg.Message() err = ws.SetWriteDeadline(time.Now().Add(time.Second * 30)) if err != nil { server.LogWithFields(r).WithField("error", err).Error("unable to write deadline") } err = ws.WriteMessage(websocket.TextMessage, payload) if err != nil { server.LogWithFields(r).WithField("error", err).Error("unable to write ws message") } err = msg.Done() if err != nil { server.LogWithFields(r).WithField("error", err).Error("unable to mark gizmo message as done") } case <-noopTicker.C: err = ws.SetWriteDeadline(time.Now().Add(time.Second * 30)) if err != nil { server.LogWithFields(r).WithField("error", err).Error("unable to write deadline") } if err := ws.WriteMessage(websocket.PingMessage, []byte("ping")); err != nil { server.LogWithFields(r).WithField("error", err).Error("error writing ws message") return } case <-stopSubscriber: return } } }() // start producer, emit to kafka producerDone := make(chan bool, 1) go func() { defer func() { producerDone <- true stopSubscriber <- true server.LogWithFields(r).WithField("topic", cfg.Topic).Info("closing stream req") }() var ( messageType int payload []byte err error read io.Reader ) for { messageType, read, err = ws.NextReader() if err != nil { if err != io.EOF { server.LogWithFields(r).WithField("error", err).Error("error reading message") } return } switch messageType { case websocket.TextMessage: payload, err = ioutil.ReadAll(read) if err != nil { server.LogWithFields(r).WithField("error", err).Error("unable to read payload") return } err = pub.PublishRaw(cfg.Topic, payload) if err != nil { server.LogWithFields(r).WithField("error", err).Error("unable to publish payload") return } case websocket.PingMessage, websocket.PongMessage, websocket.BinaryMessage: server.LogWithFields(r).Info("discarding message type: ", messageType) case websocket.CloseMessage: server.LogWithFields(r).Info("closing websocket") return } } }() <-subscriberDone <-producerDone noopTicker.Stop() server.LogWithFields(r).WithField("topic", cfg.Topic).Info("leaving stream req") }
func startConnection(conn *websocket.Conn, d *Dispatcher) { c := NewConnection() d.AddConnection(c) defer c.Close() errChan := make(chan error) var wg sync.WaitGroup wg.Add(1) go func() { defer wg.Done() var jsonPacket []byte var err error var packet rotonde.Packet for { select { case dispatcherPacket := <-c.InChan: switch data := dispatcherPacket.(type) { case rotonde.Event: packet = rotonde.Packet{Type: "event", Payload: data} case rotonde.Action: packet = rotonde.Packet{Type: "action", Payload: data} case rotonde.Definition: packet = rotonde.Packet{Type: "def", Payload: data} case rotonde.UnDefinition: packet = rotonde.Packet{Type: "undef", Payload: data} default: log.Info("Oops unknown packet: ", dispatcherPacket) } jsonPacket, err = json.Marshal(packet) if err != nil { log.Warning(err) } if err := conn.WriteMessage(websocket.TextMessage, jsonPacket); err != nil { log.Warning(err) return } case <-errChan: return } } }() wg.Add(1) go func() { defer wg.Done() var dispatcherPacket interface{} for { messageType, reader, err := conn.NextReader() if err != nil { log.Println(err) errChan <- err return } if messageType == websocket.TextMessage { packet := rotonde.Packet{} decoder := json.NewDecoder(reader) if err := decoder.Decode(&packet); err != nil { log.Warning(err) continue } switch packet.Type { case "event": event := rotonde.Event{} mapstructure.Decode(packet.Payload, &event) dispatcherPacket = event case "action": action := rotonde.Action{} mapstructure.Decode(packet.Payload, &action) dispatcherPacket = action case "sub": subscription := rotonde.Subscription{} mapstructure.Decode(packet.Payload, &subscription) dispatcherPacket = subscription case "unsub": unsubscription := rotonde.Unsubscription{} mapstructure.Decode(packet.Payload, &unsubscription) dispatcherPacket = unsubscription case "def": definition := rotonde.Definition{} mapstructure.Decode(packet.Payload, &definition) dispatcherPacket = definition case "undef": unDefinition := rotonde.UnDefinition{} mapstructure.Decode(packet.Payload, &unDefinition) dispatcherPacket = unDefinition } c.OutChan <- dispatcherPacket } } }() log.Println("Treating messages") wg.Wait() }