func (r *Runner) getBuildLog(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { id := ps.ByName("build") b := &Build{} if err := r.db.View(func(tx *bolt.Tx) error { v := tx.Bucket(dbBucket).Get([]byte(id)) if err := json.Unmarshal(v, b); err != nil { return fmt.Errorf("could not decode build %s: %s", v, err) } return nil }); err != nil { http.Error(w, err.Error(), 500) return } // if it's a V1 build, redirect to the log in S3 if b.Version == BuildVersion1 { http.Redirect(w, req, b.LogURL, http.StatusMovedPermanently) return } // if it's a browser, serve the build-log.html template if strings.Contains(req.Header.Get("Accept"), "text/html") { tpl, err := template.ParseFiles(path.Join(args.AssetsDir, "build-log.html")) if err != nil { http.Error(w, err.Error(), 500) return } w.Header().Set("Content-Type", "text/html; charset=utf-8") if err := tpl.Execute(w, b); err != nil { log.Printf("error executing build-log template: %s", err) } return } // serve the build log as either an SSE or plain text stream ch := make(chan string) stream, err := getBuildLogStream(b, ch) if err != nil { http.Error(w, err.Error(), 500) return } if cn, ok := w.(http.CloseNotifier); ok { go func() { <-cn.CloseNotify() stream.Close() }() } else { defer stream.Close() } if strings.Contains(req.Header.Get("Accept"), "text/event-stream") { sse.ServeStream(w, ch, nil) } else { servePlainStream(w, ch) } if err := stream.Err(); err != nil { log.Println("error serving build log stream:", err) } }
func (api *httpAPI) Events(w http.ResponseWriter, req *http.Request, params httprouter.Params) { eventChan := make(chan *Event) lastEventID := req.Header.Get("Last-Event-ID") sub := api.Installer.Subscribe(eventChan, lastEventID) defer api.Installer.Unsubscribe(sub) sse.ServeStream(w, eventChan, api.logger) }
func (api *API) StreamEvents(ctx context.Context, w http.ResponseWriter, req *http.Request) { log, _ := ctxhelper.LoggerFromContext(ctx) httpListener := api.router.ListenerFor("http") tcpListener := api.router.ListenerFor("tcp") httpEvents := make(chan *router.Event) tcpEvents := make(chan *router.Event) sseEvents := make(chan *router.StreamEvent) go httpListener.Watch(httpEvents) go tcpListener.Watch(tcpEvents) defer httpListener.Unwatch(httpEvents) defer tcpListener.Unwatch(tcpEvents) sendEvents := func(events chan *router.Event) { for { e, ok := <-events if !ok { return } sseEvents <- &router.StreamEvent{ Event: e.Event, Route: e.Route, Error: e.Error, } } } go sendEvents(httpEvents) go sendEvents(tcpEvents) sse.ServeStream(w, sseEvents, log) }
func streamEvents(params martini.Params, rtr *Router, w http.ResponseWriter) { httpListener := listenerFor(rtr, "http") tcpListener := listenerFor(rtr, "tcp") log := log15.New("component", "router") httpEvents := make(chan *router.Event) tcpEvents := make(chan *router.Event) sseEvents := make(chan *router.StreamEvent) go httpListener.Watch(httpEvents) go tcpListener.Watch(tcpEvents) defer httpListener.Unwatch(httpEvents) defer tcpListener.Unwatch(tcpEvents) sendEvents := func(events chan *router.Event) { for { e, ok := <-events if !ok { return } sseEvents <- &router.StreamEvent{ Event: e.Event, Route: e.Route, Error: e.Error, } } } go sendEvents(httpEvents) go sendEvents(tcpEvents) sse.ServeStream(w, sseEvents, log) }
func (c *controllerAPI) streamFormations(ctx context.Context, w http.ResponseWriter, req *http.Request) { ch := make(chan *ct.ExpandedFormation) since, err := time.Parse(time.RFC3339, req.FormValue("since")) if err != nil { respondWithError(w, err) return } sub, err := c.formationRepo.Subscribe(ch, since, nil) if err != nil { respondWithError(w, err) return } defer c.formationRepo.Unsubscribe(sub) l, _ := ctxhelper.LoggerFromContext(ctx) sse.ServeStream(w, ch, l) }
func (api *API) StreamEvents(ctx context.Context, w http.ResponseWriter, req *http.Request) { log, _ := ctxhelper.LoggerFromContext(ctx) httpListener := api.router.ListenerFor("http") tcpListener := api.router.ListenerFor("tcp") httpEvents := make(chan *router.Event) tcpEvents := make(chan *router.Event) sseEvents := make(chan *router.StreamEvent) go httpListener.Watch(httpEvents, true) go tcpListener.Watch(tcpEvents, true) defer httpListener.Unwatch(httpEvents) defer tcpListener.Unwatch(tcpEvents) reqTypes := strings.Split(req.URL.Query().Get("types"), ",") eventTypes := make(map[router.EventType]struct{}, len(reqTypes)) for _, typ := range reqTypes { eventTypes[router.EventType(typ)] = struct{}{} } sendEvents := func(events chan *router.Event) { for { e, ok := <-events if !ok { return } if _, ok := eventTypes[e.Event]; !ok { continue } sseEvents <- &router.StreamEvent{ Event: e.Event, Route: e.Route, Backend: e.Backend, Error: e.Error, } } } go sendEvents(httpEvents) go sendEvents(tcpEvents) sse.ServeStream(w, sseEvents, log) }
func (h *Host) streamEvents(id string, w http.ResponseWriter) error { ch := h.state.AddListener(id) defer h.state.RemoveListener(id, ch) sse.ServeStream(w, ch, nil) return nil }