func (pr *consulPipeRouter) privateAPI() { router := mux.NewRouter() router.Methods("GET"). MatcherFunc(app.URLMatcher("/private/api/pipe/{key}")). HandlerFunc(func(w http.ResponseWriter, r *http.Request) { key := mux.Vars(r)["key"] log.Infof("%s: Server bridge connection started", key) defer log.Infof("%s: Server bridge connection stopped", key) pipe := pr.getPipe(key) if pipe == nil { log.Errorf("%s: Server bridge connection; Unknown pipe!", key) w.WriteHeader(http.StatusNotFound) return } conn, err := xfer.Upgrade(w, r, nil) if err != nil { log.Errorf("%s: Server bridge connection; Error upgrading to websocket: %v", key, err) return } defer conn.Close() end, _ := pipe.Ends() if err := pipe.CopyToWebsocket(end, conn); err != nil && !xfer.IsExpectedWSCloseError(err) { log.Errorf("%s: Server bridge connection; Error copying pipe to websocket: %v", key, err) } }) log.Infof("Serving private API on endpoint %s.", pr.advertise) log.Infof("Private API terminated: %v", http.ListenAndServe(pr.advertise, router)) }
// handleProbeWS accepts websocket connections from the probe and registers // them in the control router, such that HandleControl calls can find them. func handleProbeWS(cr ControlRouter) CtxHandlerFunc { return func(ctx context.Context, w http.ResponseWriter, r *http.Request) { probeID := r.Header.Get(xfer.ScopeProbeIDHeader) if probeID == "" { respondWith(w, http.StatusBadRequest, xfer.ScopeProbeIDHeader) return } conn, err := xfer.Upgrade(w, r, nil) if err != nil { log.Printf("Error upgrading control websocket: %v", err) return } defer conn.Close() codec := xfer.NewJSONWebsocketCodec(conn) client := rpc.NewClientWithCodec(codec) defer client.Close() id, err := cr.Register(ctx, probeID, func(req xfer.Request) xfer.Response { var res xfer.Response if err := client.Call("control.Handle", req, &res); err != nil { return xfer.ResponseError(err) } return res }) if err != nil { respondWith(w, http.StatusBadRequest, err.Error()) return } defer cr.Deregister(ctx, probeID, id) if err := codec.WaitForReadError(); err != nil && err != io.EOF && !xfer.IsExpectedWSCloseError(err) { log.Errorf("Error on websocket: %v", err) } } }
func handlePipeWs(pr PipeRouter, end End) CtxHandlerFunc { return func(ctx context.Context, w http.ResponseWriter, r *http.Request) { id := mux.Vars(r)["pipeID"] pipe, endIO, err := pr.Get(ctx, id, end) if err != nil { log.Errorf("Error getting pipe %s: %v", id, err) http.NotFound(w, r) return } defer pr.Release(ctx, id, end) conn, err := xfer.Upgrade(w, r, nil) if err != nil { log.Errorf("Error upgrading pipe %s (%d) websocket: %v", id, end, err) return } defer conn.Close() log.Infof("Success got pipe %s:%s", id, end) if err := pipe.CopyToWebsocket(endIO, conn); err != nil && !xfer.IsExpectedWSCloseError(err) { log.Printf("Error copying to pipe %s (%d) websocket: %v", id, end, err) } } }
// Websocket for the full topology. func handleWebsocket( ctx context.Context, rep Reporter, w http.ResponseWriter, r *http.Request, ) { if err := r.ParseForm(); err != nil { respondWith(w, http.StatusInternalServerError, err.Error()) return } loop := websocketLoop if t := r.Form.Get("t"); t != "" { var err error if loop, err = time.ParseDuration(t); err != nil { respondWith(w, http.StatusBadRequest, t) return } } conn, err := xfer.Upgrade(w, r, nil) if err != nil { // log.Info("Upgrade:", err) return } defer conn.Close() quit := make(chan struct{}) go func(c xfer.Websocket) { for { // just discard everything the browser sends if _, _, err := c.ReadMessage(); err != nil { if !xfer.IsExpectedWSCloseError(err) { log.Println("err:", err) } close(quit) break } } }(conn) var ( previousTopo detailed.NodeSummaries tick = time.Tick(loop) wait = make(chan struct{}, 1) topologyID = mux.Vars(r)["topology"] ) rep.WaitOn(ctx, wait) defer rep.UnWait(ctx, wait) for { report, err := rep.Report(ctx) if err != nil { log.Errorf("Error generating report: %v", err) return } renderer, decorator, err := topologyRegistry.rendererForTopology(topologyID, r.Form, report) if err != nil { log.Errorf("Error generating report: %v", err) return } newTopo := detailed.Summaries(report, renderer.Render(report, decorator)) diff := detailed.TopoDiff(previousTopo, newTopo) previousTopo = newTopo if err := conn.WriteJSON(diff); err != nil { if !xfer.IsExpectedWSCloseError(err) { log.Errorf("cannot serialize topology diff: %s", err) } return } select { case <-wait: case <-tick: case <-quit: return } } }