func broadcastChannelOp(op string, req *http.Request) (err error) { reqParams, err := http_api.NewReqParams(req) if err != nil { return } topicName, channelName, err := http_api.GetTopicChannelArgs(reqParams) if err != nil { return } for _, addr := range getAllProducersHttpAddr(topicName) { req_url := fmt.Sprintf("%s%s?topic=%s&channel=%s", addr, op, topicName, channelName) resp, err := http.PostForm(req_url, url.Values{}) if err != nil { log.Printf("request nsqd fail %s %s", req_url, err.Error()) return err } defer resp.Body.Close() respBody, err := ioutil.ReadAll(resp.Body) log.Printf("request nsqd %s [%s] %v", req_url, string(respBody), err) } return nil }
func SubHandler(w http.ResponseWriter, req *http.Request) { reqParams, err := http_api.NewReqParams(req) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } topicName, channelName, err := http_api.GetTopicChannelArgs(reqParams) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } hj, ok := w.(http.Hijacker) if !ok { http.Error(w, "httpserver doesn't support hijacking", http.StatusInternalServerError) return } conn, bufrw, err := hj.Hijack() if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } cfg := nsq.NewConfig() cfg.UserAgent = fmt.Sprintf("nsq_httpsub go-nsq/%s", nsq.VERSION) cfg.MaxInFlight = *maxInFlight r, err := nsq.NewConsumer(topicName, channelName, cfg) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } r.SetLogger(log.New(os.Stderr, "", log.LstdFlags), nsq.LogLevelInfo) sr := &StreamReader{ topic: topicName, channel: channelName, consumer: r, req: req, conn: conn, bufrw: bufrw, // TODO: latency writer connectTime: time.Now(), } streamServer.Set(sr) log.Printf("[%s] new connection", conn.RemoteAddr().String()) bufrw.WriteString("HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Type: text/plain; charset=utf-8\r\n\r\n") bufrw.Flush() r.AddHandler(sr) // TODO: handle the error cases better (ie. at all :) ) errors := ConnectToNSQAndLookupd(r, lookupdHTTPAddrs) log.Printf("connected to NSQ %v", errors) if *timeout > 0 { go func(sr *StreamReader) { timer := time.AfterFunc(time.Duration(*timeout)*time.Second, func() { log.Printf("timeout after %d seconds", *timeout) sr.consumer.Stop() }) for { select { case <-sr.consumer.StopChan: timer.Stop() return } } }(sr) } go sr.HeartbeatLoop() // this read allows us to detect clients that disconnect go func(rw *bufio.ReadWriter) { b, err := rw.ReadByte() if err != nil { log.Printf("disconnect client %s", err.Error()) } else { log.Printf("unexpected data on request socket (%c); closing", b) } sr.consumer.Stop() }(bufrw) }