func (s *httpServer) getExistingTopicFromQuery(req *http.Request) (*http_api.ReqParams, *Topic, string, error) { reqParams, err := http_api.NewReqParams(req) if err != nil { s.ctx.nsqd.logf("ERROR: failed to parse request params - %s", err) return nil, nil, "", http_api.Err{400, "INVALID_REQUEST"} } topicName, channelName, err := http_api.GetTopicChannelArgs(reqParams) if err != nil { return nil, nil, "", http_api.Err{400, err.Error()} } topic, err := s.ctx.nsqd.GetExistingTopic(topicName) if err != nil { return nil, nil, "", http_api.Err{404, "TOPIC_NOT_FOUND"} } return reqParams, topic, channelName, err }
func (s *httpServer) doCreateChannel(w http.ResponseWriter, req *http.Request, ps httprouter.Params) (interface{}, error) { reqParams, err := http_api.NewReqParams(req) if err != nil { return nil, http_api.Err{400, "INVALID_REQUEST"} } topicName, channelName, err := http_api.GetTopicChannelArgs(reqParams) if err != nil { return nil, http_api.Err{400, err.Error()} } s.ctx.nsqlookupd.logf("DB: adding channel(%s) in topic(%s)", channelName, topicName) key := Registration{"channel", topicName, channelName} s.ctx.nsqlookupd.DB.AddRegistration(key) s.ctx.nsqlookupd.logf("DB: adding topic(%s)", topicName) key = Registration{"topic", topicName, ""} s.ctx.nsqlookupd.DB.AddRegistration(key) return nil, nil }
func (s *httpServer) doDeleteChannel(w http.ResponseWriter, req *http.Request, ps httprouter.Params) (interface{}, error) { reqParams, err := http_api.NewReqParams(req) if err != nil { return nil, http_api.Err{400, "INVALID_REQUEST"} } topicName, channelName, err := http_api.GetTopicChannelArgs(reqParams) if err != nil { return nil, http_api.Err{400, err.Error()} } registrations := s.ctx.nsqlookupd.DB.FindRegistrations("channel", topicName, channelName) if len(registrations) == 0 { return nil, http_api.Err{404, "CHANNEL_NOT_FOUND"} } s.ctx.nsqlookupd.logf("DB: removing channel(%s) from topic(%s)", channelName, topicName) for _, registration := range registrations { s.ctx.nsqlookupd.DB.RemoveRegistration(registration) } return nil, nil }
func (s *StreamServer) ServeHTTP(w http.ResponseWriter, req *http.Request) { path := req.URL.Path if path == "/stats" { StatsHandler(w, req) return } if path != "/sub" { w.WriteHeader(404) return } 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_pubsub/%s go-nsq/%s", version.Binary, 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(), } s.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, nsqdTCPAddrs, lookupdHTTPAddrs) log.Printf("connected to NSQ %v", errors) // this read allows us to detect clients that disconnect go func(rw *bufio.ReadWriter) { b, err := rw.ReadByte() if err != nil { log.Printf("got connection err %s", err.Error()) } else { log.Printf("unexpected data on request socket (%c); closing", b) } sr.consumer.Stop() }(bufrw) go sr.HeartbeatLoop() }