// serveWatch handles serving requests to the server func serveWatch(watcher watch.Interface, scope RequestScope, w http.ResponseWriter, req *restful.Request, minRequestTimeout time.Duration) { var timeout time.Duration if minRequestTimeout > 0 { // Each watch gets a random timeout between minRequestTimeout and 2*minRequestTimeout to avoid thundering herds. timeout = time.Duration(float64(minRequestTimeout) * (rand.Float64() + 1.0)) } watchServer := &WatchServer{watcher, scope.Codec, func(obj runtime.Object) { if err := setSelfLink(obj, req, scope.Namer); err != nil { glog.V(5).Infof("Failed to set self link for object %v: %v", reflect.TypeOf(obj), err) } }, &realTimeoutFactory{timeout}} if isWebsocketRequest(req.Request) { websocket.Handler(watchServer.HandleWS).ServeHTTP(httplog.Unlogged(w), req.Request) } else { watchServer.ServeHTTP(w, req.Request) } }
// ServeHTTP serves a series of JSON encoded events via straight HTTP with // Transfer-Encoding: chunked. func (self *WatchServer) ServeHTTP(w http.ResponseWriter, req *http.Request) { loggedW := httplog.LogOf(req, w) w = httplog.Unlogged(w) timeoutCh, cleanup := self.t.TimeoutCh() defer cleanup() defer self.watching.Stop() cn, ok := w.(http.CloseNotifier) if !ok { loggedW.Addf("unable to get CloseNotifier") http.NotFound(w, req) return } flusher, ok := w.(http.Flusher) if !ok { loggedW.Addf("unable to get Flusher") http.NotFound(w, req) return } w.Header().Set("Transfer-Encoding", "chunked") w.WriteHeader(http.StatusOK) flusher.Flush() encoder := watchjson.NewEncoder(w, self.codec) for { select { case <-cn.CloseNotify(): return case <-timeoutCh: return case event, ok := <-self.watching.ResultChan(): if !ok { // End of results. return } self.fixup(event.Object) if err := encoder.Encode(&event); err != nil { // Client disconnect. return } flusher.Flush() } } }