github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/pkg/api/handlers/compat/events.go (about)

     1  package compat
     2  
     3  import (
     4  	"fmt"
     5  	"net/http"
     6  
     7  	"github.com/containers/libpod/libpod"
     8  	"github.com/containers/libpod/libpod/events"
     9  	"github.com/containers/libpod/pkg/api/handlers"
    10  	"github.com/containers/libpod/pkg/api/handlers/utils"
    11  	"github.com/gorilla/schema"
    12  	jsoniter "github.com/json-iterator/go"
    13  	"github.com/pkg/errors"
    14  	"github.com/sirupsen/logrus"
    15  )
    16  
    17  func GetEvents(w http.ResponseWriter, r *http.Request) {
    18  	var (
    19  		fromStart   bool
    20  		eventsError error
    21  		decoder     = r.Context().Value("decoder").(*schema.Decoder)
    22  		runtime     = r.Context().Value("runtime").(*libpod.Runtime)
    23  	)
    24  
    25  	query := struct {
    26  		Since   string              `schema:"since"`
    27  		Until   string              `schema:"until"`
    28  		Filters map[string][]string `schema:"filters"`
    29  	}{}
    30  	if err := decoder.Decode(&query, r.URL.Query()); err != nil {
    31  		utils.Error(w, "Failed to parse parameters", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String()))
    32  	}
    33  
    34  	var libpodFilters = []string{}
    35  	if _, found := r.URL.Query()["filters"]; found {
    36  		for k, v := range query.Filters {
    37  			libpodFilters = append(libpodFilters, fmt.Sprintf("%s=%s", k, v[0]))
    38  		}
    39  	}
    40  
    41  	if len(query.Since) > 0 || len(query.Until) > 0 {
    42  		fromStart = true
    43  	}
    44  	eventChannel := make(chan *events.Event)
    45  	go func() {
    46  		readOpts := events.ReadOptions{FromStart: fromStart, Stream: true, Filters: libpodFilters, EventChannel: eventChannel, Since: query.Since, Until: query.Until}
    47  		eventsError = runtime.Events(readOpts)
    48  	}()
    49  	if eventsError != nil {
    50  		utils.InternalServerError(w, eventsError)
    51  		close(eventChannel)
    52  		return
    53  	}
    54  
    55  	// If client disappears we need to stop listening for events
    56  	go func(done <-chan struct{}) {
    57  		<-done
    58  		close(eventChannel)
    59  	}(r.Context().Done())
    60  
    61  	// Headers need to be written out before turning Writer() over to json encoder
    62  	w.Header().Set("Content-Type", "application/json")
    63  	w.WriteHeader(http.StatusOK)
    64  	if flusher, ok := w.(http.Flusher); ok {
    65  		flusher.Flush()
    66  	}
    67  
    68  	json := jsoniter.ConfigCompatibleWithStandardLibrary
    69  	coder := json.NewEncoder(w)
    70  	coder.SetEscapeHTML(true)
    71  
    72  	for event := range eventChannel {
    73  		e := handlers.EventToApiEvent(event)
    74  		if err := coder.Encode(e); err != nil {
    75  			logrus.Errorf("unable to write json: %q", err)
    76  		}
    77  		if flusher, ok := w.(http.Flusher); ok {
    78  			flusher.Flush()
    79  		}
    80  	}
    81  }