diff --git a/.github/workflows/pr-build.yaml b/.github/workflows/pr-build.yaml index 0ca06208..8b511c8a 100644 --- a/.github/workflows/pr-build.yaml +++ b/.github/workflows/pr-build.yaml @@ -2,19 +2,19 @@ name: Go Build on: push: - branches: [ main, development, feat/* ] + branches: [ main, rc/*, feat/* ] pull_request: - branches: [ main, development, feat/* ] + branches: [ main, rc/*, feat/* ] jobs: build: name: Build runs-on: ubuntu-latest steps: - - name: Set up Go 1.x + - name: Set up Go 1.17.6 uses: actions/setup-go@v2 with: - go-version: ^1.15.6 + go-version: 1.17.6 id: go - name: Check out code diff --git a/.github/workflows/pr-tests.yaml b/.github/workflows/pr-tests.yaml index ad258d9c..7b1a9d17 100644 --- a/.github/workflows/pr-tests.yaml +++ b/.github/workflows/pr-tests.yaml @@ -2,19 +2,19 @@ name: Tests on: push: - branches: [ main, development, feat/* ] + branches: [ main, rc/*, feat/* ] pull_request: - branches: [ main, development, feat/* ] + branches: [ main, rc/*, feat/* ] jobs: test: name: Unit runs-on: ubuntu-latest steps: - - name: Set up Go 1.x + - name: Set up Go 1.17.6 uses: actions/setup-go@v2 with: - go-version: ^1.15.6 + go-version: 1.17.6 id: go - name: Check out code diff --git a/README.md b/README.md index 3eedd819..84790b8b 100644 --- a/README.md +++ b/README.md @@ -73,30 +73,25 @@ Before launching the proxy (notifier) service, it has to be configured so that i correct environment variables. The supported config variables are: -- `Port`: the port on which the http server listens on. Should be the same - as the port in the `ProxyUrl` described above. -- `Username`: the username used to authorize an observer. Can be left empty for `UseAuthorization = false`. -- `Password`: the password used to authorize an observer. Can be left empty for `UseAuthorization = false`. +- `Host`: the host and port on which the http server listens on. Should be the same port + as the one specified in the `ProxyUrl` described above. +- `Username`: the username used to authorize an observer. Can be left empty for `UseAuthorization = false` on observer connector. +- `Password`: the password used to authorize an observer. Can be left empty for `UseAuthorization = false` on observer connector. - `CheckDuplicates`: if true, it will check (based on a locker service using redis) if the event have been already pushed to clients - -The [config](https://github.com/multiversx/mx-chain-notifier-go/blob/main/cmd/notifier/config/config.toml) file: +If observer connector is set to use BasicAuth with `UseAuthorization = true`, `Username` and `Password` has to be +set here on events notifier, and `Auth` flag has to be enabled in +[`api.toml`](https://github.com/multiversx/mx-chain-notifier-go/blob/main/cmd/notifier/config/api.toml) config file for events path. +For example: ```toml -[ConnectorApi] - # The port on which the Hub listens for subscriptions - Port = "5000" - - # Username is the username needed to authorize an observer to push data - Username = "" - - # Password is the password needed to authorize an observer to push event data - Password = "" - - # CheckDuplicates signals if the events received from observers have been already pushed to clients - # Requires a redis instance/cluster and should be used when multiple observers push from the same shard - CheckDuplicates = true +[APIPackages.events] + Routes = [ + { Name = "/push", Open = true, Auth = true }, + { Name = "/revert", Open = true, Auth = false }, ``` +The main config file can be found [here](https://github.com/multiversx/mx-chain-notifier-go/blob/main/cmd/notifier/config/config.toml). + After the configuration file is set up, the notifier instance can be launched. diff --git a/api/gin/webServer.go b/api/gin/webServer.go index 53665552..4f3b9c9f 100644 --- a/api/gin/webServer.go +++ b/api/gin/webServer.go @@ -18,6 +18,10 @@ import ( "github.com/multiversx/mx-chain-notifier-go/config" ) +const ( + defaultRestInterface = "localhost:5000" +) + var log = logger.GetOrCreate("api/gin") const ( @@ -29,9 +33,7 @@ const ( type ArgsWebServerHandler struct { Facade shared.FacadeHandler PayloadHandler websocket.PayloadHandler - Config config.ConnectorApiConfig - Type string - ConnectorType string + Configs config.Configs } // webServer is a wrapper for gin.Engine, holding additional components @@ -40,10 +42,8 @@ type webServer struct { facade shared.FacadeHandler payloadHandler websocket.PayloadHandler httpServer shared.HTTPServerCloser - config config.ConnectorApiConfig groups map[string]shared.GroupHandler - apiType string - connectorType string + configs config.Configs wasTriggered bool cancelFunc func() } @@ -58,9 +58,7 @@ func NewWebServerHandler(args ArgsWebServerHandler) (*webServer, error) { return &webServer{ facade: args.Facade, payloadHandler: args.PayloadHandler, - config: args.Config, - apiType: args.Type, - connectorType: args.ConnectorType, + configs: args.Configs, groups: make(map[string]shared.GroupHandler), wasTriggered: false, }, nil @@ -70,10 +68,10 @@ func checkArgs(args ArgsWebServerHandler) error { if check.IfNil(args.Facade) { return apiErrors.ErrNilFacadeHandler } - if args.Type == "" { + if args.Configs.Flags.APIType == "" { return common.ErrInvalidAPIType } - if args.ConnectorType == "" { + if args.Configs.Flags.ConnectorType == "" { return common.ErrInvalidConnectorType } if check.IfNil(args.PayloadHandler) { @@ -83,6 +81,19 @@ func checkArgs(args ArgsWebServerHandler) error { return nil } +func (w *webServer) getWSAddr() string { + addr := w.configs.MainConfig.ConnectorApi.Host + if addr == "" { + return defaultRestInterface + } + + if !strings.Contains(addr, ":") { + return fmt.Sprintf(":%s", addr) + } + + return addr +} + // Run starts the server and the Hub as goroutines // It returns an instance of http.Server func (w *webServer) Run() error { @@ -96,11 +107,6 @@ func (w *webServer) Run() error { return nil } - port := w.config.Port - if !strings.Contains(port, ":") { - port = fmt.Sprintf(":%s", port) - } - engine := gin.Default() engine.Use(cors.Default()) @@ -111,8 +117,10 @@ func (w *webServer) Run() error { w.registerRoutes(engine) + addr := w.getWSAddr() + server := &http.Server{ - Addr: port, + Addr: addr, Handler: engine, } @@ -136,7 +144,7 @@ func (w *webServer) createGroups() error { PayloadHandler: w.payloadHandler, } - if w.connectorType == common.HTTPConnectorType { + if w.configs.Flags.ConnectorType == common.HTTPConnectorType { eventsGroup, err := groups.NewEventsGroup(eventsGroupArgs) if err != nil { return err @@ -144,7 +152,13 @@ func (w *webServer) createGroups() error { groupsMap[eventsGroupID] = eventsGroup } - if w.apiType == common.WSAPIType { + statusGroup, err := groups.NewStatusGroup(w.facade) + if err != nil { + return err + } + groupsMap["status"] = statusGroup + + if w.configs.Flags.APIType == common.WSAPIType { hubHandler, err := groups.NewHubGroup(w.facade) if err != nil { return err @@ -160,8 +174,10 @@ func (w *webServer) createGroups() error { func (w *webServer) registerRoutes(ginEngine *gin.Engine) { for groupName, groupHandler := range w.groups { log.Info("registering API group", "group name", groupName) - ginGroup := ginEngine.Group(fmt.Sprintf("/%s", groupName)).Use(groupHandler.GetAdditionalMiddlewares()...) - groupHandler.RegisterRoutes(ginGroup) + + ginGroup := ginEngine.Group(fmt.Sprintf("/%s", groupName)) + + groupHandler.RegisterRoutes(ginGroup, w.configs.ApiRoutesConfig) } } diff --git a/api/gin/webServer_test.go b/api/gin/webServer_test.go index 93d245c3..b38b69a0 100644 --- a/api/gin/webServer_test.go +++ b/api/gin/webServer_test.go @@ -17,11 +17,17 @@ func createMockArgsWebServerHandler() gin.ArgsWebServerHandler { return gin.ArgsWebServerHandler{ Facade: &mocks.FacadeStub{}, PayloadHandler: &testscommon.PayloadHandlerStub{}, - Config: config.ConnectorApiConfig{ - Port: "8080", + Configs: config.Configs{ + MainConfig: config.MainConfig{ + ConnectorApi: config.ConnectorApiConfig{ + Host: "8080", + }, + }, + Flags: config.FlagsConfig{ + APIType: "notifier", + ConnectorType: "http", + }, }, - Type: "notifier", - ConnectorType: common.HTTPConnectorType, } } @@ -54,7 +60,7 @@ func TestNewWebServerHandler(t *testing.T) { t.Parallel() args := createMockArgsWebServerHandler() - args.Type = "" + args.Configs.Flags.APIType = "" ws, err := gin.NewWebServerHandler(args) require.True(t, check.IfNil(ws)) @@ -65,7 +71,7 @@ func TestNewWebServerHandler(t *testing.T) { t.Parallel() args := createMockArgsWebServerHandler() - args.ConnectorType = "" + args.Configs.Flags.ConnectorType = "" ws, err := gin.NewWebServerHandler(args) require.True(t, check.IfNil(ws)) diff --git a/api/groups/baseGroup.go b/api/groups/baseGroup.go index 38225883..fa7921c1 100644 --- a/api/groups/baseGroup.go +++ b/api/groups/baseGroup.go @@ -1,22 +1,86 @@ package groups import ( + "strings" + + "github.com/gin-gonic/gin" logger "github.com/multiversx/mx-chain-logger-go" "github.com/multiversx/mx-chain-notifier-go/api/shared" - "github.com/gin-gonic/gin" + "github.com/multiversx/mx-chain-notifier-go/config" ) var log = logger.GetOrCreate("api/groups") type baseGroup struct { - endpoints []*shared.EndpointHandlerData + endpoints []*shared.EndpointHandlerData + additionalMiddlewares []gin.HandlerFunc + authMiddleware gin.HandlerFunc +} + +func newBaseGroup() *baseGroup { + return &baseGroup{ + additionalMiddlewares: make([]gin.HandlerFunc, 0), + authMiddleware: func(ctx *gin.Context) {}, + } } // RegisterRoutes will register all the endpoints to the given web server func (bg *baseGroup) RegisterRoutes( - ws gin.IRoutes, + ws *gin.RouterGroup, + apiConfig config.APIRoutesConfig, ) { for _, handlerData := range bg.endpoints { - ws.Handle(handlerData.Method, handlerData.Path, handlerData.Handler) + isOpen, isAuthEnabled := getEndpointStatus(ws, handlerData.Path, apiConfig) + if !isOpen { + log.Debug("endpoint is closed", "path", handlerData.Path) + continue + } + + handlers := make([]gin.HandlerFunc, 0) + + if isAuthEnabled { + handlers = append(handlers, bg.GetAuthMiddleware()) + } + + handlers = append(handlers, bg.GetAdditionalMiddlewares()...) + handlers = append(handlers, handlerData.Handler) + + ws.Handle(handlerData.Method, handlerData.Path, handlers...) + } +} + +// GetAdditionalMiddlewares returns additional middlewares +func (bg *baseGroup) GetAdditionalMiddlewares() []gin.HandlerFunc { + return bg.additionalMiddlewares +} + +// GetAuthMiddleware returns auth middleware +func (bg *baseGroup) GetAuthMiddleware() gin.HandlerFunc { + return bg.authMiddleware +} + +func getEndpointStatus( + ws *gin.RouterGroup, + path string, + apiConfig config.APIRoutesConfig, +) (bool, bool) { + basePath := ws.BasePath() + + // ws.BasePath will return paths like /group + // so we need the last token after splitting by / + splitPath := strings.Split(basePath, "/") + basePath = splitPath[len(splitPath)-1] + + group, ok := apiConfig.APIPackages[basePath] + if !ok { + return false, false } + + for _, route := range group.Routes { + if route.Name == path { + return route.Open, route.Auth + } + } + + return false, false } diff --git a/api/groups/common_test.go b/api/groups/common_test.go index 8ca06484..65c17b04 100644 --- a/api/groups/common_test.go +++ b/api/groups/common_test.go @@ -5,16 +5,17 @@ import ( "fmt" "io" - "github.com/multiversx/mx-chain-notifier-go/api/shared" "github.com/gin-contrib/cors" "github.com/gin-gonic/gin" + "github.com/multiversx/mx-chain-notifier-go/api/shared" + "github.com/multiversx/mx-chain-notifier-go/config" ) -func startWebServer(group shared.GroupHandler, path string) *gin.Engine { +func startWebServer(group shared.GroupHandler, path string, apiConfig config.APIRoutesConfig) *gin.Engine { ws := gin.New() ws.Use(cors.Default()) routes := ws.Group(path) - group.RegisterRoutes(routes) + group.RegisterRoutes(routes, apiConfig) return ws } diff --git a/api/groups/eventsGroup.go b/api/groups/eventsGroup.go index f36baccb..361f1551 100644 --- a/api/groups/eventsGroup.go +++ b/api/groups/eventsGroup.go @@ -26,9 +26,8 @@ type ArgsEventsGroup struct { type eventsGroup struct { *baseGroup - facade EventsFacadeHandler - payloadHandler websocket.PayloadHandler - additionalMiddlewares []gin.HandlerFunc + facade EventsFacadeHandler + payloadHandler websocket.PayloadHandler } // NewEventsGroup registers handlers for the /events group @@ -39,10 +38,9 @@ func NewEventsGroup(args ArgsEventsGroup) (*eventsGroup, error) { } h := &eventsGroup{ - baseGroup: &baseGroup{}, - facade: args.Facade, - payloadHandler: args.PayloadHandler, - additionalMiddlewares: make([]gin.HandlerFunc, 0), + baseGroup: newBaseGroup(), + facade: args.Facade, + payloadHandler: args.PayloadHandler, } h.createMiddlewares() @@ -81,11 +79,6 @@ func checkEventsGroupArgs(args ArgsEventsGroup) error { return nil } -// GetAdditionalMiddlewares return additional middlewares for this group -func (h *eventsGroup) GetAdditionalMiddlewares() []gin.HandlerFunc { - return h.additionalMiddlewares -} - func (h *eventsGroup) pushEvents(c *gin.Context) { pushEventsRawData, err := c.GetRawData() if err != nil { @@ -135,18 +128,14 @@ func (h *eventsGroup) finalizedEvents(c *gin.Context) { } func (h *eventsGroup) createMiddlewares() { - var middleware []gin.HandlerFunc - user, pass := h.facade.GetConnectorUserAndPass() if user != "" && pass != "" { basicAuth := gin.BasicAuth(gin.Accounts{ user: pass, }) - middleware = append(middleware, basicAuth) + h.authMiddleware = basicAuth } - - h.additionalMiddlewares = middleware } // IsInterfaceNil returns true if there is no value under the interface diff --git a/api/groups/eventsGroup_test.go b/api/groups/eventsGroup_test.go index 47cfd7cb..f79829e3 100644 --- a/api/groups/eventsGroup_test.go +++ b/api/groups/eventsGroup_test.go @@ -17,6 +17,7 @@ import ( "github.com/multiversx/mx-chain-core-go/data/transaction" apiErrors "github.com/multiversx/mx-chain-notifier-go/api/errors" "github.com/multiversx/mx-chain-notifier-go/api/groups" + "github.com/multiversx/mx-chain-notifier-go/config" "github.com/multiversx/mx-chain-notifier-go/data" "github.com/multiversx/mx-chain-notifier-go/mocks" "github.com/stretchr/testify/assert" @@ -68,14 +69,40 @@ func TestNewEventsGroup(t *testing.T) { eg, err := groups.NewEventsGroup(args) require.Nil(t, err) - require.Equal(t, 1, len(eg.GetAdditionalMiddlewares())) - + require.NotNil(t, eg.GetAuthMiddleware()) }) } func TestEventsGroup_PushEvents(t *testing.T) { t.Parallel() + t.Run("invalid data, bad request", func(t *testing.T) { + t.Parallel() + + args := createMockEventsGroupArgs() + wasCalled := false + args.PayloadHandler = &testscommon.PayloadHandlerStub{ + ProcessPayloadCalled: func(payload []byte, topic string) error { + wasCalled = true + return errors.New("expected err") + }, + } + + eg, err := groups.NewEventsGroup(args) + require.Nil(t, err) + + ws := startWebServer(eg, eventsPath, getEventsRoutesConfig()) + + req, _ := http.NewRequest("POST", "/events/push", bytes.NewBuffer([]byte("invalid data"))) + req.Header.Set("Content-Type", "application/json") + resp := httptest.NewRecorder() + + ws.ServeHTTP(resp, req) + + assert.Equal(t, http.StatusBadRequest, resp.Code) + assert.True(t, wasCalled) + }) + t.Run("facade error, will try push events v2, should fail", func(t *testing.T) { t.Parallel() @@ -111,7 +138,7 @@ func TestEventsGroup_PushEvents(t *testing.T) { eg, err := groups.NewEventsGroup(args) require.Nil(t, err) - ws := startWebServer(eg, eventsPath) + ws := startWebServer(eg, eventsPath, getEventsRoutesConfig()) req, _ := http.NewRequest("POST", "/events/push", bytes.NewBuffer(jsonBytes)) req.Header.Set("Content-Type", "application/json") @@ -190,7 +217,7 @@ func TestEventsGroup_PushEvents(t *testing.T) { eg, err := groups.NewEventsGroup(args) require.Nil(t, err) - ws := startWebServer(eg, eventsPath) + ws := startWebServer(eg, eventsPath, getEventsRoutesConfig()) req, _ := http.NewRequest("POST", "/events/push", bytes.NewBuffer(jsonBytes)) req.Header.Set("Content-Type", "application/json") @@ -222,7 +249,7 @@ func TestEventsGroup_RevertEvents(t *testing.T) { eg, err := groups.NewEventsGroup(args) require.Nil(t, err) - ws := startWebServer(eg, eventsPath) + ws := startWebServer(eg, eventsPath, getEventsRoutesConfig()) req, _ := http.NewRequest("POST", "/events/revert", bytes.NewBuffer([]byte("invalid data"))) req.Header.Set("Content-Type", "application/json") @@ -263,7 +290,7 @@ func TestEventsGroup_RevertEvents(t *testing.T) { eg, err := groups.NewEventsGroup(args) require.Nil(t, err) - ws := startWebServer(eg, eventsPath) + ws := startWebServer(eg, eventsPath, getEventsRoutesConfig()) req, _ := http.NewRequest("POST", "/events/revert", bytes.NewBuffer(jsonBytes)) req.Header.Set("Content-Type", "application/json") @@ -292,7 +319,7 @@ func TestEventsGroup_FinalizedEvents(t *testing.T) { eg, err := groups.NewEventsGroup(args) require.Nil(t, err) - ws := startWebServer(eg, eventsPath) + ws := startWebServer(eg, eventsPath, getEventsRoutesConfig()) req, _ := http.NewRequest("POST", "/events/finalized", bytes.NewBuffer([]byte("invalid data"))) req.Header.Set("Content-Type", "application/json") @@ -331,7 +358,7 @@ func TestEventsGroup_FinalizedEvents(t *testing.T) { eg, err := groups.NewEventsGroup(args) require.Nil(t, err) - ws := startWebServer(eg, eventsPath) + ws := startWebServer(eg, eventsPath, getEventsRoutesConfig()) req, _ := http.NewRequest("POST", "/events/finalized", bytes.NewBuffer(jsonBytes)) req.Header.Set("Content-Type", "application/json") @@ -343,3 +370,17 @@ func TestEventsGroup_FinalizedEvents(t *testing.T) { assert.Equal(t, http.StatusOK, resp.Code) }) } + +func getEventsRoutesConfig() config.APIRoutesConfig { + return config.APIRoutesConfig{ + APIPackages: map[string]config.APIPackageConfig{ + "events": { + Routes: []config.RouteConfig{ + {Name: "/push", Open: true}, + {Name: "/revert", Open: true}, + {Name: "/finalized", Open: true}, + }, + }, + }, + } +} diff --git a/api/groups/hubGroup.go b/api/groups/hubGroup.go index afe78ef5..e8ee90ac 100644 --- a/api/groups/hubGroup.go +++ b/api/groups/hubGroup.go @@ -4,10 +4,10 @@ import ( "fmt" "net/http" + "github.com/gin-gonic/gin" "github.com/multiversx/mx-chain-core-go/core/check" "github.com/multiversx/mx-chain-notifier-go/api/errors" "github.com/multiversx/mx-chain-notifier-go/api/shared" - "github.com/gin-gonic/gin" ) const ( @@ -16,8 +16,7 @@ const ( type hubGroup struct { *baseGroup - facade HubFacadeHandler - additionalMiddlewares []gin.HandlerFunc + facade HubFacadeHandler } // NewHubGroup registers handlers for the /hub group @@ -28,9 +27,8 @@ func NewHubGroup(facade HubFacadeHandler) (*hubGroup, error) { } h := &hubGroup{ - baseGroup: &baseGroup{}, - facade: facade, - additionalMiddlewares: make([]gin.HandlerFunc, 0), + facade: facade, + baseGroup: newBaseGroup(), } endpoints := []*shared.EndpointHandlerData{ @@ -46,11 +44,6 @@ func NewHubGroup(facade HubFacadeHandler) (*hubGroup, error) { return h, nil } -// GetAdditionalMiddlewares return additional middlewares for this group -func (h *hubGroup) GetAdditionalMiddlewares() []gin.HandlerFunc { - return h.additionalMiddlewares -} - func (h *hubGroup) wsHandler(c *gin.Context) { h.facade.ServeHTTP(c.Writer, c.Request) } diff --git a/api/groups/hubGroup_test.go b/api/groups/hubGroup_test.go index 24853a25..aed7a96c 100644 --- a/api/groups/hubGroup_test.go +++ b/api/groups/hubGroup_test.go @@ -9,6 +9,7 @@ import ( "github.com/multiversx/mx-chain-core-go/core/check" apiErrors "github.com/multiversx/mx-chain-notifier-go/api/errors" "github.com/multiversx/mx-chain-notifier-go/api/groups" + "github.com/multiversx/mx-chain-notifier-go/config" "github.com/multiversx/mx-chain-notifier-go/mocks" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -41,7 +42,7 @@ func TestNewHubGroup(t *testing.T) { require.NoError(t, err) require.NotNil(t, hg) - ws := startWebServer(hg, hubPath) + ws := startWebServer(hg, hubPath, getHubRoutesConfig()) req, _ := http.NewRequest("GET", "/hub/ws", nil) resp := httptest.NewRecorder() @@ -52,3 +53,15 @@ func TestNewHubGroup(t *testing.T) { assert.True(t, wasCalled) }) } + +func getHubRoutesConfig() config.APIRoutesConfig { + return config.APIRoutesConfig{ + APIPackages: map[string]config.APIPackageConfig{ + "hub": { + Routes: []config.RouteConfig{ + {Name: "/ws", Open: true}, + }, + }, + }, + } +} diff --git a/api/groups/statusGroup.go b/api/groups/statusGroup.go new file mode 100644 index 00000000..aeec5c31 --- /dev/null +++ b/api/groups/statusGroup.go @@ -0,0 +1,68 @@ +package groups + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/multiversx/mx-chain-core-go/core/check" + "github.com/multiversx/mx-chain-notifier-go/api/errors" + "github.com/multiversx/mx-chain-notifier-go/api/shared" +) + +const ( + metricsPath = "/metrics" + prometheusMetricsPath = "/prometheus-metrics" +) + +type statusGroup struct { + *baseGroup + facade shared.FacadeHandler +} + +// NewStatusGroup returns a new instance of status group +func NewStatusGroup(facade shared.FacadeHandler) (*statusGroup, error) { + if check.IfNil(facade) { + return nil, fmt.Errorf("%w for status group", errors.ErrNilFacadeHandler) + } + + sg := &statusGroup{ + facade: facade, + baseGroup: newBaseGroup(), + } + + endpoints := []*shared.EndpointHandlerData{ + { + Path: metricsPath, + Handler: sg.getMetrics, + Method: http.MethodGet, + }, + { + Path: prometheusMetricsPath, + Handler: sg.getPrometheusMetrics, + Method: http.MethodGet, + }, + } + sg.endpoints = endpoints + + return sg, nil +} + +// getMetrics will expose the notifier's metrics statistics in json format +func (sg *statusGroup) getMetrics(c *gin.Context) { + metricsResults := sg.facade.GetMetrics() + + shared.JSONResponse(c, http.StatusOK, gin.H{"metrics": metricsResults}, "") +} + +// getPrometheusMetrics will expose notifier's metrics in prometheus format +func (sg *statusGroup) getPrometheusMetrics(c *gin.Context) { + metricsResults := sg.facade.GetMetricsForPrometheus() + + c.String(http.StatusOK, metricsResults) +} + +// IsInterfaceNil returns true if there is no value under the interface +func (sg *statusGroup) IsInterfaceNil() bool { + return sg == nil +} diff --git a/api/groups/statusGroup_test.go b/api/groups/statusGroup_test.go new file mode 100644 index 00000000..473c6698 --- /dev/null +++ b/api/groups/statusGroup_test.go @@ -0,0 +1,129 @@ +package groups_test + +import ( + "errors" + "io/ioutil" + "net/http" + "net/http/httptest" + "testing" + + "github.com/multiversx/mx-chain-core-go/core/check" + apiErrors "github.com/multiversx/mx-chain-notifier-go/api/errors" + "github.com/multiversx/mx-chain-notifier-go/api/groups" + "github.com/multiversx/mx-chain-notifier-go/config" + "github.com/multiversx/mx-chain-notifier-go/data" + "github.com/multiversx/mx-chain-notifier-go/mocks" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +const statusPath = "/status" + +type statusMetricsResponse struct { + Data struct { + Metrics map[string]*data.EndpointMetricsResponse `json:"metrics"` + } + Error string `json:"error"` +} + +func TestNewStatusGroup(t *testing.T) { + t.Parallel() + + t.Run("nil facade should error", func(t *testing.T) { + t.Parallel() + + sg, err := groups.NewStatusGroup(nil) + + require.True(t, errors.Is(err, apiErrors.ErrNilFacadeHandler)) + require.True(t, check.IfNil(sg)) + }) + + t.Run("should work", func(t *testing.T) { + t.Parallel() + + sg, err := groups.NewStatusGroup(&mocks.FacadeStub{}) + + assert.NotNil(t, sg) + assert.Nil(t, err) + }) +} + +func TestGetMetrics_ShouldWork(t *testing.T) { + t.Parallel() + + expectedMetrics := map[string]*data.EndpointMetricsResponse{ + "/guardian/config": { + NumRequests: 5, + TotalResponseTime: 100, + }, + } + facade := &mocks.FacadeStub{ + GetMetricsCalled: func() map[string]*data.EndpointMetricsResponse { + return expectedMetrics + }, + } + + statusGroup, err := groups.NewStatusGroup(facade) + require.Nil(t, err) + + ws := startWebServer(statusGroup, statusPath, getStatusRoutesConfig()) + + req, _ := http.NewRequest("GET", "/status/metrics", nil) + resp := httptest.NewRecorder() + ws.ServeHTTP(resp, req) + + var apiResp statusMetricsResponse + loadResponse(resp.Body, &apiResp) + require.Equal(t, http.StatusOK, resp.Code) + + require.Equal(t, expectedMetrics, apiResp.Data.Metrics) +} + +func TestGetPrometheusMetrics_ShouldWork(t *testing.T) { + t.Parallel() + + expectedMetrics := `num_requests{endpoint="/guardian/config"} 37` + facade := &mocks.FacadeStub{ + GetMetricsForPrometheusCalled: func() string { + return expectedMetrics + }, + } + + statusGroup, err := groups.NewStatusGroup(facade) + require.NoError(t, err) + + ws := startWebServer(statusGroup, statusPath, getStatusRoutesConfig()) + + req, _ := http.NewRequest("GET", "/status/prometheus-metrics", nil) + resp := httptest.NewRecorder() + ws.ServeHTTP(resp, req) + + bodyBytes, err := ioutil.ReadAll(resp.Body) + require.NoError(t, err) + + require.Equal(t, http.StatusOK, resp.Code) + require.Equal(t, expectedMetrics, string(bodyBytes)) +} + +func TestStatusGroup_IsInterfaceNil(t *testing.T) { + t.Parallel() + + sg, _ := groups.NewStatusGroup(nil) + assert.True(t, sg.IsInterfaceNil()) + + sg, _ = groups.NewStatusGroup(&mocks.FacadeStub{}) + assert.False(t, sg.IsInterfaceNil()) +} + +func getStatusRoutesConfig() config.APIRoutesConfig { + return config.APIRoutesConfig{ + APIPackages: map[string]config.APIPackageConfig{ + "status": { + Routes: []config.RouteConfig{ + {Name: "/metrics", Open: true}, + {Name: "/prometheus-metrics", Open: true}, + }, + }, + }, + } +} diff --git a/api/shared/interface.go b/api/shared/interface.go index 63f9594c..84d53dbb 100644 --- a/api/shared/interface.go +++ b/api/shared/interface.go @@ -3,8 +3,9 @@ package shared import ( "net/http" - "github.com/multiversx/mx-chain-notifier-go/data" "github.com/gin-gonic/gin" + "github.com/multiversx/mx-chain-notifier-go/config" + "github.com/multiversx/mx-chain-notifier-go/data" ) // HTTPServerCloser defines the basic actions of starting and closing that a web server should be able to do @@ -16,7 +17,7 @@ type HTTPServerCloser interface { // GroupHandler defines the actions needed to be performed by an gin API group type GroupHandler interface { - RegisterRoutes(ws gin.IRoutes) + RegisterRoutes(ws *gin.RouterGroup, apiConfig config.APIRoutesConfig) GetAdditionalMiddlewares() []gin.HandlerFunc IsInterfaceNil() bool } @@ -29,6 +30,8 @@ type FacadeHandler interface { HandleFinalizedEvents(finalizedBlock data.FinalizedBlock) GetConnectorUserAndPass() (string, string) ServeHTTP(w http.ResponseWriter, r *http.Request) + GetMetrics() map[string]*data.EndpointMetricsResponse + GetMetricsForPrometheus() string IsInterfaceNil() bool } @@ -38,3 +41,9 @@ type WebServerHandler interface { Close() error IsInterfaceNil() bool } + +// MiddlewareProcessor defines a processor used internally by the web server when processing requests +type MiddlewareProcessor interface { + MiddlewareHandlerFunc() gin.HandlerFunc + IsInterfaceNil() bool +} diff --git a/cmd/notifier/config/api.toml b/cmd/notifier/config/api.toml new file mode 100644 index 00000000..3de330ff --- /dev/null +++ b/cmd/notifier/config/api.toml @@ -0,0 +1,20 @@ +# API routes configuration +[APIPackages] + +[APIPackages.events] + Routes = [ + { Name = "/push", Open = true, Auth = false }, + { Name = "/revert", Open = true, Auth = false }, + { Name = "/finalized", Open = true, Auth = false }, + ] + +[APIPackages.hub] + Routes = [ + { Name = "/ws", Open = true }, + ] + +[APIPackages.status] + Routes = [ + { Name = "/metrics", Open = true }, + { Name = "/prometheus-metrics", Open = true }, + ] diff --git a/cmd/notifier/config/config.toml b/cmd/notifier/config/config.toml index db9e7e54..23b4efcf 100644 --- a/cmd/notifier/config/config.toml +++ b/cmd/notifier/config/config.toml @@ -34,13 +34,14 @@ WithAcknowledge = true [ConnectorApi] - # The port on which the Hub listens for subscriptions - Port = "5000" + # The address on which the events notifier listens for subscriptions + # It can be specified as "localhost:5000" or only as "5000" + Host = "5000" - # Username is the username needed to authorize an observer to push data + # Username and Password needed to authorize the connector + # BasicAuth is enabled only for the endpoints with "Auth" flag enabled + # in api.toml config file Username = "" - - # Password is the password needed to authorize an observer to push event data Password = "" # CheckDuplicates signals if the events received from observers have been already pushed to clients @@ -49,13 +50,8 @@ [Redis] # The url used to connect to a pubsub server - # Note: not required for running in the notifier mode Url = "redis://localhost:6379/0" - # The pubsub channel used for publishing/subscribing - # Note: not required for running in the notifier mode - Channel = "pub-sub" - # The master name for failover client MasterName = "mymaster" diff --git a/cmd/notifier/main.go b/cmd/notifier/main.go index 3ee8bd24..f62f79a6 100644 --- a/cmd/notifier/main.go +++ b/cmd/notifier/main.go @@ -14,9 +14,10 @@ import ( ) const ( - defaultLogsPath = "logs" - logFilePrefix = "event-notifier" - logFileLifeSpanSec = 86400 + defaultLogsPath = "logs" + logFilePrefix = "event-notifier" + logFileLifeSpanSec = 86400 + defaultRestInterface = "localhost:8080" ) var ( @@ -54,6 +55,12 @@ VERSION: Value: "./config/config.toml", } + apiConfigFile = cli.StringFlag{ + Name: "api-config", + Usage: "The path for the api config", + Value: "./config/api.toml", + } + workingDirectory = cli.StringFlag{ Name: "working-directory", Usage: "This flag specifies the directory where the eventNotifier proxy will store logs.", @@ -81,6 +88,7 @@ func main() { logLevel, logSaveFile, generalConfigFile, + apiConfigFile, workingDirectory, apiType, connectorType, @@ -103,23 +111,17 @@ func main() { func startEventNotifierProxy(ctx *cli.Context) error { log.Info("starting eventNotifier proxy...") - flagsConfig, err := getFlagsConfig(ctx) + cfgs, err := readConfigs(ctx) if err != nil { return err } - fileLogging, err := initLogger(flagsConfig) + fileLogging, err := initLogger(&cfgs.Flags) if err != nil { return err } - cfg, err := config.LoadConfig(flagsConfig.GeneralConfigPath) - if err != nil { - return err - } - cfg.Flags = flagsConfig - - notifierRunner, err := notifier.NewNotifierRunner(cfg) + notifierRunner, err := notifier.NewNotifierRunner(cfgs) if err != nil { return err } @@ -139,6 +141,29 @@ func startEventNotifierProxy(ctx *cli.Context) error { return nil } +func readConfigs(ctx *cli.Context) (*config.Configs, error) { + flagsConfig, err := getFlagsConfig(ctx) + if err != nil { + return nil, err + } + + mainConfig, err := config.LoadMainConfig(flagsConfig.GeneralConfigPath) + if err != nil { + return nil, err + } + + apiConfig, err := config.LoadAPIConfig(flagsConfig.APIConfigPath) + if err != nil { + return nil, err + } + + return &config.Configs{ + MainConfig: *mainConfig, + ApiRoutesConfig: *apiConfig, + Flags: *flagsConfig, + }, nil +} + func getFlagsConfig(ctx *cli.Context) (*config.FlagsConfig, error) { flagsConfig := &config.FlagsConfig{} @@ -151,6 +176,7 @@ func getFlagsConfig(ctx *cli.Context) (*config.FlagsConfig, error) { flagsConfig.LogLevel = ctx.GlobalString(logLevel.Name) flagsConfig.SaveLogFile = ctx.GlobalBool(logSaveFile.Name) flagsConfig.GeneralConfigPath = ctx.GlobalString(generalConfigFile.Name) + flagsConfig.APIConfigPath = ctx.GlobalString(apiConfigFile.Name) flagsConfig.APIType = ctx.GlobalString(apiType.Name) flagsConfig.ConnectorType = ctx.GlobalString(connectorType.Name) diff --git a/common/errors.go b/common/errors.go index d5874154..686e6ec7 100644 --- a/common/errors.go +++ b/common/errors.go @@ -28,3 +28,6 @@ var ErrNilInternalMarshaller = errors.New("nil external marshaller provided") // ErrNilFacadeHandler signals that a nil facade handler has been provided var ErrNilFacadeHandler = errors.New("nil facade handler") + +// ErrNilStatusMetricsHandler signals that a nil status metrics handler has been provided +var ErrNilStatusMetricsHandler = errors.New("nil status metrics handler") diff --git a/common/interface.go b/common/interface.go new file mode 100644 index 00000000..b51ef853 --- /dev/null +++ b/common/interface.go @@ -0,0 +1,15 @@ +package common + +import ( + "time" + + "github.com/multiversx/mx-chain-notifier-go/data" +) + +// StatusMetricsHandler defines the behavior of a component that handles status metrics +type StatusMetricsHandler interface { + AddRequest(path string, duration time.Duration) + GetAll() map[string]*data.EndpointMetricsResponse + GetMetricsForPrometheus() string + IsInterfaceNil() bool +} diff --git a/config/config.go b/config/config.go index 65edb883..e7bedc4a 100644 --- a/config/config.go +++ b/config/config.go @@ -2,14 +2,20 @@ package config import "github.com/multiversx/mx-chain-core-go/core" -// Config defines the config setup based on main config file -type Config struct { +// Configs holds all configs +type Configs struct { + MainConfig MainConfig + ApiRoutesConfig APIRoutesConfig + Flags FlagsConfig +} + +// MainConfig defines the config setup based on main config file +type MainConfig struct { General GeneralConfig WebSocketConnector WebSocketConfig ConnectorApi ConnectorApiConfig Redis RedisConfig RabbitMQ RabbitMQConfig - Flags *FlagsConfig } // GeneralConfig maps the general config section @@ -33,16 +39,32 @@ type AddressConverterConfig struct { // ConnectorApiConfig maps the connector configuration type ConnectorApiConfig struct { - Port string + Host string Username string Password string CheckDuplicates bool } +// APIRoutesConfig holds the configuration related to Rest API routes +type APIRoutesConfig struct { + APIPackages map[string]APIPackageConfig +} + +// APIPackageConfig holds the configuration for the routes of each package +type APIPackageConfig struct { + Routes []RouteConfig +} + +// RouteConfig holds the configuration for a single route +type RouteConfig struct { + Name string + Open bool + Auth bool +} + // RedisConfig maps the redis configuration type RedisConfig struct { Url string - Channel string MasterName string SentinelUrl string ConnectionType string @@ -81,14 +103,26 @@ type FlagsConfig struct { LogLevel string SaveLogFile bool GeneralConfigPath string + APIConfigPath string WorkingDir string APIType string + RestApiInterface string ConnectorType string } -// LoadConfig return a Config instance by reading the provided toml file -func LoadConfig(filePath string) (*Config, error) { - cfg := &Config{} +// LoadMainConfig returns a MainConfig instance by reading the provided toml file +func LoadMainConfig(filePath string) (*MainConfig, error) { + cfg := &MainConfig{} + err := core.LoadTomlFile(cfg, filePath) + if err != nil { + return nil, err + } + return cfg, err +} + +// LoadAPIConfig returns a APIRoutesConfig instance by reading the provided toml file +func LoadAPIConfig(filePath string) (*APIRoutesConfig, error) { + cfg := &APIRoutesConfig{} err := core.LoadTomlFile(cfg, filePath) if err != nil { return nil, err diff --git a/data/requests.go b/data/requests.go new file mode 100644 index 00000000..d4a1c074 --- /dev/null +++ b/data/requests.go @@ -0,0 +1,11 @@ +package data + +import ( + "time" +) + +// EndpointMetricsResponse defines the response for status metrics endpoint +type EndpointMetricsResponse struct { + NumRequests uint64 `json:"num_requests"` + TotalResponseTime time.Duration `json:"total_response_time"` +} diff --git a/facade/notifierFacade.go b/facade/notifierFacade.go index bd95e4a6..8fc90954 100644 --- a/facade/notifierFacade.go +++ b/facade/notifierFacade.go @@ -5,6 +5,7 @@ import ( "github.com/multiversx/mx-chain-core-go/core/check" logger "github.com/multiversx/mx-chain-logger-go" + "github.com/multiversx/mx-chain-notifier-go/common" "github.com/multiversx/mx-chain-notifier-go/config" "github.com/multiversx/mx-chain-notifier-go/data" "github.com/multiversx/mx-chain-notifier-go/dispatcher" @@ -14,10 +15,11 @@ var log = logger.GetOrCreate("facade") // ArgsNotifierFacade defines the arguments necessary for notifierFacade creation type ArgsNotifierFacade struct { - APIConfig config.ConnectorApiConfig - EventsHandler EventsHandler - WSHandler dispatcher.WSHandler - EventsInterceptor EventsInterceptor + APIConfig config.ConnectorApiConfig + EventsHandler EventsHandler + WSHandler dispatcher.WSHandler + EventsInterceptor EventsInterceptor + StatusMetricsHandler common.StatusMetricsHandler } type notifierFacade struct { @@ -25,6 +27,7 @@ type notifierFacade struct { eventsHandler EventsHandler wsHandler dispatcher.WSHandler eventsInterceptor EventsInterceptor + statusMetrics common.StatusMetricsHandler } // NewNotifierFacade creates a new notifier facade instance @@ -39,6 +42,7 @@ func NewNotifierFacade(args ArgsNotifierFacade) (*notifierFacade, error) { config: args.APIConfig, wsHandler: args.WSHandler, eventsInterceptor: args.EventsInterceptor, + statusMetrics: args.StatusMetricsHandler, }, nil } @@ -52,6 +56,9 @@ func checkArgs(args ArgsNotifierFacade) error { if check.IfNil(args.EventsInterceptor) { return ErrNilEventsInterceptor } + if check.IfNil(args.StatusMetricsHandler) { + return common.ErrNilStatusMetricsHandler + } return nil } @@ -149,6 +156,16 @@ func (nf *notifierFacade) GetConnectorUserAndPass() (string, string) { return nf.config.Username, nf.config.Password } +// GetMetrics will return metrics in json format +func (nf *notifierFacade) GetMetrics() map[string]*data.EndpointMetricsResponse { + return nf.statusMetrics.GetAll() +} + +// GetMetricsForPrometheus will return metrics in prometheus format +func (nf *notifierFacade) GetMetricsForPrometheus() string { + return nf.statusMetrics.GetMetricsForPrometheus() +} + // IsInterfaceNil returns true if there is no value under the interface func (nf *notifierFacade) IsInterfaceNil() bool { return nf == nil diff --git a/facade/notifierFacade_test.go b/facade/notifierFacade_test.go index 8a6cfedf..42731d29 100644 --- a/facade/notifierFacade_test.go +++ b/facade/notifierFacade_test.go @@ -11,6 +11,7 @@ import ( "github.com/multiversx/mx-chain-core-go/data/outport" "github.com/multiversx/mx-chain-core-go/data/smartContractResult" "github.com/multiversx/mx-chain-core-go/data/transaction" + "github.com/multiversx/mx-chain-notifier-go/common" "github.com/multiversx/mx-chain-notifier-go/config" "github.com/multiversx/mx-chain-notifier-go/data" "github.com/multiversx/mx-chain-notifier-go/facade" @@ -21,10 +22,11 @@ import ( func createMockFacadeArgs() facade.ArgsNotifierFacade { return facade.ArgsNotifierFacade{ - EventsHandler: &mocks.EventsHandlerStub{}, - APIConfig: config.ConnectorApiConfig{}, - WSHandler: &mocks.WSHandlerStub{}, - EventsInterceptor: &mocks.EventsInterceptorStub{}, + EventsHandler: &mocks.EventsHandlerStub{}, + APIConfig: config.ConnectorApiConfig{}, + WSHandler: &mocks.WSHandlerStub{}, + EventsInterceptor: &mocks.EventsInterceptorStub{}, + StatusMetricsHandler: &mocks.StatusMetricsStub{}, } } @@ -64,6 +66,17 @@ func TestNewNotifierFacade(t *testing.T) { require.Equal(t, facade.ErrNilEventsInterceptor, err) }) + t.Run("nil status metrics handler", func(t *testing.T) { + t.Parallel() + + args := createMockFacadeArgs() + args.StatusMetricsHandler = nil + + f, err := facade.NewNotifierFacade(args) + require.True(t, check.IfNil(f)) + require.Equal(t, common.ErrNilStatusMetricsHandler, err) + }) + t.Run("should work", func(t *testing.T) { t.Parallel() diff --git a/factory/processFactory.go b/factory/processFactory.go index 64109ed6..bbf75335 100644 --- a/factory/processFactory.go +++ b/factory/processFactory.go @@ -18,11 +18,12 @@ const bech32PubkeyConverterType = "bech32" // ArgsEventsHandlerFactory defines the arguments needed for events handler creation type ArgsEventsHandlerFactory struct { - APIConfig config.ConnectorApiConfig - Locker process.LockService - MqPublisher process.Publisher - HubPublisher process.Publisher - APIType string + APIConfig config.ConnectorApiConfig + Locker process.LockService + MqPublisher process.Publisher + HubPublisher process.Publisher + APIType string + StatusMetricsHandler common.StatusMetricsHandler } // CreateEventsHandler will create an events handler processor @@ -33,9 +34,10 @@ func CreateEventsHandler(args ArgsEventsHandlerFactory) (process.EventsHandler, } argsEventsHandler := process.ArgsEventsHandler{ - Config: args.APIConfig, - Locker: args.Locker, - Publisher: publisher, + Config: args.APIConfig, + Locker: args.Locker, + Publisher: publisher, + StatusMetricsHandler: args.StatusMetricsHandler, } eventsHandler, err := process.NewEventsHandler(argsEventsHandler) if err != nil { @@ -84,7 +86,7 @@ func getPubKeyConverter(cfg config.GeneralConfig) (core.PubkeyConverter, error) } // CreatePayloadHandler will create a new instance of payload handler -func CreatePayloadHandler(cfg config.Config, facade process.EventsFacadeHandler) (websocket.PayloadHandler, error) { +func CreatePayloadHandler(cfg config.Configs, facade process.EventsFacadeHandler) (websocket.PayloadHandler, error) { headerMarshaller, err := createHeaderMarshaller(cfg) if err != nil { return nil, err @@ -98,10 +100,10 @@ func CreatePayloadHandler(cfg config.Config, facade process.EventsFacadeHandler) return createPayloadHandler(connectorMarshaller, headerMarshaller, facade) } -func createConnectorMarshaller(cfg config.Config) (marshal.Marshalizer, error) { +func createConnectorMarshaller(cfg config.Configs) (marshal.Marshalizer, error) { switch cfg.Flags.ConnectorType { case common.WSObsConnectorType: - return marshalFactory.NewMarshalizer(cfg.WebSocketConnector.DataMarshallerType) + return marshalFactory.NewMarshalizer(cfg.MainConfig.WebSocketConnector.DataMarshallerType) case common.HTTPConnectorType: return &marshal.JsonMarshalizer{}, nil default: @@ -109,12 +111,12 @@ func createConnectorMarshaller(cfg config.Config) (marshal.Marshalizer, error) { } } -func createHeaderMarshaller(cfg config.Config) (marshal.Marshalizer, error) { +func createHeaderMarshaller(cfg config.Configs) (marshal.Marshalizer, error) { switch cfg.Flags.ConnectorType { case common.WSObsConnectorType: - return marshalFactory.NewMarshalizer(cfg.WebSocketConnector.DataMarshallerType) + return marshalFactory.NewMarshalizer(cfg.MainConfig.WebSocketConnector.DataMarshallerType) case common.HTTPConnectorType: - return marshalFactory.NewMarshalizer(cfg.General.InternalMarshaller.Type) + return marshalFactory.NewMarshalizer(cfg.MainConfig.General.InternalMarshaller.Type) default: return nil, common.ErrInvalidAPIType } diff --git a/factory/pubsubFactory.go b/factory/pubsubFactory.go index 768900cf..5265dff0 100644 --- a/factory/pubsubFactory.go +++ b/factory/pubsubFactory.go @@ -9,7 +9,7 @@ import ( ) // CreatePublisher creates publisher component -func CreatePublisher(apiType string, config *config.Config, marshaller marshal.Marshalizer) (rabbitmq.PublisherService, error) { +func CreatePublisher(apiType string, config config.MainConfig, marshaller marshal.Marshalizer) (rabbitmq.PublisherService, error) { switch apiType { case common.MessageQueueAPIType: return createRabbitMqPublisher(config.RabbitMQ, marshaller) diff --git a/go.mod b/go.mod index 5d046811..e5276013 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/multiversx/mx-chain-notifier-go go 1.16 require ( - github.com/gin-gonic/gin v1.8.1 + github.com/gin-gonic/gin v1.9.0 github.com/go-redis/redis/v8 v8.11.3 github.com/google/uuid v1.3.0 github.com/gorilla/websocket v1.5.0 @@ -11,11 +11,20 @@ require ( github.com/multiversx/mx-chain-logger-go v1.0.11 github.com/spaolacci/murmur3 v1.1.0 github.com/streadway/amqp v1.0.0 - github.com/stretchr/testify v1.8.2 + github.com/stretchr/testify v1.8.4 github.com/urfave/cli v1.22.10 ) require ( + github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/gin-contrib/cors v1.4.0 + github.com/klauspost/cpuid/v2 v2.2.5 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect github.com/multiversx/mx-chain-communication-go v1.0.2 + github.com/onsi/gomega v1.27.7 // indirect + github.com/prometheus/client_model v0.4.0 + github.com/prometheus/common v0.44.0 + golang.org/x/crypto v0.9.0 // indirect + google.golang.org/protobuf v1.30.0 ) diff --git a/go.sum b/go.sum index 1d49c1ee..9c7461b1 100644 --- a/go.sum +++ b/go.sum @@ -21,6 +21,7 @@ cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvf cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= @@ -45,12 +46,14 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= -github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/alecthomas/kingpin/v2 v2.3.1/go.mod h1:oYL5vtsvEHZGHxU7DMp32Dvx+qL+ptGn6lWaot2vCNE= +github.com/alecthomas/kingpin/v2 v2.3.2/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= @@ -84,13 +87,20 @@ github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= +github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.8.0 h1:ea0Xadu+sHlu7x5O3gKhRpQ1IKiMrSiHttPF0ybECuA= +github.com/bytedance/sonic v1.8.0/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= +github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -110,8 +120,9 @@ github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -145,15 +156,17 @@ github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiD github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/cors v1.4.0 h1:oJ6gwtUl3lqV0WEIwM/LxPF1QZ5qe2lGWdY2+bz7y0g= github.com/gin-contrib/cors v1.4.0/go.mod h1:bs9pNM0x/UsmHPBWT2xZz9ROh8xYjYkiURUfmBoMlcs= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8= github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= +github.com/gin-gonic/gin v1.9.0 h1:OjyFBKICoexlu99ctXNR2gg+c5pKrKMuyjgARg9qeY8= +github.com/gin-gonic/gin v1.9.0/go.mod h1:W1Me9+hsUSyj3CePGrd1/QrKJMSJ1Tu/0hFEH89961k= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= @@ -164,28 +177,35 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= -github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= -github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= -github.com/go-playground/validator/v10 v10.10.0 h1:I7mrTYv78z8k8VXa/qJlOlEXn/nBh+BF8dHX5nt/dr0= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= +github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU= +github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= github.com/go-redis/redis/v8 v8.11.3 h1:GCjoYp8c+yQTJfc0n69iwSiHjvuAdruxl7elnZCxgt8= github.com/go-redis/redis/v8 v8.11.3/go.mod h1:xNJ9xDG09FsIPwh3bWdk+0oDWHbtF9rPN0F/oD9XeKc= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= +github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -223,8 +243,9 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -242,8 +263,9 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -258,6 +280,7 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -291,6 +314,7 @@ github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7 github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj6+M= @@ -355,6 +379,8 @@ github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47e github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.1.0/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= +github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= @@ -363,8 +389,9 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= @@ -437,10 +464,14 @@ github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcncea github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= @@ -457,7 +488,6 @@ github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= @@ -530,13 +560,38 @@ github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvw github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU= +github.com/onsi/ginkgo/v2 v2.1.6/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk= +github.com/onsi/ginkgo/v2 v2.3.0/go.mod h1:Eew0uilEqZmIEZr8JrvYlvOM7Rr6xzTmMV8AyFNU9d0= +github.com/onsi/ginkgo/v2 v2.4.0/go.mod h1:iHkDK1fKGcBoEHT5W7YBq4RFWaQulw+caOMkAt4OrFo= +github.com/onsi/ginkgo/v2 v2.5.0/go.mod h1:Luc4sArBICYCS8THh8v3i3i5CuSZO+RaQRaJoeNwomw= +github.com/onsi/ginkgo/v2 v2.7.0/go.mod h1:yjiuMwPokqY1XauOgju45q3sJt6VzQ/Fict1LFVcsAo= +github.com/onsi/ginkgo/v2 v2.8.1/go.mod h1:N1/NbDngAFcSLdyZ+/aYTYGSlq9qMCS/cNKGJjy+csc= +github.com/onsi/ginkgo/v2 v2.9.0/go.mod h1:4xkjoL/tZv4SMWeww56BU5kAt19mVB47gTWxmrTcxyk= +github.com/onsi/ginkgo/v2 v2.9.1/go.mod h1:FEcmzVcCHl+4o9bQZVab+4dC9+j+91t2FHSzmGAPfuo= +github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts= +github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= -github.com/onsi/gomega v1.15.0 h1:WjP/FQ/sk43MRmnEcT+MlDw2TFvkrXlprrPST/IudjU= github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= +github.com/onsi/gomega v1.20.1/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo= +github.com/onsi/gomega v1.21.1/go.mod h1:iYAIXgPSaDHak0LCMA+AWBpIKBr8WZicMxnE8luStNc= +github.com/onsi/gomega v1.22.1/go.mod h1:x6n7VNe4hw0vkyYUM4mjIXx3JbLiPaBPNgB7PRQ1tuM= +github.com/onsi/gomega v1.24.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg= +github.com/onsi/gomega v1.24.1/go.mod h1:3AOiACssS3/MajrniINInwbfOOtfZvplPzuRSmvt1jM= +github.com/onsi/gomega v1.26.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM= +github.com/onsi/gomega v1.27.1/go.mod h1:aHX5xOykVYzWOV4WqQy0sy8BQptgukenXpCXfadcIAw= +github.com/onsi/gomega v1.27.3/go.mod h1:5vG284IBtfDAmDyrK+eGyZmUgUlmi+Wngqo557cZ6Gw= +github.com/onsi/gomega v1.27.4/go.mod h1:riYq/GJKh8hhoM01HN6Vmuy93AarCXCBGpvFDK3q3fQ= +github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= +github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU= +github.com/onsi/gomega v1.27.7/go.mod h1:1p8OOlwo2iUUDsHnOrjE5UKYJ+e3W8eQ3qSlRahPmr4= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= @@ -546,8 +601,9 @@ github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhM github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU= github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= +github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= +github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -561,16 +617,24 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= +github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= +github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= +github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= +github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= +github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -578,16 +642,19 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= +github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= github.com/raulk/go-watchdog v1.3.0/go.mod h1:fIvOnLbF0b0ZwkB9YU4mOW9Did//4vPZtDqv66NfsMU= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= @@ -609,8 +676,6 @@ github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ= github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk= github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= @@ -649,16 +714,21 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go v1.2.7 h1:qYhyWUUd6WbiM+C6JZAUkIJt/1WrjzNHY9+KCIjVqTo= github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= +github.com/ugorji/go/codec v1.2.9 h1:rmenucSohSTiyL09Y+l2OCk+FrMxGMzho2+tjr5ticU= +github.com/ugorji/go/codec v1.2.9/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.10 h1:p8Fspmz3iTctJstry1PYS3HVdllxnEzTEsgIgtxTrCk= github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= @@ -670,12 +740,15 @@ github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee/go.mod h1:m2aV4LZI4Aez7dP5PMyVKEHhUyEJ/RjmPEDOpDvudHg= github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= +github.com/xhit/go-str2duration v1.2.0/go.mod h1:3cPSlfZlUHVlneIVfePFWcJZsuwf+P1v2SRTV4cUmp4= +github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= @@ -706,6 +779,8 @@ go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= go.uber.org/zap v1.22.0/go.mod h1:H4siCOZOrAolnUPJEkfaSjDqyP+BDS0DdDWzwcgt3+U= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -729,8 +804,11 @@ golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5 golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= +golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= +golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -763,7 +841,13 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= +golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -810,6 +894,7 @@ golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= @@ -817,8 +902,15 @@ golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220812174116-3211cb980234/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -828,6 +920,8 @@ golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= +golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -842,6 +936,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -905,8 +1001,10 @@ golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -914,12 +1012,25 @@ golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= +golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -927,8 +1038,14 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -988,7 +1105,13 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= +golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1020,6 +1143,7 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= @@ -1082,8 +1206,9 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1103,7 +1228,6 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -1121,6 +1245,7 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 lukechampine.com/blake3 v1.1.6/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= diff --git a/integrationTests/interface.go b/integrationTests/interface.go index 98edc78d..30a0d18d 100644 --- a/integrationTests/interface.go +++ b/integrationTests/interface.go @@ -1,23 +1,10 @@ package integrationTests import ( - "net/http" - "github.com/multiversx/mx-chain-core-go/data/outport" "github.com/multiversx/mx-chain-notifier-go/data" ) -// FacadeHandler defines facade behaviour -type FacadeHandler interface { - HandlePushEventsV2(events data.ArgsSaveBlockData) error - HandlePushEventsV1(events data.SaveBlockData) error - HandleRevertEvents(revertBlock data.RevertBlock) - HandleFinalizedEvents(finalizedBlock data.FinalizedBlock) - GetConnectorUserAndPass() (string, string) - ServeHTTP(w http.ResponseWriter, r *http.Request) - IsInterfaceNil() bool -} - // PublisherHandler defines publisher behaviour type PublisherHandler interface { Run() diff --git a/integrationTests/rabbitmq/testNotifierWithRabbitMQ_test.go b/integrationTests/rabbitmq/testNotifierWithRabbitMQ_test.go index 8f71b632..526b86a5 100644 --- a/integrationTests/rabbitmq/testNotifierWithRabbitMQ_test.go +++ b/integrationTests/rabbitmq/testNotifierWithRabbitMQ_test.go @@ -32,8 +32,8 @@ func TestNotifierWithRabbitMQ(t *testing.T) { func testNotifierWithRabbitMQ(t *testing.T, observerType string) { cfg := integrationTests.GetDefaultConfigs() - cfg.ConnectorApi.CheckDuplicates = true - notifier, err := integrationTests.NewTestNotifierWithRabbitMq(cfg) + cfg.MainConfig.ConnectorApi.CheckDuplicates = true + notifier, err := integrationTests.NewTestNotifierWithRabbitMq(cfg.MainConfig) require.Nil(t, err) client, err := integrationTests.CreateObserverConnector(notifier.Facade, observerType, common.MessageQueueAPIType) diff --git a/integrationTests/testNotifierProxy.go b/integrationTests/testNotifierProxy.go index 3b96b88e..78afee9d 100644 --- a/integrationTests/testNotifierProxy.go +++ b/integrationTests/testNotifierProxy.go @@ -2,6 +2,7 @@ package integrationTests import ( "github.com/multiversx/mx-chain-core-go/marshal" + "github.com/multiversx/mx-chain-notifier-go/api/shared" "github.com/multiversx/mx-chain-notifier-go/config" "github.com/multiversx/mx-chain-notifier-go/disabled" "github.com/multiversx/mx-chain-notifier-go/dispatcher" @@ -9,6 +10,7 @@ import ( "github.com/multiversx/mx-chain-notifier-go/dispatcher/ws" "github.com/multiversx/mx-chain-notifier-go/facade" "github.com/multiversx/mx-chain-notifier-go/filters" + "github.com/multiversx/mx-chain-notifier-go/metrics" "github.com/multiversx/mx-chain-notifier-go/mocks" "github.com/multiversx/mx-chain-notifier-go/process" "github.com/multiversx/mx-chain-notifier-go/rabbitmq" @@ -16,7 +18,7 @@ import ( ) type testNotifier struct { - Facade FacadeHandler + Facade shared.FacadeHandler Publisher PublisherHandler WSHandler dispatcher.WSHandler RedisClient *mocks.RedisClientMock @@ -24,9 +26,8 @@ type testNotifier struct { } // NewTestNotifierWithWS will create a notifier instance for websockets flow -func NewTestNotifierWithWS(cfg *config.Config) (*testNotifier, error) { +func NewTestNotifierWithWS(cfg config.MainConfig) (*testNotifier, error) { marshaller := &marshal.JsonMarshalizer{} - redisClient := mocks.NewRedisClientMock() redlockArgs := redis.ArgsRedlockWrapper{ Client: redisClient, @@ -46,10 +47,13 @@ func NewTestNotifierWithWS(cfg *config.Config) (*testNotifier, error) { return nil, err } + statusMetricsHandler := metrics.NewStatusMetrics() + argsEventsHandler := process.ArgsEventsHandler{ - Config: cfg.ConnectorApi, - Locker: locker, - Publisher: publisher, + Config: cfg.ConnectorApi, + Locker: locker, + Publisher: publisher, + StatusMetricsHandler: statusMetricsHandler, } eventsHandler, err := process.NewEventsHandler(argsEventsHandler) if err != nil { @@ -79,10 +83,11 @@ func NewTestNotifierWithWS(cfg *config.Config) (*testNotifier, error) { } facadeArgs := facade.ArgsNotifierFacade{ - EventsHandler: eventsHandler, - APIConfig: cfg.ConnectorApi, - WSHandler: wsHandler, - EventsInterceptor: eventsInterceptor, + EventsHandler: eventsHandler, + APIConfig: cfg.ConnectorApi, + WSHandler: wsHandler, + EventsInterceptor: eventsInterceptor, + StatusMetricsHandler: statusMetricsHandler, } facade, err := facade.NewNotifierFacade(facadeArgs) if err != nil { @@ -99,9 +104,8 @@ func NewTestNotifierWithWS(cfg *config.Config) (*testNotifier, error) { } // NewTestNotifierWithRabbitMq will create a notifier instance with rabbitmq -func NewTestNotifierWithRabbitMq(cfg *config.Config) (*testNotifier, error) { +func NewTestNotifierWithRabbitMq(cfg config.MainConfig) (*testNotifier, error) { marshaller := &marshal.JsonMarshalizer{} - redisClient := mocks.NewRedisClientMock() redlockArgs := redis.ArgsRedlockWrapper{ Client: redisClient, @@ -112,6 +116,8 @@ func NewTestNotifierWithRabbitMq(cfg *config.Config) (*testNotifier, error) { return nil, err } + statusMetricsHandler := metrics.NewStatusMetrics() + rabbitmqMock := mocks.NewRabbitClientMock() publisherArgs := rabbitmq.ArgsRabbitMqPublisher{ Client: rabbitmqMock, @@ -124,9 +130,10 @@ func NewTestNotifierWithRabbitMq(cfg *config.Config) (*testNotifier, error) { } argsEventsHandler := process.ArgsEventsHandler{ - Config: cfg.ConnectorApi, - Locker: locker, - Publisher: publisher, + Config: cfg.ConnectorApi, + Locker: locker, + Publisher: publisher, + StatusMetricsHandler: statusMetricsHandler, } eventsHandler, err := process.NewEventsHandler(argsEventsHandler) if err != nil { @@ -143,10 +150,11 @@ func NewTestNotifierWithRabbitMq(cfg *config.Config) (*testNotifier, error) { wsHandler := &disabled.WSHandler{} facadeArgs := facade.ArgsNotifierFacade{ - EventsHandler: eventsHandler, - APIConfig: cfg.ConnectorApi, - WSHandler: wsHandler, - EventsInterceptor: eventsInterceptor, + EventsHandler: eventsHandler, + APIConfig: cfg.ConnectorApi, + WSHandler: wsHandler, + EventsInterceptor: eventsInterceptor, + StatusMetricsHandler: statusMetricsHandler, } facade, err := facade.NewNotifierFacade(facadeArgs) if err != nil { @@ -162,63 +170,65 @@ func NewTestNotifierWithRabbitMq(cfg *config.Config) (*testNotifier, error) { }, nil } -func GetDefaultConfigs() *config.Config { - return &config.Config{ - General: config.GeneralConfig{ - ExternalMarshaller: config.MarshallerConfig{ - Type: "json", - }, - InternalMarshaller: config.MarshallerConfig{ - Type: "json", - }, - AddressConverter: config.AddressConverterConfig{ - Type: "bech32", - Prefix: "erd", - Length: 32, - }, - }, - ConnectorApi: config.ConnectorApiConfig{ - Port: "8081", - Username: "user", - Password: "pass", - CheckDuplicates: false, - }, - Redis: config.RedisConfig{ - Url: "redis://localhost:6379", - Channel: "pub-sub", - MasterName: "mymaster", - SentinelUrl: "localhost:26379", - ConnectionType: "sentinel", - TTL: 30, - }, - RabbitMQ: config.RabbitMQConfig{ - Url: "amqp://guest:guest@localhost:5672", - EventsExchange: config.RabbitMQExchangeConfig{ - Name: "allevents", - Type: "fanout", - }, - RevertEventsExchange: config.RabbitMQExchangeConfig{ - Name: "revert", - Type: "fanout", - }, - FinalizedEventsExchange: config.RabbitMQExchangeConfig{ - Name: "finalized", - Type: "fanout", +// GetDefaultConfigs default configs +func GetDefaultConfigs() config.Configs { + return config.Configs{ + MainConfig: config.MainConfig{ + General: config.GeneralConfig{ + ExternalMarshaller: config.MarshallerConfig{ + Type: "json", + }, + InternalMarshaller: config.MarshallerConfig{ + Type: "json", + }, + AddressConverter: config.AddressConverterConfig{ + Type: "bech32", + Prefix: "erd", + Length: 32, + }, }, - BlockTxsExchange: config.RabbitMQExchangeConfig{ - Name: "blocktxs", - Type: "fanout", + ConnectorApi: config.ConnectorApiConfig{ + Host: "8081", + Username: "user", + Password: "pass", + CheckDuplicates: false, }, - BlockScrsExchange: config.RabbitMQExchangeConfig{ - Name: "blockscrs", - Type: "fanout", + Redis: config.RedisConfig{ + Url: "redis://localhost:6379", + MasterName: "mymaster", + SentinelUrl: "localhost:26379", + ConnectionType: "sentinel", + TTL: 30, }, - BlockEventsExchange: config.RabbitMQExchangeConfig{ - Name: "blockevents", - Type: "fanout", + RabbitMQ: config.RabbitMQConfig{ + Url: "amqp://guest:guest@localhost:5672", + EventsExchange: config.RabbitMQExchangeConfig{ + Name: "allevents", + Type: "fanout", + }, + RevertEventsExchange: config.RabbitMQExchangeConfig{ + Name: "revert", + Type: "fanout", + }, + FinalizedEventsExchange: config.RabbitMQExchangeConfig{ + Name: "finalized", + Type: "fanout", + }, + BlockTxsExchange: config.RabbitMQExchangeConfig{ + Name: "blocktxs", + Type: "fanout", + }, + BlockScrsExchange: config.RabbitMQExchangeConfig{ + Name: "blockscrs", + Type: "fanout", + }, + BlockEventsExchange: config.RabbitMQExchangeConfig{ + Name: "blockevents", + Type: "fanout", + }, }, }, - Flags: &config.FlagsConfig{ + Flags: config.FlagsConfig{ LogLevel: "*:INFO", SaveLogFile: false, GeneralConfigPath: "./config/config.toml", diff --git a/integrationTests/testWebServer.go b/integrationTests/testWebServer.go index ef965df0..aa201952 100644 --- a/integrationTests/testWebServer.go +++ b/integrationTests/testWebServer.go @@ -19,6 +19,7 @@ import ( "github.com/multiversx/mx-chain-notifier-go/api/groups" "github.com/multiversx/mx-chain-notifier-go/api/shared" "github.com/multiversx/mx-chain-notifier-go/common" + "github.com/multiversx/mx-chain-notifier-go/config" "github.com/stretchr/testify/assert" ) @@ -49,7 +50,7 @@ func NewTestWebServer(facade shared.FacadeHandler, apiType string, payloadHandle groupsMap := webServer.createGroups() for groupName, groupHandler := range groupsMap { ginGroup := ws.Group(groupName) - groupHandler.RegisterRoutes(ginGroup) + groupHandler.RegisterRoutes(ginGroup, getDefaultRoutesConfig()) } webServer.ws = ws @@ -164,3 +165,28 @@ func WaitTimeout(t *testing.T, wg *sync.WaitGroup, timeout time.Duration) { assert.Fail(t, "timeout when handling events") } } + +func getDefaultRoutesConfig() config.APIRoutesConfig { + return config.APIRoutesConfig{ + APIPackages: map[string]config.APIPackageConfig{ + "events": { + Routes: []config.RouteConfig{ + {Name: "/push", Open: true}, + {Name: "/revert", Open: true}, + {Name: "/finalized", Open: true}, + }, + }, + "hub": { + Routes: []config.RouteConfig{ + {Name: "/ws", Open: true}, + }, + }, + "status": { + Routes: []config.RouteConfig{ + {Name: "/metrics", Open: true}, + {Name: "/prometheus-metrics", Open: true}, + }, + }, + }, + } +} diff --git a/integrationTests/websocket/testNotifierWithWebsockets_test.go b/integrationTests/websocket/testNotifierWithWebsockets_test.go index 87ab3fa8..daf680d9 100644 --- a/integrationTests/websocket/testNotifierWithWebsockets_test.go +++ b/integrationTests/websocket/testNotifierWithWebsockets_test.go @@ -21,7 +21,7 @@ import ( func TestNotifierWithWebsockets_PushEvents(t *testing.T) { cfg := integrationTests.GetDefaultConfigs() - notifier, err := integrationTests.NewTestNotifierWithWS(cfg) + notifier, err := integrationTests.NewTestNotifierWithWS(cfg.MainConfig) require.Nil(t, err) webServer, err := integrationTests.CreateObserverConnector(notifier.Facade, common.HTTPConnectorType, common.WSAPIType) @@ -106,7 +106,7 @@ func TestNotifierWithWebsockets_PushEvents(t *testing.T) { func TestNotifierWithWebsockets_BlockEvents(t *testing.T) { cfg := integrationTests.GetDefaultConfigs() - notifier, err := integrationTests.NewTestNotifierWithWS(cfg) + notifier, err := integrationTests.NewTestNotifierWithWS(cfg.MainConfig) require.Nil(t, err) webServer, err := integrationTests.CreateObserverConnector(notifier.Facade, common.HTTPConnectorType, common.WSAPIType) @@ -198,7 +198,7 @@ func TestNotifierWithWebsockets_BlockEvents(t *testing.T) { func TestNotifierWithWebsockets_RevertEvents(t *testing.T) { cfg := integrationTests.GetDefaultConfigs() - notifier, err := integrationTests.NewTestNotifierWithWS(cfg) + notifier, err := integrationTests.NewTestNotifierWithWS(cfg.MainConfig) require.Nil(t, err) webServer, err := integrationTests.CreateObserverConnector(notifier.Facade, common.HTTPConnectorType, common.WSAPIType) @@ -259,7 +259,7 @@ func TestNotifierWithWebsockets_RevertEvents(t *testing.T) { func TestNotifierWithWebsockets_FinalizedEvents(t *testing.T) { cfg := integrationTests.GetDefaultConfigs() - notifier, err := integrationTests.NewTestNotifierWithWS(cfg) + notifier, err := integrationTests.NewTestNotifierWithWS(cfg.MainConfig) require.Nil(t, err) webServer, err := integrationTests.CreateObserverConnector(notifier.Facade, common.HTTPConnectorType, common.WSAPIType) @@ -310,7 +310,7 @@ func TestNotifierWithWebsockets_FinalizedEvents(t *testing.T) { func TestNotifierWithWebsockets_TxsEvents(t *testing.T) { cfg := integrationTests.GetDefaultConfigs() - notifier, err := integrationTests.NewTestNotifierWithWS(cfg) + notifier, err := integrationTests.NewTestNotifierWithWS(cfg.MainConfig) require.Nil(t, err) webServer, err := integrationTests.CreateObserverConnector(notifier.Facade, common.HTTPConnectorType, common.WSAPIType) @@ -394,7 +394,7 @@ func TestNotifierWithWebsockets_TxsEvents(t *testing.T) { func TestNotifierWithWebsockets_ScrsEvents(t *testing.T) { cfg := integrationTests.GetDefaultConfigs() - notifier, err := integrationTests.NewTestNotifierWithWS(cfg) + notifier, err := integrationTests.NewTestNotifierWithWS(cfg.MainConfig) require.Nil(t, err) webServer, err := integrationTests.CreateObserverConnector(notifier.Facade, common.HTTPConnectorType, common.WSAPIType) @@ -487,8 +487,8 @@ func TestNotifierWithWebsockets_AllEvents(t *testing.T) { func testNotifierWithWebsockets_AllEvents(t *testing.T, observerType string) { cfg := integrationTests.GetDefaultConfigs() - cfg.ConnectorApi.CheckDuplicates = true - notifier, err := integrationTests.NewTestNotifierWithWS(cfg) + cfg.MainConfig.ConnectorApi.CheckDuplicates = true + notifier, err := integrationTests.NewTestNotifierWithWS(cfg.MainConfig) require.Nil(t, err) client, err := integrationTests.CreateObserverConnector(notifier.Facade, observerType, common.MessageQueueAPIType) diff --git a/metrics/prometheusMetrics.go b/metrics/prometheusMetrics.go new file mode 100644 index 00000000..152ea3fa --- /dev/null +++ b/metrics/prometheusMetrics.go @@ -0,0 +1,41 @@ +package metrics + +import ( + "bytes" + + dto "github.com/prometheus/client_model/go" + "github.com/prometheus/common/expfmt" + "google.golang.org/protobuf/proto" +) + +func requestsCounterMetric(metricName, endpoint string, count uint64) string { + metricFamily := &dto.MetricFamily{ + Name: proto.String(metricName), + Type: dto.MetricType_COUNTER.Enum(), + Metric: []*dto.Metric{ + { + Label: []*dto.LabelPair{ + { + Name: proto.String("operation"), + Value: proto.String(endpoint), + }, + }, + Counter: &dto.Counter{ + Value: proto.Float64(float64(count)), + }, + }, + }, + } + + return promMetricAsString(metricFamily) +} + +func promMetricAsString(metric *dto.MetricFamily) string { + out := bytes.NewBuffer(make([]byte, 0)) + _, err := expfmt.MetricFamilyToText(out, metric) + if err != nil { + return "" + } + + return out.String() + "\n" +} diff --git a/metrics/statusMetrics.go b/metrics/statusMetrics.go new file mode 100644 index 00000000..1fb3f8e9 --- /dev/null +++ b/metrics/statusMetrics.go @@ -0,0 +1,86 @@ +package metrics + +import ( + "strings" + "sync" + "time" + + "github.com/multiversx/mx-chain-notifier-go/data" +) + +const ( + numRequestsPromMetric = "num_requests" + totalResponseTimePromMetric = "total_response_time" +) + +type statusMetrics struct { + operationMetrics map[string]*data.EndpointMetricsResponse + mutOperationMetrics sync.RWMutex +} + +// NewStatusMetrics will return an instance of the statusMetrics +func NewStatusMetrics() *statusMetrics { + return &statusMetrics{ + operationMetrics: make(map[string]*data.EndpointMetricsResponse), + } +} + +// AddRequest will add the received data to the metrics map +func (sm *statusMetrics) AddRequest(path string, duration time.Duration) { + sm.mutOperationMetrics.Lock() + defer sm.mutOperationMetrics.Unlock() + + currentData := sm.operationMetrics[path] + if currentData == nil { + newMetricsData := &data.EndpointMetricsResponse{ + NumRequests: 1, + TotalResponseTime: duration, + } + + sm.operationMetrics[path] = newMetricsData + + return + } + + currentData.NumRequests++ + currentData.TotalResponseTime += duration +} + +// GetAll returns the metrics map +func (sm *statusMetrics) GetAll() map[string]*data.EndpointMetricsResponse { + sm.mutOperationMetrics.RLock() + defer sm.mutOperationMetrics.RUnlock() + + return sm.getAll() +} + +func (sm *statusMetrics) getAll() map[string]*data.EndpointMetricsResponse { + newMap := make(map[string]*data.EndpointMetricsResponse) + for key, value := range sm.operationMetrics { + newMap[key] = value + } + + return newMap +} + +// GetMetricsForPrometheus returns the metrics in a prometheus format +func (sm *statusMetrics) GetMetricsForPrometheus() string { + sm.mutOperationMetrics.RLock() + defer sm.mutOperationMetrics.RUnlock() + + metricsMap := sm.getAll() + + stringBuilder := strings.Builder{} + + for endpointPath, endpointData := range metricsMap { + stringBuilder.WriteString(requestsCounterMetric(numRequestsPromMetric, endpointPath, endpointData.NumRequests)) + stringBuilder.WriteString(requestsCounterMetric(totalResponseTimePromMetric, endpointPath, uint64(endpointData.TotalResponseTime.Milliseconds()))) + } + + return stringBuilder.String() +} + +// IsInterfaceNil returns true if there is no value under the interface +func (sm *statusMetrics) IsInterfaceNil() bool { + return sm == nil +} diff --git a/metrics/statusMetrics_test.go b/metrics/statusMetrics_test.go new file mode 100644 index 00000000..0793cb87 --- /dev/null +++ b/metrics/statusMetrics_test.go @@ -0,0 +1,155 @@ +package metrics_test + +import ( + "fmt" + "sync" + "testing" + "time" + + "github.com/multiversx/mx-chain-core-go/core/check" + "github.com/multiversx/mx-chain-notifier-go/data" + "github.com/multiversx/mx-chain-notifier-go/metrics" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNewStatusMetrics(t *testing.T) { + t.Parallel() + + sm := metrics.NewStatusMetrics() + require.False(t, check.IfNil(sm)) +} + +func TestStatusMetrics_AddRequestData(t *testing.T) { + t.Parallel() + + t.Run("one metric exists for an endpoint", func(t *testing.T) { + t.Parallel() + + sm := metrics.NewStatusMetrics() + + testOp, testDuration := "block_events", 1*time.Second + sm.AddRequest(testOp, testDuration) + + res := sm.GetAll() + require.Equal(t, res[testOp], &data.EndpointMetricsResponse{ + NumRequests: 1, + TotalResponseTime: testDuration, + }) + }) + + t.Run("multiple entries exist for an endpoint", func(t *testing.T) { + t.Parallel() + + sm := metrics.NewStatusMetrics() + + testOp := "block_events" + testDuration0, testDuration1, testDuration2 := 4*time.Millisecond, 20*time.Millisecond, 2*time.Millisecond + sm.AddRequest(testOp, testDuration0) + sm.AddRequest(testOp, testDuration1) + sm.AddRequest(testOp, testDuration2) + + res := sm.GetAll() + require.Equal(t, res[testOp], &data.EndpointMetricsResponse{ + NumRequests: 3, + TotalResponseTime: testDuration0 + testDuration1 + testDuration2, + }) + }) + + t.Run("multiple entries for multiple endpoints", func(t *testing.T) { + t.Parallel() + + sm := metrics.NewStatusMetrics() + + testOp0, testOp1 := "block_events", "scrs_events" + + testDuration0End0, testDuration1End0 := time.Second, 5*time.Second + testDuration0End1, testDuration1End1 := time.Hour, 4*time.Hour + + sm.AddRequest(testOp0, testDuration0End0) + sm.AddRequest(testOp0, testDuration1End0) + + sm.AddRequest(testOp1, testDuration0End1) + sm.AddRequest(testOp1, testDuration1End1) + + res := sm.GetAll() + + require.Len(t, res, 2) + require.Equal(t, res[testOp0], &data.EndpointMetricsResponse{ + NumRequests: 2, + TotalResponseTime: testDuration0End0 + testDuration1End0, + }) + require.Equal(t, res[testOp1], &data.EndpointMetricsResponse{ + NumRequests: 2, + TotalResponseTime: testDuration0End1 + testDuration1End1, + }) + }) +} + +func TestStatusMetrics_GetMetricsForPrometheus(t *testing.T) { + t.Parallel() + + t.Run("should work", func(t *testing.T) { + t.Parallel() + + sm := metrics.NewStatusMetrics() + + testOperation := "block_events" + testDuration0, testDuration1, testDuration2 := 4*time.Millisecond, 20*time.Millisecond, 2*time.Millisecond + sm.AddRequest(testOperation, testDuration0) + sm.AddRequest(testOperation, testDuration1) + sm.AddRequest(testOperation, testDuration2) + + res := sm.GetMetricsForPrometheus() + + expectedString := `# TYPE num_requests counter +num_requests{operation="block_events"} 3 + +# TYPE total_response_time counter +total_response_time{operation="block_events"} 26 + +` + + require.Equal(t, expectedString, res) + + }) +} + +func TestStatusMetrics_ConcurrentOperations(t *testing.T) { + t.Parallel() + + defer func() { + r := recover() + require.Nil(t, r) + }() + + sm := metrics.NewStatusMetrics() + + numIterations := 500 + wg := sync.WaitGroup{} + wg.Add(numIterations) + + for i := 0; i < numIterations; i++ { + go func(index int) { + switch index % 3 { + case 0: + sm.AddRequest(fmt.Sprintf("op_%d", index%5), time.Hour*time.Duration(index)) + case 1: + _ = sm.GetAll() + case 2: + _ = sm.GetMetricsForPrometheus() + } + + wg.Done() + }(i) + } + + wg.Wait() +} + +func TestStatusMetrics_IsInterfaceNil(t *testing.T) { + t.Parallel() + + sm := metrics.NewStatusMetrics() + assert.False(t, sm.IsInterfaceNil()) +} diff --git a/mocks/facadeStub.go b/mocks/facadeStub.go index 28b39682..5e207514 100644 --- a/mocks/facadeStub.go +++ b/mocks/facadeStub.go @@ -14,6 +14,8 @@ type FacadeStub struct { HandleFinalizedEventsCalled func(events data.FinalizedBlock) ServeCalled func(w http.ResponseWriter, r *http.Request) GetConnectorUserAndPassCalled func() (string, string) + GetMetricsCalled func() map[string]*data.EndpointMetricsResponse + GetMetricsForPrometheusCalled func() string } // HandlePushEventsV2 - @@ -64,6 +66,24 @@ func (fs *FacadeStub) GetConnectorUserAndPass() (string, string) { return "", "" } +// GetMetrics - +func (fs *FacadeStub) GetMetrics() map[string]*data.EndpointMetricsResponse { + if fs.GetMetricsCalled != nil { + return fs.GetMetricsCalled() + } + + return nil +} + +// GetMetricsForPrometheus - +func (fs *FacadeStub) GetMetricsForPrometheus() string { + if fs.GetMetricsForPrometheusCalled != nil { + return fs.GetMetricsForPrometheusCalled() + } + + return "" +} + // IsInterfaceNil - func (fs *FacadeStub) IsInterfaceNil() bool { return fs == nil diff --git a/mocks/statusMetricsStub.go b/mocks/statusMetricsStub.go new file mode 100644 index 00000000..0267a7c5 --- /dev/null +++ b/mocks/statusMetricsStub.go @@ -0,0 +1,44 @@ +package mocks + +import ( + "time" + + "github.com/multiversx/mx-chain-notifier-go/data" +) + +// StatusMetricsStub - +type StatusMetricsStub struct { + AddRequestCalled func(path string, duration time.Duration) + GetAllCalled func() map[string]*data.EndpointMetricsResponse + GetMetricsForPrometheusCalled func() string +} + +// AddRequest - +func (s *StatusMetricsStub) AddRequest(path string, duration time.Duration) { + if s.AddRequestCalled != nil { + s.AddRequestCalled(path, duration) + } +} + +// GetAll - +func (s *StatusMetricsStub) GetAll() map[string]*data.EndpointMetricsResponse { + if s.GetAllCalled != nil { + return s.GetAllCalled() + } + + return nil +} + +// GetMetricsForPrometheus - +func (s *StatusMetricsStub) GetMetricsForPrometheus() string { + if s.GetMetricsForPrometheusCalled != nil { + return s.GetMetricsForPrometheusCalled() + } + + return "" +} + +// IsInterfaceNil - +func (s *StatusMetricsStub) IsInterfaceNil() bool { + return s == nil +} diff --git a/notifier/notifierRunner.go b/notifier/notifierRunner.go index 87da3b14..68199087 100644 --- a/notifier/notifierRunner.go +++ b/notifier/notifierRunner.go @@ -12,6 +12,7 @@ import ( "github.com/multiversx/mx-chain-notifier-go/dispatcher" "github.com/multiversx/mx-chain-notifier-go/facade" "github.com/multiversx/mx-chain-notifier-go/factory" + "github.com/multiversx/mx-chain-notifier-go/metrics" "github.com/multiversx/mx-chain-notifier-go/process" "github.com/multiversx/mx-chain-notifier-go/rabbitmq" ) @@ -19,37 +20,37 @@ import ( var log = logger.GetOrCreate("notifierRunner") type notifierRunner struct { - configs *config.Config + configs config.Configs } // NewNotifierRunner create a new notifierRunner instance -func NewNotifierRunner(cfgs *config.Config) (*notifierRunner, error) { +func NewNotifierRunner(cfgs *config.Configs) (*notifierRunner, error) { if cfgs == nil { return nil, ErrNilConfigs } return ¬ifierRunner{ - configs: cfgs, + configs: *cfgs, }, nil } // Start will trigger the notifier service func (nr *notifierRunner) Start() error { - externalMarshaller, err := marshalFactory.NewMarshalizer(nr.configs.General.ExternalMarshaller.Type) + externalMarshaller, err := marshalFactory.NewMarshalizer(nr.configs.MainConfig.General.ExternalMarshaller.Type) if err != nil { return err } - wsConnectorMarshaller, err := marshalFactory.NewMarshalizer(nr.configs.WebSocketConnector.DataMarshallerType) + wsConnectorMarshaller, err := marshalFactory.NewMarshalizer(nr.configs.MainConfig.WebSocketConnector.DataMarshallerType) if err != nil { return err } - lockService, err := factory.CreateLockService(nr.configs.ConnectorApi.CheckDuplicates, nr.configs.Redis) + lockService, err := factory.CreateLockService(nr.configs.MainConfig.ConnectorApi.CheckDuplicates, nr.configs.MainConfig.Redis) if err != nil { return err } - publisher, err := factory.CreatePublisher(nr.configs.Flags.APIType, nr.configs, externalMarshaller) + publisher, err := factory.CreatePublisher(nr.configs.Flags.APIType, nr.configs.MainConfig, externalMarshaller) if err != nil { return err } @@ -64,35 +65,39 @@ func (nr *notifierRunner) Start() error { return err } + statusMetricsHandler := metrics.NewStatusMetrics() + argsEventsHandler := factory.ArgsEventsHandlerFactory{ - APIConfig: nr.configs.ConnectorApi, - Locker: lockService, - MqPublisher: publisher, - HubPublisher: hub, - APIType: nr.configs.Flags.APIType, + APIConfig: nr.configs.MainConfig.ConnectorApi, + Locker: lockService, + MqPublisher: publisher, + HubPublisher: hub, + APIType: nr.configs.Flags.APIType, + StatusMetricsHandler: statusMetricsHandler, } eventsHandler, err := factory.CreateEventsHandler(argsEventsHandler) if err != nil { return err } - eventsInterceptor, err := factory.CreateEventsInterceptor(nr.configs.General) + eventsInterceptor, err := factory.CreateEventsInterceptor(nr.configs.MainConfig.General) if err != nil { return err } facadeArgs := facade.ArgsNotifierFacade{ - EventsHandler: eventsHandler, - APIConfig: nr.configs.ConnectorApi, - WSHandler: wsHandler, - EventsInterceptor: eventsInterceptor, + EventsHandler: eventsHandler, + APIConfig: nr.configs.MainConfig.ConnectorApi, + WSHandler: wsHandler, + EventsInterceptor: eventsInterceptor, + StatusMetricsHandler: statusMetricsHandler, } facade, err := facade.NewNotifierFacade(facadeArgs) if err != nil { return err } - payloadHandler, err := factory.CreatePayloadHandler(*nr.configs, facade) + payloadHandler, err := factory.CreatePayloadHandler(nr.configs, facade) if err != nil { return err } @@ -100,16 +105,14 @@ func (nr *notifierRunner) Start() error { webServerArgs := gin.ArgsWebServerHandler{ Facade: facade, PayloadHandler: payloadHandler, - Config: nr.configs.ConnectorApi, - Type: nr.configs.Flags.APIType, - ConnectorType: nr.configs.Flags.ConnectorType, + Configs: nr.configs, } webServer, err := gin.NewWebServerHandler(webServerArgs) if err != nil { return err } - wsConnector, err := factory.CreateWSObserverConnector(nr.configs.Flags.ConnectorType, nr.configs.WebSocketConnector, wsConnectorMarshaller, payloadHandler) + wsConnector, err := factory.CreateWSObserverConnector(nr.configs.Flags.ConnectorType, nr.configs.MainConfig.WebSocketConnector, wsConnectorMarshaller, payloadHandler) if err != nil { return err } diff --git a/process/eventsHandler.go b/process/eventsHandler.go index 291585e5..7b09644d 100644 --- a/process/eventsHandler.go +++ b/process/eventsHandler.go @@ -2,6 +2,7 @@ package process import ( "context" + "fmt" "time" "github.com/multiversx/mx-chain-core-go/core/check" @@ -22,19 +23,24 @@ const ( txsKeyPrefix = "txs_" txsWithOrderKeyPrefix = "txsWithOrder_" scrsKeyPrefix = "scrs_" + + rabbitmqMetricPrefix = "RabbitMQ" + redisMetricPrefix = "Redis" ) // ArgsEventsHandler defines the arguments needed for an events handler type ArgsEventsHandler struct { - Config config.ConnectorApiConfig - Locker LockService - Publisher Publisher + Config config.ConnectorApiConfig + Locker LockService + Publisher Publisher + StatusMetricsHandler common.StatusMetricsHandler } type eventsHandler struct { - config config.ConnectorApiConfig - locker LockService - publisher Publisher + config config.ConnectorApiConfig + locker LockService + publisher Publisher + metricsHandler common.StatusMetricsHandler } // NewEventsHandler creates a new events handler component @@ -45,9 +51,10 @@ func NewEventsHandler(args ArgsEventsHandler) (*eventsHandler, error) { } return &eventsHandler{ - locker: args.Locker, - publisher: args.Publisher, - config: args.Config, + locker: args.Locker, + publisher: args.Publisher, + config: args.Config, + metricsHandler: args.StatusMetricsHandler, }, nil } @@ -58,6 +65,9 @@ func checkArgs(args ArgsEventsHandler) error { if check.IfNil(args.Publisher) { return ErrNilPublisherService } + if check.IfNil(args.StatusMetricsHandler) { + return common.ErrNilStatusMetricsHandler + } return nil } @@ -65,45 +75,48 @@ func checkArgs(args ArgsEventsHandler) error { // HandlePushEvents will handle push events received from observer func (eh *eventsHandler) HandlePushEvents(events data.BlockEvents) error { if events.Hash == "" { - log.Debug("received empty events block hash", + log.Debug("received empty hash", "event", common.PushLogsAndEvents, "will process", false, ) return common.ErrReceivedEmptyEvents } + shouldProcessEvents := true if eh.config.CheckDuplicates { - shouldProcessEvents = eh.tryCheckProcessedWithRetry(events.Hash) + shouldProcessEvents = eh.tryCheckProcessedWithRetry(common.PushLogsAndEvents, events.Hash) } if !shouldProcessEvents { - log.Info("received duplicated events for block", + log.Info("received duplicated events", "event", common.PushLogsAndEvents, "block hash", events.Hash, - "processed", false, + "will process", false, ) return nil } if len(events.Events) == 0 { - log.Info("received empty events for block", + log.Warn("received empty events", "event", common.PushLogsAndEvents, "block hash", events.Hash, "will process", shouldProcessEvents, ) events.Events = make([]data.Event, 0) } else { - log.Info("received events for block", + log.Info("received", "event", common.PushLogsAndEvents, "block hash", events.Hash, "will process", shouldProcessEvents, ) } + t := time.Now() eh.publisher.Broadcast(events) + eh.metricsHandler.AddRequest(getRabbitOpID(common.PushLogsAndEvents), time.Since(t)) return nil } // HandleRevertEvents will handle revents events received from observer func (eh *eventsHandler) HandleRevertEvents(revertBlock data.RevertBlock) { if revertBlock.Hash == "" { - log.Warn("received empty revert block hash", + log.Warn("received empty hash", "event", common.RevertBlockEvents, "will process", false, ) return @@ -111,166 +124,176 @@ func (eh *eventsHandler) HandleRevertEvents(revertBlock data.RevertBlock) { shouldProcessRevert := true if eh.config.CheckDuplicates { - revertKey := revertKeyPrefix + revertBlock.Hash - shouldProcessRevert = eh.tryCheckProcessedWithRetry(revertKey) + shouldProcessRevert = eh.tryCheckProcessedWithRetry(common.RevertBlockEvents, revertBlock.Hash) } if !shouldProcessRevert { - log.Info("received duplicated revert event for block", + log.Info("received duplicated events", "event", common.RevertBlockEvents, "block hash", revertBlock.Hash, - "processed", false, + "will process", false, ) return } - log.Info("received revert event for block", + log.Info("received", "event", common.RevertBlockEvents, "block hash", revertBlock.Hash, "will process", shouldProcessRevert, ) + t := time.Now() eh.publisher.BroadcastRevert(revertBlock) + eh.metricsHandler.AddRequest(getRabbitOpID(common.RevertBlockEvents), time.Since(t)) } // HandleFinalizedEvents will handle finalized events received from observer func (eh *eventsHandler) HandleFinalizedEvents(finalizedBlock data.FinalizedBlock) { if finalizedBlock.Hash == "" { - log.Warn("received empty finalized block hash", + log.Warn("received empty hash", "event", common.FinalizedBlockEvents, "will process", false, ) return } shouldProcessFinalized := true if eh.config.CheckDuplicates { - finalizedKey := finalizedKeyPrefix + finalizedBlock.Hash - shouldProcessFinalized = eh.tryCheckProcessedWithRetry(finalizedKey) + shouldProcessFinalized = eh.tryCheckProcessedWithRetry(common.FinalizedBlockEvents, finalizedBlock.Hash) } if !shouldProcessFinalized { - log.Info("received duplicated finalized event for block", + log.Info("received duplicated events", "event", common.FinalizedBlockEvents, "block hash", finalizedBlock.Hash, - "processed", false, + "will process", false, ) return } - log.Info("received finalized events for block", + log.Info("received", "event", common.FinalizedBlockEvents, "block hash", finalizedBlock.Hash, "will process", shouldProcessFinalized, ) + t := time.Now() eh.publisher.BroadcastFinalized(finalizedBlock) + eh.metricsHandler.AddRequest(getRabbitOpID(common.FinalizedBlockEvents), time.Since(t)) } // HandleBlockTxs will handle txs events received from observer func (eh *eventsHandler) HandleBlockTxs(blockTxs data.BlockTxs) { if blockTxs.Hash == "" { - log.Warn("received empty txs block hash", + log.Warn("received empty hash", "event", common.BlockTxs, "will process", false, ) return } shouldProcessTxs := true if eh.config.CheckDuplicates { - txsKey := txsKeyPrefix + blockTxs.Hash - shouldProcessTxs = eh.tryCheckProcessedWithRetry(txsKey) + shouldProcessTxs = eh.tryCheckProcessedWithRetry(common.BlockTxs, blockTxs.Hash) } if !shouldProcessTxs { - log.Info("received duplicated txs event for block", + log.Info("received duplicated events", "event", common.BlockTxs, "block hash", blockTxs.Hash, - "processed", false, + "will process", false, ) return } if len(blockTxs.Txs) == 0 { - log.Info("received empty txs event for block", + log.Warn("received empty events", "event", common.BlockTxs, "block hash", blockTxs.Hash, "will process", shouldProcessTxs, ) } else { - log.Info("received txs events for block", + log.Info("received", "event", common.BlockTxs, "block hash", blockTxs.Hash, "will process", shouldProcessTxs, ) } + t := time.Now() eh.publisher.BroadcastTxs(blockTxs) + eh.metricsHandler.AddRequest(getRabbitOpID(common.BlockTxs), time.Since(t)) } // HandleBlockScrs will handle scrs events received from observer func (eh *eventsHandler) HandleBlockScrs(blockScrs data.BlockScrs) { if blockScrs.Hash == "" { - log.Warn("received empty scrs block hash", + log.Warn("received empty hash", "event", common.BlockScrs, "will process", false, ) return } shouldProcessScrs := true if eh.config.CheckDuplicates { - scrsKey := scrsKeyPrefix + blockScrs.Hash - shouldProcessScrs = eh.tryCheckProcessedWithRetry(scrsKey) + shouldProcessScrs = eh.tryCheckProcessedWithRetry(common.BlockScrs, blockScrs.Hash) } if !shouldProcessScrs { - log.Info("received duplicated scrs event for block", + log.Info("received duplicated events", "event", common.BlockScrs, "block hash", blockScrs.Hash, - "processed", false, + "will process", false, ) return } if len(blockScrs.Scrs) == 0 { - log.Info("received empty scrs event for block", + log.Warn("received empty events", "event", common.BlockScrs, "block hash", blockScrs.Hash, "will process", shouldProcessScrs, ) } else { - log.Info("received scrs events for block", + log.Info("received", "event", common.BlockScrs, "block hash", blockScrs.Hash, "will process", shouldProcessScrs, ) } + t := time.Now() eh.publisher.BroadcastScrs(blockScrs) + eh.metricsHandler.AddRequest(getRabbitOpID(common.BlockScrs), time.Since(t)) } // HandleBlockEventsWithOrder will handle full block events received from observer func (eh *eventsHandler) HandleBlockEventsWithOrder(blockTxs data.BlockEventsWithOrder) { if blockTxs.Hash == "" { - log.Warn("received full block events with empty block hash", + log.Warn("received empty hash", "event", common.BlockEvents, "will process", false, ) return } shouldProcessTxs := true if eh.config.CheckDuplicates { - txsKey := txsWithOrderKeyPrefix + blockTxs.Hash - shouldProcessTxs = eh.tryCheckProcessedWithRetry(txsKey) + shouldProcessTxs = eh.tryCheckProcessedWithRetry(common.BlockEvents, blockTxs.Hash) } if !shouldProcessTxs { - log.Info("received duplicated full block events for block", + log.Info("received duplicated events", "event", common.BlockEvents, "block hash", blockTxs.Hash, - "processed", false, + "will process", false, ) return } - log.Info("received full block events for block", + log.Info("received", "event", common.BlockEvents, "block hash", blockTxs.Hash, "will process", shouldProcessTxs, ) + t := time.Now() eh.publisher.BroadcastBlockEventsWithOrder(blockTxs) + eh.metricsHandler.AddRequest(getRabbitOpID(common.BlockEvents), time.Since(t)) } -func (eh *eventsHandler) tryCheckProcessedWithRetry(blockHash string) bool { +func (eh *eventsHandler) tryCheckProcessedWithRetry(id, blockHash string) bool { var err error var setSuccessful bool + prefix := getPrefixLockerKey(id) + key := prefix + blockHash + for { - setSuccessful, err = eh.locker.IsEventProcessed(context.Background(), blockHash) + t := time.Now() + setSuccessful, err = eh.locker.IsEventProcessed(context.Background(), key) + eh.metricsHandler.AddRequest(getRedisOpID(id), time.Since(t)) if err == nil { break @@ -286,12 +309,37 @@ func (eh *eventsHandler) tryCheckProcessedWithRetry(blockHash string) bool { } } - if !setSuccessful { - log.Debug("did not succeed to set event in locker") - return false + log.Debug("locker", "event", id, "block hash", blockHash, "succeeded", setSuccessful) + + return setSuccessful +} + +func getPrefixLockerKey(id string) string { + // keep this matching for backwards compatibility + switch id { + case common.PushLogsAndEvents: + return "" + case common.RevertBlockEvents: + return revertKeyPrefix + case common.FinalizedBlockEvents: + return finalizedKeyPrefix + case common.BlockTxs: + return txsKeyPrefix + case common.BlockScrs: + return scrsKeyPrefix + case common.BlockEvents: + return txsWithOrderKeyPrefix } - return true + return "" +} + +func getRabbitOpID(operation string) string { + return fmt.Sprintf("%s-%s", rabbitmqMetricPrefix, operation) +} + +func getRedisOpID(operation string) string { + return fmt.Sprintf("%s-%s", redisMetricPrefix, operation) } // IsInterfaceNil returns true if there is no value under the interface diff --git a/process/eventsHandler_test.go b/process/eventsHandler_test.go index 8b1e52ed..9fdf8b9e 100644 --- a/process/eventsHandler_test.go +++ b/process/eventsHandler_test.go @@ -9,6 +9,7 @@ import ( "github.com/multiversx/mx-chain-core-go/data/outport" "github.com/multiversx/mx-chain-core-go/data/smartContractResult" "github.com/multiversx/mx-chain-core-go/data/transaction" + "github.com/multiversx/mx-chain-notifier-go/common" "github.com/multiversx/mx-chain-notifier-go/config" "github.com/multiversx/mx-chain-notifier-go/data" "github.com/multiversx/mx-chain-notifier-go/mocks" @@ -21,8 +22,9 @@ func createMockEventsHandlerArgs() process.ArgsEventsHandler { Config: config.ConnectorApiConfig{ CheckDuplicates: false, }, - Locker: &mocks.LockerStub{}, - Publisher: &mocks.PublisherStub{}, + Locker: &mocks.LockerStub{}, + Publisher: &mocks.PublisherStub{}, + StatusMetricsHandler: &mocks.StatusMetricsStub{}, } } @@ -51,6 +53,17 @@ func TestNewEventsHandler(t *testing.T) { require.Nil(t, eventsHandler) }) + t.Run("nil status metrics handler", func(t *testing.T) { + t.Parallel() + + args := createMockEventsHandlerArgs() + args.StatusMetricsHandler = nil + + eventsHandler, err := process.NewEventsHandler(args) + require.Equal(t, common.ErrNilStatusMetricsHandler, err) + require.Nil(t, eventsHandler) + }) + t.Run("should work", func(t *testing.T) { t.Parallel() @@ -430,6 +443,7 @@ func TestTryCheckProcessedWithRetry(t *testing.T) { t.Parallel() hash := "hash1" + prefix := "prefix_" t.Run("event is NOT already processed", func(t *testing.T) { t.Parallel() @@ -445,7 +459,7 @@ func TestTryCheckProcessedWithRetry(t *testing.T) { eventsHandler, err := process.NewEventsHandler(args) require.Nil(t, err) - ok := eventsHandler.TryCheckProcessedWithRetry(hash) + ok := eventsHandler.TryCheckProcessedWithRetry(prefix, hash) require.False(t, ok) }) @@ -463,7 +477,7 @@ func TestTryCheckProcessedWithRetry(t *testing.T) { eventsHandler, err := process.NewEventsHandler(args) require.Nil(t, err) - ok := eventsHandler.TryCheckProcessedWithRetry(hash) + ok := eventsHandler.TryCheckProcessedWithRetry(prefix, hash) require.True(t, ok) }) @@ -494,7 +508,7 @@ func TestTryCheckProcessedWithRetry(t *testing.T) { eventsHandler, err := process.NewEventsHandler(args) require.Nil(t, err) - ok := eventsHandler.TryCheckProcessedWithRetry(hash) + ok := eventsHandler.TryCheckProcessedWithRetry(prefix, hash) require.True(t, ok) }) } diff --git a/process/export_test.go b/process/export_test.go index af668379..6ff81d51 100644 --- a/process/export_test.go +++ b/process/export_test.go @@ -6,8 +6,8 @@ import ( ) // TryCheckProcessedWithRetry exports internal method for testing -func (eh *eventsHandler) TryCheckProcessedWithRetry(blockHash string) bool { - return eh.tryCheckProcessedWithRetry(blockHash) +func (eh *eventsHandler) TryCheckProcessedWithRetry(prefix, blockHash string) bool { + return eh.tryCheckProcessedWithRetry(prefix, blockHash) } // GetLogEventsFromTransactionsPool exports internal method for testing diff --git a/rabbitmq/rabbitClient.go b/rabbitmq/rabbitClient.go index 5009ceda..2196bf07 100644 --- a/rabbitmq/rabbitClient.go +++ b/rabbitmq/rabbitClient.go @@ -78,13 +78,16 @@ func (rc *rabbitMqClient) Publish(exchange, key string, mandatory, immediate boo immediate, msg, ) + if err != nil { + log.Error("failed to publish message", "exchange", exchange, "error", err.Error()) + } select { - case <-rc.ackCh: - log.Debug("Publish: published message ack") + case deliveryTag := <-rc.ackCh: + log.Debug("Publish: published message ack", "deliveryTag", deliveryTag) return err - case <-rc.nackCh: - log.Debug("Publish: published message nack, will retry to publish message", "error", err) + case deliveryTag := <-rc.nackCh: + log.Debug("Publish: published message nack, will retry to publish message", "deliveryTag", deliveryTag) case err := <-rc.connErrCh: if err != nil { log.Error("rabbitMQ connection failure", "err", err.Error()) diff --git a/redis/connection.go b/redis/connection.go index 62f434f3..d6c5c430 100644 --- a/redis/connection.go +++ b/redis/connection.go @@ -3,9 +3,9 @@ package redis import ( "context" + "github.com/go-redis/redis/v8" logger "github.com/multiversx/mx-chain-logger-go" "github.com/multiversx/mx-chain-notifier-go/config" - "github.com/go-redis/redis/v8" ) var log = logger.GetOrCreate("redis") @@ -18,6 +18,8 @@ func CreateSimpleClient(cfg config.RedisConfig) (RedLockClient, error) { } client := redis.NewClient(opt) + log.Debug("created redis instance connection type", "connection url", cfg.Url) + rc := NewRedisClientWrapper(client) ok := rc.IsConnected(context.Background()) if !ok { @@ -35,6 +37,8 @@ func CreateFailoverClient(cfg config.RedisConfig) (RedLockClient, error) { }) rc := NewRedisClientWrapper(client) + log.Debug("created redis sentinel connection type", "connection url", cfg.SentinelUrl, "master", cfg.MasterName) + ok := rc.IsConnected(context.Background()) if !ok { return nil, ErrRedisConnectionFailed diff --git a/redis/redlock.go b/redis/redlock.go index 0ced14be..6814398a 100644 --- a/redis/redlock.go +++ b/redis/redlock.go @@ -40,7 +40,7 @@ func (r *redlockWrapper) IsEventProcessed(ctx context.Context, blockHash string) return r.client.SetEntry(ctx, blockHash, true, r.ttl) } -// HasConnection return true if the redis client is connected +// HasConnection returns true if the redis client is connected func (r *redlockWrapper) HasConnection(ctx context.Context) bool { return r.client.IsConnected(ctx) }