package api import ( "log" "net/http" _ "gitea.ceperka.net/rosti/lobby2/docs" // This line is necessary for swag to find your docs! "gitea.ceperka.net/rosti/lobby2/nodes" "github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware" echoSwagger "github.com/swaggo/echo-swagger" ) // @title Lobby2 API // @version 2.0 // @description API of Lobby 2 project that helps to discover and connect to other nodes and their services. // @BasePath / // @securityDefinitions.apikey Bearer // @in header // @name Authorization type API struct { listen string token string np *nodes.NodesProcessor e *echo.Echo } func NewAPI(np *nodes.NodesProcessor, listen string, token string) *API { return &API{ listen: listen, token: token, np: np, } } func (a *API) Run() error { if a.token == "" { log.Fatalln("TOKEN is required") } a.e = echo.New() a.e.Use(middleware.Logger()) a.e.Use(tokenMiddlware(a.token)) a.e.GET("/", func(c echo.Context) error { return c.Redirect(http.StatusTemporaryRedirect, "/swagger/index.html") }) a.e.GET("/swagger/*", echoSwagger.WrapHandler) a.e.GET("/nodes", a.listHandler) a.e.GET("/nodes/:hostname", a.getHandler) a.e.POST("/nodes/:hostname", a.refreshHandler) a.e.GET("/prometheus/:service", a.prometheusHandler) // Start the server in a goroutine so that it doesn't block the signal listening return a.e.Start(a.listen) } // @Summary List of nodes // @Description List of all discovered nodes and their labels. // @Produce application/json // @Success 200 {object} nodes.Nodes "List of nodes" // @Failure 401 {object} Message "Forbidden access" // @Security Bearer // @Router /nodes [get] func (a *API) listHandler(c echo.Context) error { return c.JSON(http.StatusOK, a.np.List()) } // @Summary Get node // @Description Return one nodes based on given hostname // @Produce application/json // @Param hostname path string true "Node hostname" // @Success 200 {array} nodes.Node "Node details" // @Failure 401 {object} Message "Forbidden access" // @Security Bearer // @Router /nodes/{hostname} [get] func (a *API) getHandler(c echo.Context) error { hostname := c.Param("hostname") node, ok := a.np.Get(hostname) if !ok { return echo.NewHTTPError(http.StatusNotFound, "node not found") } return c.JSON(http.StatusOK, node) } // @Summary Refresh node // @Description Send new data or update existing data about a node // @Produce application/json // @Param hostname path string true "Node hostname" // @Param labels body nodes.Labels true "Node labels" // @Param kv body nodes.KV true "Key-value" // @Success 200 {array} nodes.Node "Node details" // @Failure 401 {object} Message "Forbidden access" // @Security Bearer // @Router /nodes/{hostname} [post] func (a *API) refreshHandler(c echo.Context) error { hostname := c.Param("hostname") params := params{} err := c.Bind(¶ms) if err != nil { return c.JSON(http.StatusBadRequest, Message{Message: err.Error()}) } a.np.Refresh(hostname, params.Labels, params.KV) return c.NoContent(http.StatusNoContent) } // @Summary Prometheus service discovery // @Description Return one nodes based on given hostname // @Produce application/json // @Success 200 {array} []prometheusDiscovery "Node details" // @Failure 401 {object} Message "Forbidden access" // @Security Bearer // @Router /prometheus/{service} [get] func (a *API) prometheusHandler(c echo.Context) error { ss := c.Param("service") pds := nodes.GetPrometheusSD(a.np, ss) return c.JSONPretty(http.StatusOK, pds, " ") }