From 17365eb5b33d945f765741a5a4a64a4068d14039 Mon Sep 17 00:00:00 2001 From: esuwu Date: Wed, 11 Jan 2023 22:46:34 -0600 Subject: [PATCH 01/20] Added aliases handlers --- .../internal/common/messaging/handlers.go | 35 +++++++++++++- .../internal/common/messaging/pair/client.go | 16 +++++++ .../internal/telegram/handlers/handlers.go | 47 +++++++++++++++++++ cmd/bots/internal/telegram/handlers/text.go | 22 +++++++++ .../telegram/messages/error_messages.go | 1 + pkg/entities/node.go | 1 + pkg/messaging/pair/request_types.go | 1 + pkg/messaging/pair/requests.go | 7 +++ pkg/messaging/pair/responses.go | 2 +- pkg/messaging/pair/server.go | 21 ++++++--- pkg/storing/nodes/nodes.go | 47 ++++++++++++++----- 11 files changed, 180 insertions(+), 20 deletions(-) diff --git a/cmd/bots/internal/common/messaging/handlers.go b/cmd/bots/internal/common/messaging/handlers.go index 1825b11c..2fb7c8a5 100644 --- a/cmd/bots/internal/common/messaging/handlers.go +++ b/cmd/bots/internal/common/messaging/handlers.go @@ -43,6 +43,26 @@ func AddNewNodeHandler( return fmt.Sprintf("New node '%s' was added", updatedUrl), nil } +func UpdateAliasHandler( + chatID string, + bot Bot, + requestType chan<- pair.RequestPair, + url string, + alias string) (string, error) { + + if !bot.IsEligibleForAction(chatID) { + return insufficientPermissionMsg, InsufficientPermissionsError + } + + updatedUrl, err := entities.CheckAndUpdateURL(url) + if err != nil { + return incorrectUrlMsg, IncorrectUrlError + } + requestType <- &pair.UpdateNodeRequest{Url: updatedUrl, Alias: alias} + + return fmt.Sprintf("Node '%s' was updated with alias %s", updatedUrl, alias), nil +} + func RemoveNodeHandler( chatID string, bot Bot, @@ -85,11 +105,24 @@ func RequestNodesList(requestType chan<- pair.RequestPair, responsePairType <-ch if !ok { return nil, errors.New("failed to convert response interface to the node list type") } - urls := nodesList.Urls + urls := make([]string, len(nodesList.Nodes)) + for i, n := range nodesList.Nodes { + urls[i] = n.URL + } sort.Strings(urls) return urls, nil } +func RequestFullNodesList(requestType chan<- pair.RequestPair, responsePairType <-chan pair.ResponsePair, specific bool) ([]entities.Node, error) { + requestType <- &pair.NodesListRequest{Specific: specific} + responsePair := <-responsePairType + nodesList, ok := responsePair.(*pair.NodesListResponse) + if !ok { + return nil, errors.New("failed to convert response interface to the node list type") + } + return nodesList.Nodes, nil +} + func RequestNodeStatement(requestType chan<- pair.RequestPair, responsePairType <-chan pair.ResponsePair, node string, height int) (*pair.NodeStatementResponse, error) { requestType <- &pair.NodeStatementRequest{Url: node, Height: height} responsePair := <-responsePairType diff --git a/cmd/bots/internal/common/messaging/pair/client.go b/cmd/bots/internal/common/messaging/pair/client.go index 1a77ac21..3133e725 100644 --- a/cmd/bots/internal/common/messaging/pair/client.go +++ b/cmd/bots/internal/common/messaging/pair/client.go @@ -77,6 +77,22 @@ func StartPairMessagingClient(ctx context.Context, nanomsgURL string, requestPai logger.Error("failed to send message", zap.Error(err)) } + case *pair.UpdateNodeRequest: + message.WriteByte(byte(pair.RequestUpdateNode)) + node := entities.Node{ + URL: r.Url, + Enabled: true, + Alias: r.Alias, + } + nodeInfo, err := json.Marshal(node) + if err != nil { + logger.Error("failed to marshal node's info") + } + message.Write(nodeInfo) + err = pairSocket.Send(message.Bytes()) + if err != nil { + logger.Error("failed to send message", zap.Error(err)) + } case *pair.DeleteNodeRequest: message.WriteByte(byte(pair.RequestDeleteNodeT)) diff --git a/cmd/bots/internal/telegram/handlers/handlers.go b/cmd/bots/internal/telegram/handlers/handlers.go index 088bc573..d208e81a 100644 --- a/cmd/bots/internal/telegram/handlers/handlers.go +++ b/cmd/bots/internal/telegram/handlers/handlers.go @@ -154,6 +154,53 @@ func InitTgHandlers(environment *common.TelegramBotEnvironment, requestType chan ) } return RemoveNodeHandler(c, environment, requestType, responsePairType, args[0]) + + }) + + environment.Bot.Handle("/add_alias", func(c tele.Context) error { + args := c.Args() + if len(args) > 2 { + return c.Send( + messages.RemovedMoreThanOne, + &tele.SendOptions{ + ParseMode: tele.ModeDefault, + }, + ) + } + if len(args) < 1 { + return c.Send( + messages.RemovedLessThanOne, + &tele.SendOptions{ + ParseMode: tele.ModeDefault, + }, + ) + } + return UpdateAliasHandler(c, environment, requestType, args[0], args[1]) + }) + + environment.Bot.Handle("/aliases", func(c tele.Context) error { + nodes, err := messaging.RequestFullNodesList(requestType, responsePairType, false) + if err != nil { + environment.Zap.Error("failed to request nodes list buttons", zap.Error(err)) + return err + } + additionalNodes, err := messaging.RequestFullNodesList(requestType, responsePairType, true) + if err != nil { + environment.Zap.Error("failed to request list of specific nodes", zap.Error(err)) + return err + } + nodes = append(nodes, additionalNodes...) + var msg string + for _, n := range nodes { + msg += fmt.Sprintf("Node: %s\nAlias: %s\n\n", n.URL, n.Alias) + } + + return c.Send( + msg, + &tele.SendOptions{ + ParseMode: tele.ModeHTML, + }, + ) }) environment.Bot.Handle("/subscribe", func(c tele.Context) error { diff --git a/cmd/bots/internal/telegram/handlers/text.go b/cmd/bots/internal/telegram/handlers/text.go index d5fd3b68..412648c5 100644 --- a/cmd/bots/internal/telegram/handlers/text.go +++ b/cmd/bots/internal/telegram/handlers/text.go @@ -89,6 +89,28 @@ func RemoveNodeHandler( ) } +func UpdateAliasHandler( + c tele.Context, + environment *common.TelegramBotEnvironment, + requestType chan<- pair.RequestPair, + url string, + alias string) error { + + response, err := messaging.UpdateAliasHandler(strconv.FormatInt(c.Chat().ID, 10), environment, requestType, url, alias) + if err != nil { + if err == messaging.IncorrectUrlError || err == messaging.InsufficientPermissionsError { + return c.Send( + response, + &tele.SendOptions{ParseMode: tele.ModeDefault}, + ) + } + return errors.Wrap(err, "failed to update a node") + } + return c.Send( + response, + &tele.SendOptions{ParseMode: tele.ModeHTML}) +} + func SubscribeHandler( c tele.Context, environment *common.TelegramBotEnvironment, diff --git a/cmd/bots/internal/telegram/messages/error_messages.go b/cmd/bots/internal/telegram/messages/error_messages.go index 42a9b3e2..ec7568ca 100644 --- a/cmd/bots/internal/telegram/messages/error_messages.go +++ b/cmd/bots/internal/telegram/messages/error_messages.go @@ -5,6 +5,7 @@ const ( AddedLessThanOne = "You should add a node" RemovedMoreThanOne = "You can remove only one node at a time" RemovedLessThanOne = "You should remove a node" + UpdateWrongFormat = "Format: /add_alias " SubscribedToMoreThanOne = "You can subscribe to only one node at a time" SubscribedToLessThanOne = "You should subscribe to a node" UnsubscribedFromMoreThanOne = "You can unsubscribe from only one node at a time" diff --git a/pkg/entities/node.go b/pkg/entities/node.go index 96153a48..004f83a7 100644 --- a/pkg/entities/node.go +++ b/pkg/entities/node.go @@ -15,6 +15,7 @@ const ( type Node struct { URL string `json:"url"` Enabled bool `json:"enabled"` + Alias string `json:"alias"` } func CheckAndUpdateURL(s string) (string, error) { diff --git a/pkg/messaging/pair/request_types.go b/pkg/messaging/pair/request_types.go index 5f37d585..13d59e8e 100644 --- a/pkg/messaging/pair/request_types.go +++ b/pkg/messaging/pair/request_types.go @@ -7,6 +7,7 @@ const ( RequestSpecificNodeListT RequestInsertNewNodeT RequestInsertSpecificNewNodeT + RequestUpdateNode RequestDeleteNodeT RequestNodesStatus RequestNodeStatement diff --git a/pkg/messaging/pair/requests.go b/pkg/messaging/pair/requests.go index ca4b1898..ec9be8e7 100644 --- a/pkg/messaging/pair/requests.go +++ b/pkg/messaging/pair/requests.go @@ -15,6 +15,11 @@ type InsertNewNodeRequest struct { Specific bool } +type UpdateNodeRequest struct { + Url string + Alias string +} + type DeleteNodeRequest struct { Url string } @@ -28,6 +33,8 @@ func (nl *NodesListRequest) requestMarker() {} func (nl *InsertNewNodeRequest) requestMarker() {} +func (nl *UpdateNodeRequest) requestMarker() {} + func (nl *DeleteNodeRequest) requestMarker() {} func (nl *NodesStatusRequest) requestMarker() {} diff --git a/pkg/messaging/pair/responses.go b/pkg/messaging/pair/responses.go index 8566132d..4408d68a 100644 --- a/pkg/messaging/pair/responses.go +++ b/pkg/messaging/pair/responses.go @@ -8,7 +8,7 @@ import ( type ResponsePair interface{ responseMarker() } type NodesListResponse struct { - Urls []string `json:"urls"` + Nodes []entities.Node `json:"nodes"` } type NodesStatusResponse struct { diff --git a/pkg/messaging/pair/server.go b/pkg/messaging/pair/server.go index aea4698b..03da4d5e 100644 --- a/pkg/messaging/pair/server.go +++ b/pkg/messaging/pair/server.go @@ -60,11 +60,7 @@ func StartPairMessagingServer(ctx context.Context, nanomsgURL string, ns *nodes. } } var nodeList NodesListResponse - - nodeList.Urls = make([]string, len(nodes)) - for i, node := range nodes { - nodeList.Urls[i] = node.URL - } + nodeList.Nodes = nodes response, err := json.Marshal(nodeList) if err != nil { logger.Error("Failed to marshal node list to json", zap.Error(err)) @@ -76,16 +72,27 @@ func StartPairMessagingServer(ctx context.Context, nanomsgURL string, ns *nodes. case RequestInsertNewNodeT: url := msg[1:] - err := ns.InsertIfNew(string(url)) + err := ns.InsertIfNew(string(url), false) if err != nil { logger.Error("Failed to insert a new node to storage", zap.Error(err)) } case RequestInsertSpecificNewNodeT: url := msg[1:] - err := ns.InsertSpecificIfNew(string(url)) + err := ns.InsertIfNew(string(url), true) + if err != nil { + logger.Error("Failed to insert a new specific node to storage", zap.Error(err)) + } + case RequestUpdateNode: + node := entities.Node{} + err := json.Unmarshal(msg[1:], &node) + if err != nil { + logger.Error("Failed to update a specific node", zap.Error(err)) + } + err = ns.Update(node) if err != nil { logger.Error("Failed to insert a new specific node to storage", zap.Error(err)) } + case RequestDeleteNodeT: url := msg[1:] err := ns.Delete(string(url)) diff --git a/pkg/storing/nodes/nodes.go b/pkg/storing/nodes/nodes.go index 7ac06673..57e4fb8b 100644 --- a/pkg/storing/nodes/nodes.go +++ b/pkg/storing/nodes/nodes.go @@ -82,31 +82,56 @@ func (cs *Storage) EnabledSpecificNodes() ([]entities.Node, error) { return cs.queryNodes(func(n node) bool { return n.Enabled }, 0, true) } -func (cs *Storage) InsertIfNew(url string) error { - ids, err := cs.queryNodes(func(n node) bool { return n.URL == url }, 0, false) +// Update handles both specific and non-specific nodes +func (cs *Storage) Update(nodeToUpdate entities.Node) error { + specific := false + ids, err := cs.queryNodes(func(n node) bool { return n.URL == nodeToUpdate.URL }, 0, false) if err != nil { return err } if len(ids) == 0 { - id, err := cs.db.Insert(nodesTableName, &node{Node: entities.Node{ - URL: url, - Enabled: true, - }}) + // look for the url in the specific nodes table + ids, err = cs.queryNodes(func(n node) bool { return n.URL == nodeToUpdate.URL }, 0, true) if err != nil { return err } - cs.zap.Sugar().Infof("New node #%d at '%s' was stored", id, url) + specific = true + if len(ids) == 0 { + return errors.Errorf("node %s was not found in the storage", nodeToUpdate.URL) + } + } + if len(ids) > 1 { + return errors.Errorf("failed to update a node in the storage, multiple nodes were found") + } + tableName := nodesTableName + if specific { + tableName = specificNodesTableName + } + + pulledNode := ids[0] + err = cs.db.Update(tableName, &node{Node: entities.Node{ + URL: pulledNode.URL, + Enabled: pulledNode.Enabled, + Alias: nodeToUpdate.Alias, + }}) + if err != nil { + return err } + cs.zap.Sugar().Infof("New node '%s' was updated with alias %s", pulledNode.URL, nodeToUpdate.Alias) return nil } -func (cs *Storage) InsertSpecificIfNew(url string) error { - ids, err := cs.queryNodes(func(n node) bool { return n.URL == url }, 0, true) +func (cs *Storage) InsertIfNew(url string, specific bool) error { + ids, err := cs.queryNodes(func(n node) bool { return n.URL == url }, 0, false) if err != nil { return err } + tableName := nodesTableName + if specific { + tableName = specificNodesTableName + } if len(ids) == 0 { - id, err := cs.db.Insert(specificNodesTableName, &node{Node: entities.Node{ + id, err := cs.db.Insert(tableName, &node{Node: entities.Node{ URL: url, Enabled: true, }}) @@ -171,7 +196,7 @@ func (cs *Storage) populate(nodes string) error { if err != nil { return err } - err = cs.InsertIfNew(url) + err = cs.InsertIfNew(url, false) if err != nil { return err } From 8e8bab07a1082c0fe03001557551eb626a58332b Mon Sep 17 00:00:00 2001 From: esuwu Date: Sun, 15 Jan 2023 19:46:54 -0600 Subject: [PATCH 02/20] Added aliases to alerts --- cmd/bots/internal/common/environment.go | 34 ++++++- .../internal/discord/handlers/handlers.go | 5 + .../internal/telegram/handlers/handlers.go | 13 ++- cmd/nodemon/nodemon.go | 2 +- pkg/messaging/pubsub/server.go | 33 ++++++- pkg/storing/nodes/nodes.go | 95 ++++++++++++++----- 6 files changed, 150 insertions(+), 32 deletions(-) diff --git a/cmd/bots/internal/common/environment.go b/cmd/bots/internal/common/environment.go index 3c11294c..59bfda4f 100644 --- a/cmd/bots/internal/common/environment.go +++ b/cmd/bots/internal/common/environment.go @@ -457,6 +457,10 @@ func ScheduleNodesStatus( zapLogger.Error("failed to schedule nodes status, unknown bot type") return } + msg, err = ReplaceNodesWithAliases(requestType, responsePairType, msg) + if err != nil { + zapLogger.Error("failed to replaces nodes with aliases", zap.Error(err)) + } bot.SendMessage(msg) return } @@ -568,12 +572,38 @@ func HandleNodesStatusError(nodesStatusResp *pair.NodesStatusResponse, extension return fmt.Sprintf("%s\n\n%s", nodesStatusResp.ErrMessage, msg), statusCondition, nil } return nodesStatusResp.ErrMessage, statusCondition, nil + +} + +func ReplaceNodesWithAliases(requestType chan<- pair.RequestPair, + responsePairType <-chan pair.ResponsePair, msg string) (string, error) { + + nodes, err := messaging.RequestFullNodesList(requestType, responsePairType, false) + if err != nil { + return "", err + } + specificNodes, err := messaging.RequestFullNodesList(requestType, responsePairType, true) + if err != nil { + return "", err + } + nodes = append(nodes, specificNodes...) + + for _, n := range nodes { + if n.Alias != "" { + n.URL = strings.ReplaceAll(n.URL, entities.HttpsScheme+"://", "") + n.URL = strings.ReplaceAll(n.URL, entities.HttpScheme+"://", "") + msg = strings.ReplaceAll(msg, n.URL, n.Alias) + } + } + + return msg, nil } -func HandleNodesStatus(nodesStatusResp *pair.NodesStatusResponse, extension expectedExtension) (string, StatusCondition, error) { +func HandleNodesStatus(nodesStatusResp *pair.NodesStatusResponse, + extension expectedExtension) (string, StatusCondition, error) { statusCondition := StatusCondition{AllNodesAreOk: false, NodesNumber: 0, Height: ""} - // remove all https and http prefixes + // remove all https and http prefixes and for i := range nodesStatusResp.NodesStatus { nodesStatusResp.NodesStatus[i].Url = strings.ReplaceAll(nodesStatusResp.NodesStatus[i].Url, entities.HttpsScheme+"://", "") nodesStatusResp.NodesStatus[i].Url = strings.ReplaceAll(nodesStatusResp.NodesStatus[i].Url, entities.HttpScheme+"://", "") diff --git a/cmd/bots/internal/discord/handlers/handlers.go b/cmd/bots/internal/discord/handlers/handlers.go index 9b4d4e59..f343f7f0 100644 --- a/cmd/bots/internal/discord/handlers/handlers.go +++ b/cmd/bots/internal/discord/handlers/handlers.go @@ -55,6 +55,11 @@ func InitDscHandlers(environment *common.DiscordBotEnvironment, requestType chan msg = fmt.Sprintf("%d %s", statusCondition.NodesNumber, msg) } + msg, err = common.ReplaceNodesWithAliases(requestType, responsePairType, msg) + if err != nil { + environment.Zap.Error("failed to replaces nodes with aliases", zap.Error(err)) + } + msg = fmt.Sprintf("```yaml\n%s\n```", msg) _, err = s.ChannelMessageSend(environment.ChatID, msg) if err != nil { diff --git a/cmd/bots/internal/telegram/handlers/handlers.go b/cmd/bots/internal/telegram/handlers/handlers.go index d208e81a..3fd2aef8 100644 --- a/cmd/bots/internal/telegram/handlers/handlers.go +++ b/cmd/bots/internal/telegram/handlers/handlers.go @@ -192,7 +192,12 @@ func InitTgHandlers(environment *common.TelegramBotEnvironment, requestType chan nodes = append(nodes, additionalNodes...) var msg string for _, n := range nodes { - msg += fmt.Sprintf("Node: %s\nAlias: %s\n\n", n.URL, n.Alias) + if n.Alias != "" { + msg += fmt.Sprintf("Node: %s\nAlias: %s\n\n", n.URL, n.Alias) + } + } + if msg == "" { + msg = "No aliases have been found" } return c.Send( @@ -351,6 +356,12 @@ func InitTgHandlers(environment *common.TelegramBotEnvironment, requestType chan msg = fmt.Sprintf("%d %s", statusCondition.NodesNumber, msg) } + msg, err = common.ReplaceNodesWithAliases(requestType, responsePairType, msg) + if err != nil { + environment.Zap.Error("failed to replaces nodes with aliases", zap.Error(err)) + return err + } + return c.Send( msg, &tele.SendOptions{ diff --git a/cmd/nodemon/nodemon.go b/cmd/nodemon/nodemon.go index 6546454c..43eb840c 100644 --- a/cmd/nodemon/nodemon.go +++ b/cmd/nodemon/nodemon.go @@ -177,7 +177,7 @@ func run() error { alerts := analyzer.Start(notifications) go func() { - err := pubsub.StartPubMessagingServer(ctx, nanomsgPubSubURL, alerts, zap) + err := pubsub.StartPubMessagingServer(ctx, nanomsgPubSubURL, alerts, zap, ns) if err != nil { zap.Fatal("failed to start pub messaging server", zapLogger.Error(err)) } diff --git a/pkg/messaging/pubsub/server.go b/pkg/messaging/pubsub/server.go index 05375637..23cb4e2c 100644 --- a/pkg/messaging/pubsub/server.go +++ b/pkg/messaging/pubsub/server.go @@ -13,9 +13,10 @@ import ( "go.uber.org/zap" "nodemon/pkg/entities" "nodemon/pkg/messaging" + "nodemon/pkg/storing/nodes" ) -func StartPubMessagingServer(ctx context.Context, nanomsgURL string, alerts <-chan entities.Alert, logger *zap.Logger) error { +func StartPubMessagingServer(ctx context.Context, nanomsgURL string, alerts <-chan entities.Alert, logger *zap.Logger, ns *nodes.Storage) error { if len(nanomsgURL) == 0 || len(strings.Fields(nanomsgURL)) > 1 { return errors.New("invalid nanomsg IPC URL for pub sub socket") } @@ -41,11 +42,18 @@ func StartPubMessagingServer(ctx context.Context, nanomsgURL string, alerts <-ch case alert := <-alerts: logger.Sugar().Infof("Alert has been generated: %v", alert) + details, err := replaceNodesWithAliases(ns, alert.Message()) + if err != nil { + if err != nil { + logger.Error("Failed to replace nodes with aliases", zap.Error(err)) + } + } + jsonAlert, err := json.Marshal( messaging.Alert{ AlertDescription: alert.ShortDescription(), Level: alert.Level(), - Details: alert.Message(), + Details: details, }) if err != nil { logger.Error("Failed to marshal alert to json", zap.Error(err)) @@ -61,3 +69,24 @@ func StartPubMessagingServer(ctx context.Context, nanomsgURL string, alerts <-ch } } } + +func replaceNodesWithAliases(ns *nodes.Storage, message string) (string, error) { + nodes, err := ns.Nodes(false) + if err != nil { + return "", err + } + specificNodes, err := ns.Nodes(true) + if err != nil { + return "", err + } + nodes = append(nodes, specificNodes...) + + for _, n := range nodes { + if n.Alias != "" { + n.URL = strings.ReplaceAll(n.URL, entities.HttpsScheme+"://", "") + n.URL = strings.ReplaceAll(n.URL, entities.HttpScheme+"://", "") + message = strings.ReplaceAll(message, n.URL, n.Alias) + } + } + return message, nil +} diff --git a/pkg/storing/nodes/nodes.go b/pkg/storing/nodes/nodes.go index 57e4fb8b..ce0560d4 100644 --- a/pkg/storing/nodes/nodes.go +++ b/pkg/storing/nodes/nodes.go @@ -16,21 +16,21 @@ const ( specificNodesTableName = "specific_nodes" ) -type node struct { +type nodeRecord struct { ID int `json:"id"` entities.Node } -func (n *node) GetID() int { +func (n *nodeRecord) GetID() int { return n.ID } -func (n *node) SetID(id int) { +func (n *nodeRecord) SetID(id int) { n.ID = id } // AfterFind required by Hare function. Don't ask why. -func (n *node) AfterFind(_ *hare.Database) error { +func (n *nodeRecord) AfterFind(_ *hare.Database) error { return nil } @@ -71,58 +71,70 @@ func (cs *Storage) Close() error { } func (cs *Storage) Nodes(specific bool) ([]entities.Node, error) { - return cs.queryNodes(func(_ node) bool { return true }, 0, specific) + nodesRecord, err := cs.queryNodes(func(_ nodeRecord) bool { return true }, 0, specific) + if err != nil { + return nil, err + } + return nodesFromRecords(nodesRecord), nil } func (cs *Storage) EnabledNodes() ([]entities.Node, error) { - return cs.queryNodes(func(n node) bool { return n.Enabled }, 0, false) + nodesRecords, err := cs.queryNodes(func(n nodeRecord) bool { return n.Enabled }, 0, false) + if err != nil { + return nil, err + } + return nodesFromRecords(nodesRecords), nil } func (cs *Storage) EnabledSpecificNodes() ([]entities.Node, error) { - return cs.queryNodes(func(n node) bool { return n.Enabled }, 0, true) + nodesRecords, err := cs.queryNodes(func(n nodeRecord) bool { return n.Enabled }, 0, true) + if err != nil { + return nil, err + } + return nodesFromRecords(nodesRecords), nil } // Update handles both specific and non-specific nodes func (cs *Storage) Update(nodeToUpdate entities.Node) error { specific := false - ids, err := cs.queryNodes(func(n node) bool { return n.URL == nodeToUpdate.URL }, 0, false) + ids, err := cs.queryNodes(func(n nodeRecord) bool { return n.URL == nodeToUpdate.URL }, 0, false) if err != nil { return err } if len(ids) == 0 { // look for the url in the specific nodes table - ids, err = cs.queryNodes(func(n node) bool { return n.URL == nodeToUpdate.URL }, 0, true) + ids, err = cs.queryNodes(func(n nodeRecord) bool { return n.URL == nodeToUpdate.URL }, 0, true) if err != nil { return err } specific = true if len(ids) == 0 { - return errors.Errorf("node %s was not found in the storage", nodeToUpdate.URL) + return errors.Errorf("nodeRecord %s was not found in the storage", nodeToUpdate.URL) } } - if len(ids) > 1 { - return errors.Errorf("failed to update a node in the storage, multiple nodes were found") + if len(ids) != 1 { + return errors.Errorf("failed to update a nodeRecord in the storage, multiple nodes were found") } tableName := nodesTableName if specific { tableName = specificNodesTableName } - pulledNode := ids[0] - err = cs.db.Update(tableName, &node{Node: entities.Node{ - URL: pulledNode.URL, - Enabled: pulledNode.Enabled, + pulledRecord := ids[0] + err = cs.db.Update(tableName, &nodeRecord{Node: entities.Node{ + URL: pulledRecord.URL, + Enabled: pulledRecord.Enabled, Alias: nodeToUpdate.Alias, - }}) + }, ID: pulledRecord.ID}) if err != nil { return err } - cs.zap.Sugar().Infof("New node '%s' was updated with alias %s", pulledNode.URL, nodeToUpdate.Alias) + cs.zap.Sugar().Infof("New nodeRecord '%s' was updated with alias %s", pulledRecord.URL, nodeToUpdate.Alias) return nil } func (cs *Storage) InsertIfNew(url string, specific bool) error { - ids, err := cs.queryNodes(func(n node) bool { return n.URL == url }, 0, false) + ids, err := cs.queryNodes(func(n nodeRecord) bool { return n.URL == url }, 0, false) if err != nil { return err } @@ -131,14 +143,14 @@ func (cs *Storage) InsertIfNew(url string, specific bool) error { tableName = specificNodesTableName } if len(ids) == 0 { - id, err := cs.db.Insert(tableName, &node{Node: entities.Node{ + id, err := cs.db.Insert(tableName, &nodeRecord{Node: entities.Node{ URL: url, Enabled: true, }}) if err != nil { return err } - cs.zap.Sugar().Infof("New node #%d at '%s' was stored", id, url) + cs.zap.Sugar().Infof("New nodeRecord #%d at '%s' was stored", id, url) } return nil } @@ -149,7 +161,7 @@ func (cs *Storage) Delete(url string) error { return err } for _, id := range ids { - var n node + var n nodeRecord if err := cs.db.Find(nodesTableName, id, &n); err != nil { return err } @@ -166,23 +178,46 @@ func (cs *Storage) Delete(url string) error { return nil } -func (cs *Storage) queryNodes(queryFn func(n node) bool, limit int, specific bool) ([]entities.Node, error) { +func (cs *Storage) FindAlias(url string) (string, error) { + ids, err := cs.queryNodes(func(n nodeRecord) bool { return n.URL == url }, 0, false) + if err != nil { + return "", err + } + if len(ids) == 0 { + // look for the url in the specific nodes table + ids, err = cs.queryNodes(func(n nodeRecord) bool { return n.URL == url }, 0, true) + if err != nil { + return "", err + } + if len(ids) == 0 { + return "", errors.Errorf("nodeRecord %s was not found in the storage", url) + } + } + if len(ids) != 1 { + return "", errors.Errorf("failed to update a nodeRecord in the storage, multiple nodes were found") + } + + return ids[0].Alias, nil +} + +func (cs *Storage) queryNodes(queryFn func(n nodeRecord) bool, limit int, specific bool) ([]nodeRecord, error) { table := nodesTableName if specific { table = specificNodesTableName } - var results []entities.Node + var results []nodeRecord ids, err := cs.db.IDs(table) if err != nil { return nil, err } for _, id := range ids { - var n node + var n nodeRecord if err := cs.db.Find(table, id, &n); err != nil { return nil, err } if queryFn(n) { - results = append(results, n.Node) + n.ID = id + results = append(results, n) } if limit != 0 && limit == len(results) { break @@ -203,3 +238,11 @@ func (cs *Storage) populate(nodes string) error { } return nil } + +func nodesFromRecords(records []nodeRecord) []entities.Node { + var nodes []entities.Node + for _, r := range records { + nodes = append(nodes, r.Node) + } + return nodes +} From 432ed861bf97ca9e7651dc0a58889ce8ded055f6 Mon Sep 17 00:00:00 2001 From: esuwu Date: Sun, 15 Jan 2023 19:49:55 -0600 Subject: [PATCH 03/20] Added help message --- cmd/bots/internal/telegram/messages/base_messages.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmd/bots/internal/telegram/messages/base_messages.go b/cmd/bots/internal/telegram/messages/base_messages.go index f5d10f94..60261e11 100644 --- a/cmd/bots/internal/telegram/messages/base_messages.go +++ b/cmd/bots/internal/telegram/messages/base_messages.go @@ -16,7 +16,9 @@ const ( "/add node - to add a node to the list\n" + "/remove node - to remove a node from the list\n" + "/subscribe alert name - to subscribe to a specific alert\n" + - "/unsubscribe alert name - to unsubscribe from a specific alert" + "/unsubscribe alert name - to unsubscribe from a specific alert" + + "/add_alias node alias" + + "/aliases - to see the matching list with aliases" MuteText = "Say no more..." + messages.SleepingMsg PongText = "Pong!" + messages.PongMsg From 038c49b49fb59e57c5f687de2cc88eeafa66aebb Mon Sep 17 00:00:00 2001 From: esuwu Date: Thu, 19 Jan 2023 02:52:16 -0600 Subject: [PATCH 04/20] Added alerts templates --- cmd/bots/internal/common/environment.go | 201 +++++++++++++++--- .../common/templates/{ => alerts}/alert.html | 0 .../common/templates/{ => alerts}/alert.md | 0 .../common/templates/alerts/alert_fixed.html | 5 + .../templates/alerts/base_target_alert.html | 11 + .../common/templates/alerts/height_alert.html | 21 ++ .../templates/alerts/incomplete_alert.html | 5 + .../alerts/internal_error_alert.html | 5 + .../alerts/invalid_height_alert.html | 5 + .../templates/alerts/state_hash_alert.html | 31 +++ .../templates/alerts/unreachable_alert.html | 5 + pkg/messaging/pubsub/server.go | 84 +++++--- 12 files changed, 310 insertions(+), 63 deletions(-) rename cmd/bots/internal/common/templates/{ => alerts}/alert.html (100%) rename cmd/bots/internal/common/templates/{ => alerts}/alert.md (100%) create mode 100644 cmd/bots/internal/common/templates/alerts/alert_fixed.html create mode 100644 cmd/bots/internal/common/templates/alerts/base_target_alert.html create mode 100644 cmd/bots/internal/common/templates/alerts/height_alert.html create mode 100644 cmd/bots/internal/common/templates/alerts/incomplete_alert.html create mode 100644 cmd/bots/internal/common/templates/alerts/internal_error_alert.html create mode 100644 cmd/bots/internal/common/templates/alerts/invalid_height_alert.html create mode 100644 cmd/bots/internal/common/templates/alerts/state_hash_alert.html create mode 100644 cmd/bots/internal/common/templates/alerts/unreachable_alert.html diff --git a/cmd/bots/internal/common/environment.go b/cmd/bots/internal/common/environment.go index 59bfda4f..c008edac 100644 --- a/cmd/bots/internal/common/environment.go +++ b/cmd/bots/internal/common/environment.go @@ -528,6 +528,171 @@ func executeTemplate(template string, data any, extension expectedExtension) (st } +func executeAlertTemplate(alertType entities.AlertType, alertJson []byte, extension expectedExtension) (string, error) { + //alert.Details = strings.ReplaceAll(alert.Details, entities.HttpScheme+"://", "") + //alert.Details = strings.ReplaceAll(alert.Details, entities.HttpsScheme+"://", "") + var msg string + switch alertType { + case entities.UnreachableAlertType: + var unreachableAlert entities.UnreachableAlert + err := json.Unmarshal(alertJson, &unreachableAlert) + if err != nil { + return "", err + } + + // TODO replace node name with an alias + + msg, err = executeTemplate("templates/alerts/unreachable_alert", unreachableAlert, extension) + if err != nil { + return "", err + } + case entities.IncompleteAlertType: + var incompleteAlert entities.IncompleteAlert + err := json.Unmarshal(alertJson, &incompleteAlert) + if err != nil { + return "", err + } + incompleteStatement := incompleteAlert.NodeStatement + + // TODO replace node name with an alias + + msg, err = executeTemplate("templates/alerts/incomplete_alert", incompleteStatement, extension) + if err != nil { + return "", err + } + case entities.InvalidHeightAlertType: + var invalidHeightAlert entities.InvalidHeightAlert + err := json.Unmarshal(alertJson, &invalidHeightAlert) + if err != nil { + return "", err + } + invalidHeightStatement := invalidHeightAlert.NodeStatement + + // TODO replace node name with an alias + + msg, err = executeTemplate("templates/alerts/invalid_height_alert", invalidHeightStatement, extension) + if err != nil { + return "", err + } + case entities.HeightAlertType: + var heightAlert entities.HeightAlert + err := json.Unmarshal(alertJson, &heightAlert) + if err != nil { + return "", err + } + type group struct { + Nodes []string + Height int + } + heightStatement := struct { + HeightDifference int + FirstGroup group + SecondGroup group + }{ + HeightDifference: heightAlert.MaxHeightGroup.Height - heightAlert.OtherHeightGroup.Height, + FirstGroup: group{ + Nodes: heightAlert.MaxHeightGroup.Nodes, + Height: heightAlert.MaxHeightGroup.Height, + }, + SecondGroup: group{ + Nodes: heightAlert.OtherHeightGroup.Nodes, + Height: heightAlert.OtherHeightGroup.Height, + }, + } + + msg, err = executeTemplate("templates/alerts/height_alert", heightStatement, extension) + if err != nil { + return "", err + } + case entities.StateHashAlertType: + var stateHashAlert entities.StateHashAlert + err := json.Unmarshal(alertJson, &stateHashAlert) + if err != nil { + return "", err + } + type stateHashGroup struct { + BlockID string + Nodes []string + StateHash string + } + stateHashStatement := struct { + SameHeight int + LastCommonStateHashExist bool + ForkHeight int + ForkBlockID string + ForkStateHash string + + FirstGroup stateHashGroup + SecondGroup stateHashGroup + }{ + SameHeight: stateHashAlert.CurrentGroupsBucketHeight, + LastCommonStateHashExist: stateHashAlert.LastCommonStateHashExist, + ForkHeight: stateHashAlert.LastCommonStateHashHeight, + ForkBlockID: stateHashAlert.LastCommonStateHash.BlockID.String(), + ForkStateHash: stateHashAlert.LastCommonStateHash.SumHash.Hex(), + + FirstGroup: stateHashGroup{ + BlockID: stateHashAlert.FirstGroup.StateHash.BlockID.String(), + Nodes: stateHashAlert.FirstGroup.Nodes, + StateHash: stateHashAlert.FirstGroup.StateHash.SumHash.Hex(), + }, + SecondGroup: stateHashGroup{ + BlockID: stateHashAlert.SecondGroup.StateHash.BlockID.String(), + Nodes: stateHashAlert.SecondGroup.Nodes, + StateHash: stateHashAlert.SecondGroup.StateHash.SumHash.Hex(), + }, + } + + msg, err = executeTemplate("templates/alerts/state_hash_alert", stateHashStatement, extension) + if err != nil { + return "", err + } + case entities.AlertFixedType: + var alertFixed entities.AlertFixed + err := json.Unmarshal(alertJson, &alertFixed) + if err != nil { + return "", err + } + + fixedStatement := struct { + PreviousAlert string + }{ + PreviousAlert: alertFixed.Fixed.Message(), + } + + msg, err = executeTemplate("templates/alerts/alert_fixed", fixedStatement, extension) + if err != nil { + return "", err + } + case entities.BaseTargetAlertType: + var baseTargetAlert entities.BaseTargetAlert + err := json.Unmarshal(alertJson, &baseTargetAlert) + if err != nil { + return "", err + } + + msg, err = executeTemplate("templates/alerts/base_target_alert", baseTargetAlert, extension) + if err != nil { + return "", err + } + case entities.InternalErrorAlertType: + var internalErrorAlert entities.InternalErrorAlert + err := json.Unmarshal(alertJson, &internalErrorAlert) + if err != nil { + return "", err + } + msg, err = executeTemplate("templates/alerts/internal_error_alert", internalErrorAlert, extension) + if err != nil { + return "", err + } + default: + return "", errors.New("unknown alert type") + } + + return msg, nil + +} + type StatusCondition struct { AllNodesAreOk bool NodesNumber int @@ -708,44 +873,14 @@ func constructMessage(alertType entities.AlertType, alertJson []byte, extension return "", errors.Wrap(err, "failed to unmarshal json") } - prettyAlert := makeMessagePretty(alertType, alert) - - msg, err := executeTemplate("templates/alert", prettyAlert, extension) + //prettyAlert := makeMessagePretty(alertType, alert) // executeAlertTemplate + msg, err := executeAlertTemplate(alertType, alertJson, extension) if err != nil { - return "", err + return "", errors.Errorf("failed to execute an alert template, %v", err) } return msg, nil } -func makeMessagePretty(alertType entities.AlertType, alert generalMessaging.Alert) generalMessaging.Alert { - alert.Details = strings.ReplaceAll(alert.Details, entities.HttpScheme+"://", "") - alert.Details = strings.ReplaceAll(alert.Details, entities.HttpsScheme+"://", "") - // simple alert is skipped because it needs to be deleted - switch alertType { - case entities.UnreachableAlertType, entities.InvalidHeightAlertType, entities.StateHashAlertType, entities.HeightAlertType: - alert.AlertDescription += fmt.Sprintf(" %s", commonMessages.ErrorOrDeleteMsg) - case entities.InternalErrorAlertType: - alert.AlertDescription += fmt.Sprintf(" %s", commonMessages.WarnMsg) - case entities.IncompleteAlertType: - alert.AlertDescription += fmt.Sprintf(" %s", commonMessages.QuestionMsg) - case entities.AlertFixedType: - alert.AlertDescription += fmt.Sprintf(" %s", commonMessages.OkMsg) - default: - - } - switch alert.Level { - case entities.InfoLevel: - alert.Level += fmt.Sprintf(" %s", commonMessages.InfoMsg) - case entities.WarnLevel: - alert.Level += fmt.Sprintf(" %s", commonMessages.WarnMsg) - case entities.ErrorLevel: - alert.Level += fmt.Sprintf(" %s", commonMessages.ErrorOrDeleteMsg) - default: - } - - return alert -} - func FindAlertTypeByName(alertName string) (entities.AlertType, bool) { for key, val := range entities.AlertTypes { if val == alertName { diff --git a/cmd/bots/internal/common/templates/alert.html b/cmd/bots/internal/common/templates/alerts/alert.html similarity index 100% rename from cmd/bots/internal/common/templates/alert.html rename to cmd/bots/internal/common/templates/alerts/alert.html diff --git a/cmd/bots/internal/common/templates/alert.md b/cmd/bots/internal/common/templates/alerts/alert.md similarity index 100% rename from cmd/bots/internal/common/templates/alert.md rename to cmd/bots/internal/common/templates/alerts/alert.md diff --git a/cmd/bots/internal/common/templates/alerts/alert_fixed.html b/cmd/bots/internal/common/templates/alerts/alert_fixed.html new file mode 100644 index 00000000..3277b07c --- /dev/null +++ b/cmd/bots/internal/common/templates/alerts/alert_fixed.html @@ -0,0 +1,5 @@ +Alert type: Resolved ✅ + +Level: Info ℹ + +Details: The issue has been resolved: {{ .PreviousAlert}} diff --git a/cmd/bots/internal/common/templates/alerts/base_target_alert.html b/cmd/bots/internal/common/templates/alerts/base_target_alert.html new file mode 100644 index 00000000..34432a1a --- /dev/null +++ b/cmd/bots/internal/common/templates/alerts/base_target_alert.html @@ -0,0 +1,11 @@ +Alert type: Base Target + +Level: Error ❌ + +Details: Base target is greater than the threshold value. The threshold value is {{ .Threshold}} + +{{ with .BaseTargetValues }} +{{range .}} + Node: {{ .Node}} + Base Target: {{ .BaseTarget}} +{{end}} diff --git a/cmd/bots/internal/common/templates/alerts/height_alert.html b/cmd/bots/internal/common/templates/alerts/height_alert.html new file mode 100644 index 00000000..9d8356d3 --- /dev/null +++ b/cmd/bots/internal/common/templates/alerts/height_alert.html @@ -0,0 +1,21 @@ +Alert type: Height ❌ + +Level: Error ❌ + +Details: Some node(s) are {{ .HeightDifference}} blocks behind + +{{ with .FirstGroup }} +First group wih height {{ .Height}}: + +{{range .Nodes}} +Node: {{.}} +{{end}} +{{end}} + +{{ with .SecondGroup }} +Second group wih height {{ .Height}}: + +{{range .Nodes}} +Node: {{.}} +{{end}} +{{end}} diff --git a/cmd/bots/internal/common/templates/alerts/incomplete_alert.html b/cmd/bots/internal/common/templates/alerts/incomplete_alert.html new file mode 100644 index 00000000..266f1b2c --- /dev/null +++ b/cmd/bots/internal/common/templates/alerts/incomplete_alert.html @@ -0,0 +1,5 @@ +Alert type: Incomplete ❔ + +Level: Warning ❗ + +Details: Incomplete statement for node {{ .Node}} {{ .Version}} at height {{ .Height}} diff --git a/cmd/bots/internal/common/templates/alerts/internal_error_alert.html b/cmd/bots/internal/common/templates/alerts/internal_error_alert.html new file mode 100644 index 00000000..979491fa --- /dev/null +++ b/cmd/bots/internal/common/templates/alerts/internal_error_alert.html @@ -0,0 +1,5 @@ +Alert type: InternalErrorAlert ❗️ + +Level: Warning ❗ + +Details: An internal error has occurred: {{ .Error}} diff --git a/cmd/bots/internal/common/templates/alerts/invalid_height_alert.html b/cmd/bots/internal/common/templates/alerts/invalid_height_alert.html new file mode 100644 index 00000000..755cc9fe --- /dev/null +++ b/cmd/bots/internal/common/templates/alerts/invalid_height_alert.html @@ -0,0 +1,5 @@ +Alert type: Invalid Height ❌ + +Level: Warning ❗ + +Details: Node {{ .Node}} {{ .Version}} has an invalid height {{ .Height}} diff --git a/cmd/bots/internal/common/templates/alerts/state_hash_alert.html b/cmd/bots/internal/common/templates/alerts/state_hash_alert.html new file mode 100644 index 00000000..f3beb356 --- /dev/null +++ b/cmd/bots/internal/common/templates/alerts/state_hash_alert.html @@ -0,0 +1,31 @@ +Alert type: State Hash ❌ + +Level: Error ❌ + +Details: Nodes have different state hashes at the same height {{ .SameHeight}} + +{{ with .FirstGroup }} +First group: +BlockID: {{ .BlockID}} +State Hash: {{ .StateHash}} + +{{range .Nodes}} +{{.}} +{{end}} +{{end}} + +{{ with .SecondGroup }} +Second group: +BlockID: {{ .BlockID}} +State Hash: {{ .StateHash}} + +{{range .Nodes}} +{{.}} +{{end}} +{{end}} + +{{ if .LastCommonStateHashExist }} +Fork occurred after block {{ .ForkHeight}} +BlockID: {{ .ForkBlockID}} +State Hash: {{ .ForkStateHash}} +{{ end }} \ No newline at end of file diff --git a/cmd/bots/internal/common/templates/alerts/unreachable_alert.html b/cmd/bots/internal/common/templates/alerts/unreachable_alert.html new file mode 100644 index 00000000..e00d9cfd --- /dev/null +++ b/cmd/bots/internal/common/templates/alerts/unreachable_alert.html @@ -0,0 +1,5 @@ +Alert type: Unreachable ❌ + +Level: Error ❌ + +Details: Node {{ .Node}} is unreachable diff --git a/pkg/messaging/pubsub/server.go b/pkg/messaging/pubsub/server.go index 23cb4e2c..a1aca27e 100644 --- a/pkg/messaging/pubsub/server.go +++ b/pkg/messaging/pubsub/server.go @@ -12,7 +12,6 @@ import ( _ "go.nanomsg.org/mangos/v3/transport/all" "go.uber.org/zap" "nodemon/pkg/entities" - "nodemon/pkg/messaging" "nodemon/pkg/storing/nodes" ) @@ -42,19 +41,15 @@ func StartPubMessagingServer(ctx context.Context, nanomsgURL string, alerts <-ch case alert := <-alerts: logger.Sugar().Infof("Alert has been generated: %v", alert) - details, err := replaceNodesWithAliases(ns, alert.Message()) - if err != nil { - if err != nil { - logger.Error("Failed to replace nodes with aliases", zap.Error(err)) - } - } + // TODO remove this + //details, err := replaceNodesWithAliases(ns, alert.Message()) + //if err != nil { + // if err != nil { + // logger.Error("Failed to replace nodes with aliases", zap.Error(err)) + // } + //} - jsonAlert, err := json.Marshal( - messaging.Alert{ - AlertDescription: alert.ShortDescription(), - Level: alert.Level(), - Details: details, - }) + jsonAlert, err := AlertToJson(alert) if err != nil { logger.Error("Failed to marshal alert to json", zap.Error(err)) } @@ -70,23 +65,52 @@ func StartPubMessagingServer(ctx context.Context, nanomsgURL string, alerts <-ch } } -func replaceNodesWithAliases(ns *nodes.Storage, message string) (string, error) { - nodes, err := ns.Nodes(false) - if err != nil { - return "", err - } - specificNodes, err := ns.Nodes(true) - if err != nil { - return "", err - } - nodes = append(nodes, specificNodes...) - - for _, n := range nodes { - if n.Alias != "" { - n.URL = strings.ReplaceAll(n.URL, entities.HttpsScheme+"://", "") - n.URL = strings.ReplaceAll(n.URL, entities.HttpScheme+"://", "") - message = strings.ReplaceAll(message, n.URL, n.Alias) +func AlertToJson(alert entities.Alert) ([]byte, error) { + var jsonAlert []byte + var err error + switch a := alert.(type) { + case *entities.UnreachableAlert: + jsonAlert, err = json.Marshal(a) + if err != nil { + return nil, err + } + case *entities.IncompleteAlert: + jsonAlert, err = json.Marshal(a) + if err != nil { + return nil, err + } + case *entities.InvalidHeightAlert: + jsonAlert, err = json.Marshal(a) + if err != nil { + return nil, err + } + case *entities.HeightAlert: + jsonAlert, err = json.Marshal(a) + if err != nil { + return nil, err + } + case *entities.StateHashAlert: + jsonAlert, err = json.Marshal(a) + if err != nil { + return nil, err + } + case *entities.AlertFixed: + jsonAlert, err = json.Marshal(a) + if err != nil { + return nil, err + } + case *entities.BaseTargetAlert: + jsonAlert, err = json.Marshal(a) + if err != nil { + return nil, err + } + case *entities.InternalErrorAlert: + jsonAlert, err = json.Marshal(a) + if err != nil { + return nil, err } + default: + return nil, errors.New("unknown alert type") } - return message, nil + return jsonAlert, nil } From 732c8cd76e8e7988b0a7bb7aa4b5cbd7fc1d4e3f Mon Sep 17 00:00:00 2001 From: esuwu Date: Sat, 21 Jan 2023 21:14:32 -0600 Subject: [PATCH 05/20] Added templates for discord alerts --- cmd/bots/discord/discord.go | 8 +- cmd/bots/internal/common/environment.go | 165 +++++++++++------- cmd/bots/internal/common/init/init.go | 9 +- .../common/templates/alerts/alert.html | 5 - .../internal/common/templates/alerts/alert.md | 7 - .../common/templates/alerts/alert_fixed.md | 7 + .../templates/alerts/base_target_alert.md | 13 ++ .../common/templates/alerts/height_alert.html | 10 +- .../common/templates/alerts/height_alert.md | 23 +++ .../templates/alerts/incomplete_alert.md | 7 + .../templates/alerts/internal_error_alert.md | 7 + .../alerts/invalid_height_alert.html | 2 +- .../templates/alerts/invalid_height_alert.md | 7 + .../templates/alerts/state_hash_alert.md | 33 ++++ .../templates/alerts/unreachable_alert.md | 7 + .../internal/discord/handlers/handlers.go | 18 +- .../internal/telegram/handlers/handlers.go | 18 +- cmd/bots/telegram/telegram.go | 7 +- pkg/messaging/pubsub/server.go | 8 - 19 files changed, 246 insertions(+), 115 deletions(-) delete mode 100644 cmd/bots/internal/common/templates/alerts/alert.html delete mode 100644 cmd/bots/internal/common/templates/alerts/alert.md create mode 100644 cmd/bots/internal/common/templates/alerts/alert_fixed.md create mode 100644 cmd/bots/internal/common/templates/alerts/base_target_alert.md create mode 100644 cmd/bots/internal/common/templates/alerts/height_alert.md create mode 100644 cmd/bots/internal/common/templates/alerts/incomplete_alert.md create mode 100644 cmd/bots/internal/common/templates/alerts/internal_error_alert.md create mode 100644 cmd/bots/internal/common/templates/alerts/invalid_height_alert.md create mode 100644 cmd/bots/internal/common/templates/alerts/state_hash_alert.md create mode 100644 cmd/bots/internal/common/templates/alerts/unreachable_alert.md diff --git a/cmd/bots/discord/discord.go b/cmd/bots/discord/discord.go index c6ad5012..948f29f3 100644 --- a/cmd/bots/discord/discord.go +++ b/cmd/bots/discord/discord.go @@ -68,13 +68,13 @@ func runDiscordBot() error { ctx, done := signal.NotifyContext(context.Background(), os.Interrupt) defer done() - discordBotEnv, err := initial.InitDiscordBot(discordBotToken, discordChatID, zap) + pairRequest := make(chan pairResponses.RequestPair) + pairResponse := make(chan pairResponses.ResponsePair) + + discordBotEnv, err := initial.InitDiscordBot(discordBotToken, discordChatID, zap, pairRequest, pairResponse) if err != nil { return errors.Wrap(err, "failed to init discord bot") } - - pairRequest := make(chan pairResponses.RequestPair) - pairResponse := make(chan pairResponses.ResponsePair) handlers.InitDscHandlers(discordBotEnv, pairRequest, pairResponse) go func() { diff --git a/cmd/bots/internal/common/environment.go b/cmd/bots/internal/common/environment.go index c008edac..928b496c 100644 --- a/cmd/bots/internal/common/environment.go +++ b/cmd/bots/internal/common/environment.go @@ -79,15 +79,18 @@ func (s *subscriptions) MapR(f func()) { } type DiscordBotEnvironment struct { - ChatID string - Bot *discordgo.Session - subSocket protocol.Socket - Subscriptions subscriptions - Zap *zap.Logger + ChatID string + Bot *discordgo.Session + subSocket protocol.Socket + Subscriptions subscriptions + Zap *zap.Logger + requestType chan<- pair.RequestPair + responsePairType <-chan pair.ResponsePair } -func NewDiscordBotEnvironment(bot *discordgo.Session, chatID string, zap *zap.Logger) *DiscordBotEnvironment { - return &DiscordBotEnvironment{Bot: bot, ChatID: chatID, Subscriptions: subscriptions{subs: make(map[entities.AlertType]string), mu: new(sync.RWMutex)}, Zap: zap} +func NewDiscordBotEnvironment(bot *discordgo.Session, chatID string, zap *zap.Logger, requestType chan<- pair.RequestPair, + responsePairType <-chan pair.ResponsePair) *DiscordBotEnvironment { + return &DiscordBotEnvironment{Bot: bot, ChatID: chatID, Subscriptions: subscriptions{subs: make(map[entities.AlertType]string), mu: new(sync.RWMutex)}, Zap: zap, requestType: requestType, responsePairType: responsePairType} } func (dscBot *DiscordBotEnvironment) Start() error { @@ -128,7 +131,18 @@ func (dscBot *DiscordBotEnvironment) SendAlertMessage(msg []byte) { return } - messageToBot, err := constructMessage(alertType, msg[1:], Markdown) + nodes, err := messaging.RequestFullNodesList(dscBot.requestType, dscBot.responsePairType, false) + if err != nil { + dscBot.Zap.Error("failed to request list of nodes", zap.Error(err)) + } + specificNodes, err := messaging.RequestFullNodesList(dscBot.requestType, dscBot.responsePairType, true) + if err != nil { + dscBot.Zap.Error("failed to request list of specific nodes", zap.Error(err)) + } + + nodes = append(nodes, specificNodes...) + + messageToBot, err := constructMessage(alertType, msg[1:], Markdown, nodes) if err != nil { dscBot.Zap.Error("failed to construct message", zap.Error(err)) return @@ -167,16 +181,18 @@ func (dscBot *DiscordBotEnvironment) IsEligibleForAction(chatID string) bool { } type TelegramBotEnvironment struct { - ChatID int64 - Bot *telebot.Bot - Mute bool // If it used elsewhere, should be protected by mutex - subSocket protocol.Socket - subscriptions subscriptions - Zap *zap.Logger + ChatID int64 + Bot *telebot.Bot + Mute bool // If it used elsewhere, should be protected by mutex + subSocket protocol.Socket + subscriptions subscriptions + Zap *zap.Logger + requestType chan<- pair.RequestPair + responsePairType <-chan pair.ResponsePair } -func NewTelegramBotEnvironment(bot *telebot.Bot, chatID int64, mute bool, zap *zap.Logger) *TelegramBotEnvironment { - return &TelegramBotEnvironment{Bot: bot, ChatID: chatID, Mute: mute, subscriptions: subscriptions{subs: make(map[entities.AlertType]string), mu: new(sync.RWMutex)}, Zap: zap} +func NewTelegramBotEnvironment(bot *telebot.Bot, chatID int64, mute bool, zap *zap.Logger, requestType chan<- pair.RequestPair, responsePairType <-chan pair.ResponsePair) *TelegramBotEnvironment { + return &TelegramBotEnvironment{Bot: bot, ChatID: chatID, Mute: mute, subscriptions: subscriptions{subs: make(map[entities.AlertType]string), mu: new(sync.RWMutex)}, Zap: zap, requestType: requestType, responsePairType: responsePairType} } func (tgEnv *TelegramBotEnvironment) Start() error { @@ -218,7 +234,18 @@ func (tgEnv *TelegramBotEnvironment) SendAlertMessage(msg []byte) { return } - messageToBot, err := constructMessage(alertType, msg[1:], Html) + nodes, err := messaging.RequestFullNodesList(tgEnv.requestType, tgEnv.responsePairType, false) + if err != nil { + tgEnv.Zap.Error("failed to request list of nodes", zap.Error(err)) + } + specificNodes, err := messaging.RequestFullNodesList(tgEnv.requestType, tgEnv.responsePairType, true) + if err != nil { + tgEnv.Zap.Error("failed to request list of specific nodes", zap.Error(err)) + } + + nodes = append(nodes, specificNodes...) + + messageToBot, err := constructMessage(alertType, msg[1:], Html, nodes) if err != nil { tgEnv.Zap.Error("failed to construct message", zap.Error(err)) return @@ -398,15 +425,20 @@ func ScheduleNodesStatus( responsePairType <-chan pair.ResponsePair, bot messaging.Bot, zapLogger *zap.Logger) error { _, err := taskScheduler.ScheduleWithCron(func(ctx context.Context) { - urls, err := messaging.RequestNodesList(requestType, responsePairType, false) + nodes, err := messaging.RequestFullNodesList(requestType, responsePairType, false) if err != nil { zapLogger.Error("failed to get nodes list", zap.Error(err)) } - additionalUrls, err := messaging.RequestNodesList(requestType, responsePairType, true) + additionalUrls, err := messaging.RequestFullNodesList(requestType, responsePairType, true) if err != nil { zapLogger.Error("failed to get additional nodes list", zap.Error(err)) } - urls = append(urls, additionalUrls...) + nodes = append(nodes, additionalUrls...) + + urls := make([]string, len(nodes)) + for i := range nodes { + urls[i] = nodes[i].URL + } nodesStatus, err := messaging.RequestNodesStatus(requestType, responsePairType, urls) if err != nil { @@ -417,12 +449,12 @@ func ScheduleNodesStatus( statusCondition := StatusCondition{AllNodesAreOk: false, NodesNumber: 0, Height: ""} switch bot.(type) { case *TelegramBotEnvironment: - handledNodesStatus, statusCondition, err = HandleNodesStatus(nodesStatus, Html) + handledNodesStatus, statusCondition, err = HandleNodesStatus(nodesStatus, Html, nodes) if err != nil { zapLogger.Error("failed to handle nodes status", zap.Error(err)) } case *DiscordBotEnvironment: - handledNodesStatus, statusCondition, err = HandleNodesStatus(nodesStatus, Markdown) + handledNodesStatus, statusCondition, err = HandleNodesStatus(nodesStatus, Markdown, nodes) if err != nil { zapLogger.Error("failed to handle nodes status", zap.Error(err)) } @@ -457,10 +489,6 @@ func ScheduleNodesStatus( zapLogger.Error("failed to schedule nodes status, unknown bot type") return } - msg, err = ReplaceNodesWithAliases(requestType, responsePairType, msg) - if err != nil { - zapLogger.Error("failed to replaces nodes with aliases", zap.Error(err)) - } bot.SendMessage(msg) return } @@ -525,12 +553,24 @@ func executeTemplate(template string, data any, extension expectedExtension) (st default: return "", errors.New("unknown message type to execute a template") } +} +func replaceNodeWithAlias(node string, nodesAlias map[string]string) string { + if alias, ok := nodesAlias[node]; ok { + return alias + } + node = strings.ReplaceAll(node, entities.HttpsScheme+"://", "") + node = strings.ReplaceAll(node, entities.HttpScheme+"://", "") + return node } -func executeAlertTemplate(alertType entities.AlertType, alertJson []byte, extension expectedExtension) (string, error) { - //alert.Details = strings.ReplaceAll(alert.Details, entities.HttpScheme+"://", "") - //alert.Details = strings.ReplaceAll(alert.Details, entities.HttpsScheme+"://", "") +func executeAlertTemplate(alertType entities.AlertType, alertJson []byte, extension expectedExtension, allNodes []entities.Node) (string, error) { + nodesAliases := make(map[string]string) + for _, n := range allNodes { + if n.Alias != "" { + nodesAliases[n.URL] = n.Alias + } + } var msg string switch alertType { case entities.UnreachableAlertType: @@ -540,7 +580,7 @@ func executeAlertTemplate(alertType entities.AlertType, alertJson []byte, extens return "", err } - // TODO replace node name with an alias + unreachableAlert.Node = replaceNodeWithAlias(unreachableAlert.Node, nodesAliases) msg, err = executeTemplate("templates/alerts/unreachable_alert", unreachableAlert, extension) if err != nil { @@ -553,8 +593,7 @@ func executeAlertTemplate(alertType entities.AlertType, alertJson []byte, extens return "", err } incompleteStatement := incompleteAlert.NodeStatement - - // TODO replace node name with an alias + incompleteStatement.Node = replaceNodeWithAlias(incompleteStatement.Node, nodesAliases) msg, err = executeTemplate("templates/alerts/incomplete_alert", incompleteStatement, extension) if err != nil { @@ -568,7 +607,7 @@ func executeAlertTemplate(alertType entities.AlertType, alertJson []byte, extens } invalidHeightStatement := invalidHeightAlert.NodeStatement - // TODO replace node name with an alias + invalidHeightStatement.Node = replaceNodeWithAlias(invalidHeightStatement.Node, nodesAliases) msg, err = executeTemplate("templates/alerts/invalid_height_alert", invalidHeightStatement, extension) if err != nil { @@ -580,6 +619,14 @@ func executeAlertTemplate(alertType entities.AlertType, alertJson []byte, extens if err != nil { return "", err } + + for i := range heightAlert.MaxHeightGroup.Nodes { + heightAlert.MaxHeightGroup.Nodes[i] = replaceNodeWithAlias(heightAlert.MaxHeightGroup.Nodes[i], nodesAliases) + } + for i := range heightAlert.OtherHeightGroup.Nodes { + heightAlert.OtherHeightGroup.Nodes[i] = replaceNodeWithAlias(heightAlert.OtherHeightGroup.Nodes[i], nodesAliases) + } + type group struct { Nodes []string Height int @@ -610,6 +657,13 @@ func executeAlertTemplate(alertType entities.AlertType, alertJson []byte, extens if err != nil { return "", err } + + for i := range stateHashAlert.FirstGroup.Nodes { + stateHashAlert.FirstGroup.Nodes[i] = replaceNodeWithAlias(stateHashAlert.FirstGroup.Nodes[i], nodesAliases) + } + for i := range stateHashAlert.SecondGroup.Nodes { + stateHashAlert.SecondGroup.Nodes[i] = replaceNodeWithAlias(stateHashAlert.SecondGroup.Nodes[i], nodesAliases) + } type stateHashGroup struct { BlockID string Nodes []string @@ -654,6 +708,8 @@ func executeAlertTemplate(alertType entities.AlertType, alertJson []byte, extens return "", err } + // TODO there is no alias here right now, but AlertFixed needs to be changed. Make previous alert to look like a number + fixedStatement := struct { PreviousAlert string }{ @@ -667,6 +723,11 @@ func executeAlertTemplate(alertType entities.AlertType, alertJson []byte, extens case entities.BaseTargetAlertType: var baseTargetAlert entities.BaseTargetAlert err := json.Unmarshal(alertJson, &baseTargetAlert) + + for i := range baseTargetAlert.BaseTargetValues { + baseTargetAlert.BaseTargetValues[i].Node = replaceNodeWithAlias(baseTargetAlert.BaseTargetValues[i].Node, nodesAliases) + } + if err != nil { return "", err } @@ -740,38 +801,18 @@ func HandleNodesStatusError(nodesStatusResp *pair.NodesStatusResponse, extension } -func ReplaceNodesWithAliases(requestType chan<- pair.RequestPair, - responsePairType <-chan pair.ResponsePair, msg string) (string, error) { - - nodes, err := messaging.RequestFullNodesList(requestType, responsePairType, false) - if err != nil { - return "", err - } - specificNodes, err := messaging.RequestFullNodesList(requestType, responsePairType, true) - if err != nil { - return "", err - } - nodes = append(nodes, specificNodes...) +func HandleNodesStatus(nodesStatusResp *pair.NodesStatusResponse, + extension expectedExtension, allNodes []entities.Node) (string, StatusCondition, error) { + statusCondition := StatusCondition{AllNodesAreOk: false, NodesNumber: 0, Height: ""} - for _, n := range nodes { + nodesAliases := make(map[string]string) + for _, n := range allNodes { if n.Alias != "" { - n.URL = strings.ReplaceAll(n.URL, entities.HttpsScheme+"://", "") - n.URL = strings.ReplaceAll(n.URL, entities.HttpScheme+"://", "") - msg = strings.ReplaceAll(msg, n.URL, n.Alias) + nodesAliases[n.URL] = n.Alias } } - - return msg, nil -} - -func HandleNodesStatus(nodesStatusResp *pair.NodesStatusResponse, - extension expectedExtension) (string, StatusCondition, error) { - statusCondition := StatusCondition{AllNodesAreOk: false, NodesNumber: 0, Height: ""} - - // remove all https and http prefixes and for i := range nodesStatusResp.NodesStatus { - nodesStatusResp.NodesStatus[i].Url = strings.ReplaceAll(nodesStatusResp.NodesStatus[i].Url, entities.HttpsScheme+"://", "") - nodesStatusResp.NodesStatus[i].Url = strings.ReplaceAll(nodesStatusResp.NodesStatus[i].Url, entities.HttpScheme+"://", "") + nodesStatusResp.NodesStatus[i].Url = replaceNodeWithAlias(nodesStatusResp.NodesStatus[i].Url, nodesAliases) } if nodesStatusResp.ErrMessage != "" { @@ -866,7 +907,7 @@ func HandleNodeStatement(nodeStatementResp *pair.NodeStatementResponse, extensio return msg, nil } -func constructMessage(alertType entities.AlertType, alertJson []byte, extension expectedExtension) (string, error) { +func constructMessage(alertType entities.AlertType, alertJson []byte, extension expectedExtension, allNodes []entities.Node) (string, error) { alert := generalMessaging.Alert{} err := json.Unmarshal(alertJson, &alert) if err != nil { @@ -874,7 +915,7 @@ func constructMessage(alertType entities.AlertType, alertJson []byte, extension } //prettyAlert := makeMessagePretty(alertType, alert) // executeAlertTemplate - msg, err := executeAlertTemplate(alertType, alertJson, extension) + msg, err := executeAlertTemplate(alertType, alertJson, extension, allNodes) if err != nil { return "", errors.Errorf("failed to execute an alert template, %v", err) } diff --git a/cmd/bots/internal/common/init/init.go b/cmd/bots/internal/common/init/init.go index bd9c4dd3..d02dcd18 100644 --- a/cmd/bots/internal/common/init/init.go +++ b/cmd/bots/internal/common/init/init.go @@ -7,6 +7,7 @@ import ( tele "gopkg.in/telebot.v3" "nodemon/cmd/bots/internal/common" "nodemon/cmd/bots/internal/telegram/config" + "nodemon/pkg/messaging/pair" ) func InitTgBot(behavior string, @@ -15,6 +16,8 @@ func InitTgBot(behavior string, botToken string, chatID int64, logger *zap.Logger, + requestType chan<- pair.RequestPair, + responsePairType <-chan pair.ResponsePair, ) (*common.TelegramBotEnvironment, error) { botSettings, err := config.NewTgBotSettings(behavior, webhookLocalAddress, publicURL, botToken) if err != nil { @@ -27,7 +30,7 @@ func InitTgBot(behavior string, logger.Sugar().Debugf("telegram chat id for sending alerts is %d", chatID) - tgBotEnv := common.NewTelegramBotEnvironment(bot, chatID, false, logger) + tgBotEnv := common.NewTelegramBotEnvironment(bot, chatID, false, logger, requestType, responsePairType) return tgBotEnv, nil } @@ -35,6 +38,8 @@ func InitDiscordBot( botToken string, chatID string, logger *zap.Logger, + requestType chan<- pair.RequestPair, + responsePairType <-chan pair.ResponsePair, ) (*common.DiscordBotEnvironment, error) { bot, err := discordgo.New("Bot " + botToken) if err != nil { @@ -43,6 +48,6 @@ func InitDiscordBot( logger.Sugar().Debugf("discord chat id for sending alerts is %s", chatID) bot.Identify.Intents = discordgo.IntentsGuildMessages | discordgo.IntentsMessageContent - dscBotEnv := common.NewDiscordBotEnvironment(bot, chatID, logger) + dscBotEnv := common.NewDiscordBotEnvironment(bot, chatID, logger, requestType, responsePairType) return dscBotEnv, nil } diff --git a/cmd/bots/internal/common/templates/alerts/alert.html b/cmd/bots/internal/common/templates/alerts/alert.html deleted file mode 100644 index 42c3a667..00000000 --- a/cmd/bots/internal/common/templates/alerts/alert.html +++ /dev/null @@ -1,5 +0,0 @@ -Alert type: {{ .AlertDescription}} - -Level: {{ .Level}} - -Details: {{ .Details}} diff --git a/cmd/bots/internal/common/templates/alerts/alert.md b/cmd/bots/internal/common/templates/alerts/alert.md deleted file mode 100644 index 0d47cf78..00000000 --- a/cmd/bots/internal/common/templates/alerts/alert.md +++ /dev/null @@ -1,7 +0,0 @@ -```yaml -Alert type: {{ .AlertDescription}} - -Level: {{ .Level}} - -Details: {{ .Details}} -``` \ No newline at end of file diff --git a/cmd/bots/internal/common/templates/alerts/alert_fixed.md b/cmd/bots/internal/common/templates/alerts/alert_fixed.md new file mode 100644 index 00000000..c607c8fb --- /dev/null +++ b/cmd/bots/internal/common/templates/alerts/alert_fixed.md @@ -0,0 +1,7 @@ +```yaml +Alert type: Resolved ✅ + +Level: Info ℹ + +Details: The issue has been resolved, {{ .PreviousAlert}} +``` \ No newline at end of file diff --git a/cmd/bots/internal/common/templates/alerts/base_target_alert.md b/cmd/bots/internal/common/templates/alerts/base_target_alert.md new file mode 100644 index 00000000..ec409c1b --- /dev/null +++ b/cmd/bots/internal/common/templates/alerts/base_target_alert.md @@ -0,0 +1,13 @@ +```yaml +Alert type: Base Target + +Level: Error ❌ + +Details: Base target is greater than the threshold value. The threshold value is {{ .Threshold}} + +{{ with .BaseTargetValues }} +{{range .}} +Node: {{ .Node}} +Base Target: {{ .BaseTarget}} + {{end}} +``` \ No newline at end of file diff --git a/cmd/bots/internal/common/templates/alerts/height_alert.html b/cmd/bots/internal/common/templates/alerts/height_alert.html index 9d8356d3..c0515832 100644 --- a/cmd/bots/internal/common/templates/alerts/height_alert.html +++ b/cmd/bots/internal/common/templates/alerts/height_alert.html @@ -5,17 +5,19 @@ Details: Some node(s) are {{ .HeightDifference}} blocks behind {{ with .FirstGroup }} -First group wih height {{ .Height}}: +First group with height {{ .Height}}: {{range .Nodes}} -Node: {{.}} +{{.}} + {{end}} {{end}} {{ with .SecondGroup }} -Second group wih height {{ .Height}}: +Second group with height {{ .Height}}: {{range .Nodes}} -Node: {{.}} +{{.}} + {{end}} {{end}} diff --git a/cmd/bots/internal/common/templates/alerts/height_alert.md b/cmd/bots/internal/common/templates/alerts/height_alert.md new file mode 100644 index 00000000..e2419a36 --- /dev/null +++ b/cmd/bots/internal/common/templates/alerts/height_alert.md @@ -0,0 +1,23 @@ +```yaml +Alert type: Height ❌ + +Level: Error ❌ + +Details: Some node(s) are {{ .HeightDifference}} blocks behind + +{{ with .FirstGroup }} +First group with height {{ .Height}}: + +{{range .Nodes}} +{{.}} +{{end}} +{{end}} + + +{{ with .SecondGroup }} +Second group with height {{ .Height}}: +{{range .Nodes}} +{{.}} +{{end}} +{{end}} +``` \ No newline at end of file diff --git a/cmd/bots/internal/common/templates/alerts/incomplete_alert.md b/cmd/bots/internal/common/templates/alerts/incomplete_alert.md new file mode 100644 index 00000000..f2720499 --- /dev/null +++ b/cmd/bots/internal/common/templates/alerts/incomplete_alert.md @@ -0,0 +1,7 @@ +```yaml +Alert type: Incomplete ❔ + +Level: Warning ❗ + +Details: Incomplete statement for node {{ .Node}} {{ .Version}} at height {{ .Height}} +``` \ No newline at end of file diff --git a/cmd/bots/internal/common/templates/alerts/internal_error_alert.md b/cmd/bots/internal/common/templates/alerts/internal_error_alert.md new file mode 100644 index 00000000..cdbe7849 --- /dev/null +++ b/cmd/bots/internal/common/templates/alerts/internal_error_alert.md @@ -0,0 +1,7 @@ +```yaml +Alert type: InternalErrorAlert ❗️ + +Level: Warning ❗ + +Details: An internal error has occurred, {{ .Error}} +``` \ No newline at end of file diff --git a/cmd/bots/internal/common/templates/alerts/invalid_height_alert.html b/cmd/bots/internal/common/templates/alerts/invalid_height_alert.html index 755cc9fe..4a417fc9 100644 --- a/cmd/bots/internal/common/templates/alerts/invalid_height_alert.html +++ b/cmd/bots/internal/common/templates/alerts/invalid_height_alert.html @@ -2,4 +2,4 @@ Level: Warning ❗ -Details: Node {{ .Node}} {{ .Version}} has an invalid height {{ .Height}} +Details: Node {{ .Node}} {{ .Version}} has an invalid height {{ .Height}} diff --git a/cmd/bots/internal/common/templates/alerts/invalid_height_alert.md b/cmd/bots/internal/common/templates/alerts/invalid_height_alert.md new file mode 100644 index 00000000..4ea640a3 --- /dev/null +++ b/cmd/bots/internal/common/templates/alerts/invalid_height_alert.md @@ -0,0 +1,7 @@ +```yaml +Alert type: Invalid Height ❌ + +Level: Warning ❗ + +Details: Node {{ .Node}} {{ .Version}} has an invalid height {{ .Height}} +``` \ No newline at end of file diff --git a/cmd/bots/internal/common/templates/alerts/state_hash_alert.md b/cmd/bots/internal/common/templates/alerts/state_hash_alert.md new file mode 100644 index 00000000..49670848 --- /dev/null +++ b/cmd/bots/internal/common/templates/alerts/state_hash_alert.md @@ -0,0 +1,33 @@ +```yaml +Alert type: State Hash ❌ + +Level: Error ❌ + +Details: Nodes have different state hashes at the same height {{ .SameHeight}} + +{{ with .FirstGroup }} +BlockID (First group): {{ .BlockID}} +State Hash (First group): {{ .StateHash}} + +{{range .Nodes}} +{{.}} +{{end}} +{{end}} + + +{{ with .SecondGroup }} +BlockID (Second group): {{ .BlockID}} +State Hash (Second group): {{ .StateHash}} + +{{range .Nodes}} +{{.}} +{{end}} +{{end}} + + +{{ if .LastCommonStateHashExist }} +Fork occurred after block {{ .ForkHeight}} +BlockID: {{ .ForkBlockID}} +State Hash: {{ .ForkStateHash}} +{{ end }} +``` \ No newline at end of file diff --git a/cmd/bots/internal/common/templates/alerts/unreachable_alert.md b/cmd/bots/internal/common/templates/alerts/unreachable_alert.md new file mode 100644 index 00000000..417664b1 --- /dev/null +++ b/cmd/bots/internal/common/templates/alerts/unreachable_alert.md @@ -0,0 +1,7 @@ +```yaml +Alert type: Unreachable ❌ + +Level: Error ❌ + +Details: Node {{ .Node}} is unreachable +``` \ No newline at end of file diff --git a/cmd/bots/internal/discord/handlers/handlers.go b/cmd/bots/internal/discord/handlers/handlers.go index f343f7f0..6f3bf3ce 100644 --- a/cmd/bots/internal/discord/handlers/handlers.go +++ b/cmd/bots/internal/discord/handlers/handlers.go @@ -33,21 +33,26 @@ func InitDscHandlers(environment *common.DiscordBotEnvironment, requestType chan } if m.Content == "/status" { - urls, err := messaging.RequestNodesList(requestType, responsePairType, false) + nodes, err := messaging.RequestFullNodesList(requestType, responsePairType, false) if err != nil { environment.Zap.Error("failed to get a list of nodes", zap.Error(err)) } - additionalUrls, err := messaging.RequestNodesList(requestType, responsePairType, true) + additionalUrls, err := messaging.RequestFullNodesList(requestType, responsePairType, true) if err != nil { environment.Zap.Error("failed to get a list of nodes", zap.Error(err)) } - urls = append(urls, additionalUrls...) + nodes = append(nodes, additionalUrls...) + + urls := make([]string, len(nodes)) + for i, n := range nodes { + urls[i] = n.URL + } nodesStatus, err := messaging.RequestNodesStatus(requestType, responsePairType, urls) if err != nil { environment.Zap.Error("failed to request nodes status", zap.Error(err)) } - msg, statusCondition, err := common.HandleNodesStatus(nodesStatus, common.Markdown) + msg, statusCondition, err := common.HandleNodesStatus(nodesStatus, common.Markdown, nodes) if err != nil { environment.Zap.Error("failed to handle nodes status", zap.Error(err)) } @@ -55,11 +60,6 @@ func InitDscHandlers(environment *common.DiscordBotEnvironment, requestType chan msg = fmt.Sprintf("%d %s", statusCondition.NodesNumber, msg) } - msg, err = common.ReplaceNodesWithAliases(requestType, responsePairType, msg) - if err != nil { - environment.Zap.Error("failed to replaces nodes with aliases", zap.Error(err)) - } - msg = fmt.Sprintf("```yaml\n%s\n```", msg) _, err = s.ChannelMessageSend(environment.ChatID, msg) if err != nil { diff --git a/cmd/bots/internal/telegram/handlers/handlers.go b/cmd/bots/internal/telegram/handlers/handlers.go index 3fd2aef8..dee8965f 100644 --- a/cmd/bots/internal/telegram/handlers/handlers.go +++ b/cmd/bots/internal/telegram/handlers/handlers.go @@ -328,17 +328,21 @@ func InitTgHandlers(environment *common.TelegramBotEnvironment, requestType chan }) environment.Bot.Handle("/status", func(c tele.Context) error { - urls, err := messaging.RequestNodesList(requestType, responsePairType, false) + nodes, err := messaging.RequestFullNodesList(requestType, responsePairType, false) if err != nil { environment.Zap.Error("failed to request nodes list buttons", zap.Error(err)) return err } - additionalUrls, err := messaging.RequestNodesList(requestType, responsePairType, true) + additionalUrls, err := messaging.RequestFullNodesList(requestType, responsePairType, true) if err != nil { environment.Zap.Error("failed to request list of specific nodes", zap.Error(err)) return err } - urls = append(urls, additionalUrls...) + nodes = append(nodes, additionalUrls...) + urls := make([]string, len(nodes)) + for i, n := range nodes { + urls[i] = n.URL + } nodesStatus, err := messaging.RequestNodesStatus(requestType, responsePairType, urls) if err != nil { @@ -346,7 +350,7 @@ func InitTgHandlers(environment *common.TelegramBotEnvironment, requestType chan return err } - msg, statusCondition, err := common.HandleNodesStatus(nodesStatus, common.Html) + msg, statusCondition, err := common.HandleNodesStatus(nodesStatus, common.Html, nodes) if err != nil { environment.Zap.Error("failed to handle status of nodes", zap.Error(err)) return err @@ -356,12 +360,6 @@ func InitTgHandlers(environment *common.TelegramBotEnvironment, requestType chan msg = fmt.Sprintf("%d %s", statusCondition.NodesNumber, msg) } - msg, err = common.ReplaceNodesWithAliases(requestType, responsePairType, msg) - if err != nil { - environment.Zap.Error("failed to replaces nodes with aliases", zap.Error(err)) - return err - } - return c.Send( msg, &tele.SendOptions{ diff --git a/cmd/bots/telegram/telegram.go b/cmd/bots/telegram/telegram.go index 71155f3d..e4e73fa5 100644 --- a/cmd/bots/telegram/telegram.go +++ b/cmd/bots/telegram/telegram.go @@ -76,13 +76,14 @@ func runTelegramBot() error { ctx, done := signal.NotifyContext(context.Background(), os.Interrupt) defer done() - tgBotEnv, err := initial.InitTgBot(behavior, webhookLocalAddress, publicURL, tgBotToken, tgChatID, zap) + pairRequest := make(chan pairResponses.RequestPair) + pairResponse := make(chan pairResponses.ResponsePair) + + tgBotEnv, err := initial.InitTgBot(behavior, webhookLocalAddress, publicURL, tgBotToken, tgChatID, zap, pairRequest, pairResponse) if err != nil { zap.Fatal("failed to initialize telegram bot", zapLogger.Error(err)) } - pairRequest := make(chan pairResponses.RequestPair) - pairResponse := make(chan pairResponses.ResponsePair) handlers.InitTgHandlers(tgBotEnv, pairRequest, pairResponse) go func() { diff --git a/pkg/messaging/pubsub/server.go b/pkg/messaging/pubsub/server.go index a1aca27e..907c4882 100644 --- a/pkg/messaging/pubsub/server.go +++ b/pkg/messaging/pubsub/server.go @@ -41,14 +41,6 @@ func StartPubMessagingServer(ctx context.Context, nanomsgURL string, alerts <-ch case alert := <-alerts: logger.Sugar().Infof("Alert has been generated: %v", alert) - // TODO remove this - //details, err := replaceNodesWithAliases(ns, alert.Message()) - //if err != nil { - // if err != nil { - // logger.Error("Failed to replace nodes with aliases", zap.Error(err)) - // } - //} - jsonAlert, err := AlertToJson(alert) if err != nil { logger.Error("Failed to marshal alert to json", zap.Error(err)) From 4ec6c0eb59d9916799bf8683ad8d7e7fe3445c32 Mon Sep 17 00:00:00 2001 From: esuwu Date: Sun, 22 Jan 2023 22:32:39 -0600 Subject: [PATCH 06/20] Improved templates --- .../internal/common/templates/alerts/height_alert.html | 8 ++------ .../common/templates/alerts/state_hash_alert.html | 4 ++-- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/cmd/bots/internal/common/templates/alerts/height_alert.html b/cmd/bots/internal/common/templates/alerts/height_alert.html index c0515832..d2a76f6f 100644 --- a/cmd/bots/internal/common/templates/alerts/height_alert.html +++ b/cmd/bots/internal/common/templates/alerts/height_alert.html @@ -6,18 +6,14 @@ {{ with .FirstGroup }} First group with height {{ .Height}}: - {{range .Nodes}} -{{.}} - +{{.}} {{end}} {{end}} {{ with .SecondGroup }} Second group with height {{ .Height}}: - {{range .Nodes}} -{{.}} - +{{.}} {{end}} {{end}} diff --git a/cmd/bots/internal/common/templates/alerts/state_hash_alert.html b/cmd/bots/internal/common/templates/alerts/state_hash_alert.html index f3beb356..9e1eae62 100644 --- a/cmd/bots/internal/common/templates/alerts/state_hash_alert.html +++ b/cmd/bots/internal/common/templates/alerts/state_hash_alert.html @@ -8,7 +8,7 @@ First group: BlockID: {{ .BlockID}} State Hash: {{ .StateHash}} - +Nodes: {{range .Nodes}} {{.}} {{end}} @@ -18,7 +18,7 @@ Second group: BlockID: {{ .BlockID}} State Hash: {{ .StateHash}} - +Nodes: {{range .Nodes}} {{.}} {{end}} From a2d223d13d17cd3ffc6b6f4929186231abe14343 Mon Sep 17 00:00:00 2001 From: esuwu Date: Sun, 22 Jan 2023 22:55:17 -0600 Subject: [PATCH 07/20] Fixed review issues --- cmd/bots/discord/discord.go | 2 +- cmd/bots/internal/common/environment.go | 56 ++++++------------- .../internal/common/messaging/handlers.go | 32 +++++++++-- .../internal/discord/handlers/handlers.go | 35 +++++------- .../internal/telegram/handlers/handlers.go | 43 +++----------- cmd/bots/internal/telegram/handlers/text.go | 6 +- .../telegram/messages/error_messages.go | 2 +- pkg/messaging/pair/server.go | 3 +- 8 files changed, 71 insertions(+), 108 deletions(-) diff --git a/cmd/bots/discord/discord.go b/cmd/bots/discord/discord.go index 948f29f3..73188cdd 100644 --- a/cmd/bots/discord/discord.go +++ b/cmd/bots/discord/discord.go @@ -75,7 +75,7 @@ func runDiscordBot() error { if err != nil { return errors.Wrap(err, "failed to init discord bot") } - handlers.InitDscHandlers(discordBotEnv, pairRequest, pairResponse) + handlers.InitDscHandlers(discordBotEnv, pairRequest, pairResponse, zap) go func() { err := pubsub.StartSubMessagingClient(ctx, nanomsgPubSubURL, discordBotEnv, zap) diff --git a/cmd/bots/internal/common/environment.go b/cmd/bots/internal/common/environment.go index 928b496c..10b3bd94 100644 --- a/cmd/bots/internal/common/environment.go +++ b/cmd/bots/internal/common/environment.go @@ -83,21 +83,21 @@ type DiscordBotEnvironment struct { Bot *discordgo.Session subSocket protocol.Socket Subscriptions subscriptions - Zap *zap.Logger + zap *zap.Logger requestType chan<- pair.RequestPair responsePairType <-chan pair.ResponsePair } func NewDiscordBotEnvironment(bot *discordgo.Session, chatID string, zap *zap.Logger, requestType chan<- pair.RequestPair, responsePairType <-chan pair.ResponsePair) *DiscordBotEnvironment { - return &DiscordBotEnvironment{Bot: bot, ChatID: chatID, Subscriptions: subscriptions{subs: make(map[entities.AlertType]string), mu: new(sync.RWMutex)}, Zap: zap, requestType: requestType, responsePairType: responsePairType} + return &DiscordBotEnvironment{Bot: bot, ChatID: chatID, Subscriptions: subscriptions{subs: make(map[entities.AlertType]string), mu: new(sync.RWMutex)}, zap: zap, requestType: requestType, responsePairType: responsePairType} } func (dscBot *DiscordBotEnvironment) Start() error { - dscBot.Zap.Info("Discord bot started") + dscBot.zap.Info("Discord bot started") err := dscBot.Bot.Open() if err != nil { - dscBot.Zap.Error("failed to open discord bot", zap.Error(err)) + dscBot.zap.Error("failed to open discord bot", zap.Error(err)) return err } return nil @@ -110,47 +110,41 @@ func (dscBot *DiscordBotEnvironment) SetSubSocket(subSocket protocol.Socket) { func (dscBot *DiscordBotEnvironment) SendMessage(msg string) { _, err := dscBot.Bot.ChannelMessageSend(dscBot.ChatID, msg) if err != nil { - dscBot.Zap.Error("failed to send a message to discord", zap.Error(err)) + dscBot.zap.Error("failed to send a message to discord", zap.Error(err)) } } func (dscBot *DiscordBotEnvironment) SendAlertMessage(msg []byte) { if len(msg) == 0 { - dscBot.Zap.Error("received empty alert message") + dscBot.zap.Error("received empty alert message") return } alertType := entities.AlertType(msg[0]) _, ok := entities.AlertTypes[alertType] if !ok { - dscBot.Zap.Sugar().Errorf("failed to construct message, unknown alert type %c, %v", byte(alertType), errUnknownAlertType) + dscBot.zap.Sugar().Errorf("failed to construct message, unknown alert type %c, %v", byte(alertType), errUnknownAlertType) _, err := dscBot.Bot.ChannelMessageSend(dscBot.ChatID, errUnknownAlertType.Error()) if err != nil { - dscBot.Zap.Error("failed to send a message to discord", zap.Error(err)) + dscBot.zap.Error("failed to send a message to discord", zap.Error(err)) } return } - nodes, err := messaging.RequestFullNodesList(dscBot.requestType, dscBot.responsePairType, false) - if err != nil { - dscBot.Zap.Error("failed to request list of nodes", zap.Error(err)) - } - specificNodes, err := messaging.RequestFullNodesList(dscBot.requestType, dscBot.responsePairType, true) + nodes, err := messaging.RequestAllNodes(dscBot.requestType, dscBot.responsePairType) if err != nil { - dscBot.Zap.Error("failed to request list of specific nodes", zap.Error(err)) + dscBot.zap.Error("failed to get nodes list", zap.Error(err)) } - nodes = append(nodes, specificNodes...) - messageToBot, err := constructMessage(alertType, msg[1:], Markdown, nodes) if err != nil { - dscBot.Zap.Error("failed to construct message", zap.Error(err)) + dscBot.zap.Error("failed to construct message", zap.Error(err)) return } _, err = dscBot.Bot.ChannelMessageSend(dscBot.ChatID, messageToBot) if err != nil { - dscBot.Zap.Error("failed to send a message to discord", zap.Error(err)) + dscBot.zap.Error("failed to send a message to discord", zap.Error(err)) } } @@ -165,7 +159,7 @@ func (dscBot *DiscordBotEnvironment) SubscribeToAllAlerts() error { return err } dscBot.Subscriptions.Add(alertType, alertName) - dscBot.Zap.Sugar().Infof("subscribed to %s", alertName) + dscBot.zap.Sugar().Infof("subscribed to %s", alertName) } return nil @@ -234,17 +228,11 @@ func (tgEnv *TelegramBotEnvironment) SendAlertMessage(msg []byte) { return } - nodes, err := messaging.RequestFullNodesList(tgEnv.requestType, tgEnv.responsePairType, false) - if err != nil { - tgEnv.Zap.Error("failed to request list of nodes", zap.Error(err)) - } - specificNodes, err := messaging.RequestFullNodesList(tgEnv.requestType, tgEnv.responsePairType, true) + nodes, err := messaging.RequestAllNodes(tgEnv.requestType, tgEnv.responsePairType) if err != nil { - tgEnv.Zap.Error("failed to request list of specific nodes", zap.Error(err)) + tgEnv.Zap.Error("failed to get nodes list", zap.Error(err)) } - nodes = append(nodes, specificNodes...) - messageToBot, err := constructMessage(alertType, msg[1:], Html, nodes) if err != nil { tgEnv.Zap.Error("failed to construct message", zap.Error(err)) @@ -425,20 +413,11 @@ func ScheduleNodesStatus( responsePairType <-chan pair.ResponsePair, bot messaging.Bot, zapLogger *zap.Logger) error { _, err := taskScheduler.ScheduleWithCron(func(ctx context.Context) { - nodes, err := messaging.RequestFullNodesList(requestType, responsePairType, false) + nodes, err := messaging.RequestAllNodes(requestType, responsePairType) if err != nil { zapLogger.Error("failed to get nodes list", zap.Error(err)) } - additionalUrls, err := messaging.RequestFullNodesList(requestType, responsePairType, true) - if err != nil { - zapLogger.Error("failed to get additional nodes list", zap.Error(err)) - } - nodes = append(nodes, additionalUrls...) - - urls := make([]string, len(nodes)) - for i := range nodes { - urls[i] = nodes[i].URL - } + urls := messaging.NodesToUrls(nodes) nodesStatus, err := messaging.RequestNodesStatus(requestType, responsePairType, urls) if err != nil { @@ -914,7 +893,6 @@ func constructMessage(alertType entities.AlertType, alertJson []byte, extension return "", errors.Wrap(err, "failed to unmarshal json") } - //prettyAlert := makeMessagePretty(alertType, alert) // executeAlertTemplate msg, err := executeAlertTemplate(alertType, alertJson, extension, allNodes) if err != nil { return "", errors.Errorf("failed to execute an alert template, %v", err) diff --git a/cmd/bots/internal/common/messaging/handlers.go b/cmd/bots/internal/common/messaging/handlers.go index 2fb7c8a5..76fc38d3 100644 --- a/cmd/bots/internal/common/messaging/handlers.go +++ b/cmd/bots/internal/common/messaging/handlers.go @@ -98,22 +98,19 @@ func RequestNodesStatus( } -func RequestNodesList(requestType chan<- pair.RequestPair, responsePairType <-chan pair.ResponsePair, specific bool) ([]string, error) { +func RequestNodesUrls(requestType chan<- pair.RequestPair, responsePairType <-chan pair.ResponsePair, specific bool) ([]string, error) { requestType <- &pair.NodesListRequest{Specific: specific} responsePair := <-responsePairType nodesList, ok := responsePair.(*pair.NodesListResponse) if !ok { return nil, errors.New("failed to convert response interface to the node list type") } - urls := make([]string, len(nodesList.Nodes)) - for i, n := range nodesList.Nodes { - urls[i] = n.URL - } + urls := NodesToUrls(nodesList.Nodes) sort.Strings(urls) return urls, nil } -func RequestFullNodesList(requestType chan<- pair.RequestPair, responsePairType <-chan pair.ResponsePair, specific bool) ([]entities.Node, error) { +func RequestNodes(requestType chan<- pair.RequestPair, responsePairType <-chan pair.ResponsePair, specific bool) ([]entities.Node, error) { requestType <- &pair.NodesListRequest{Specific: specific} responsePair := <-responsePairType nodesList, ok := responsePair.(*pair.NodesListResponse) @@ -123,6 +120,29 @@ func RequestFullNodesList(requestType chan<- pair.RequestPair, responsePairType return nodesList.Nodes, nil } +func RequestAllNodes(requestType chan<- pair.RequestPair, responsePairType <-chan pair.ResponsePair) ([]entities.Node, error) { + regularNodes, err := RequestNodes(requestType, responsePairType, false) + if err != nil { + return nil, err + } + specificNodes, err := RequestNodes(requestType, responsePairType, true) + if err != nil { + return nil, err + } + var nodes []entities.Node + nodes = append(nodes, regularNodes...) + nodes = append(nodes, specificNodes...) + return nodes, nil +} + +func NodesToUrls(nodes []entities.Node) []string { + urls := make([]string, len(nodes)) + for i, n := range nodes { + urls[i] = n.URL + } + return urls +} + func RequestNodeStatement(requestType chan<- pair.RequestPair, responsePairType <-chan pair.ResponsePair, node string, height int) (*pair.NodeStatementResponse, error) { requestType <- &pair.NodeStatementRequest{Url: node, Height: height} responsePair := <-responsePairType diff --git a/cmd/bots/internal/discord/handlers/handlers.go b/cmd/bots/internal/discord/handlers/handlers.go index 6f3bf3ce..9c9d0e79 100644 --- a/cmd/bots/internal/discord/handlers/handlers.go +++ b/cmd/bots/internal/discord/handlers/handlers.go @@ -13,7 +13,7 @@ import ( "nodemon/pkg/messaging/pair" ) -func InitDscHandlers(environment *common.DiscordBotEnvironment, requestType chan<- pair.RequestPair, responsePairType <-chan pair.ResponsePair) { +func InitDscHandlers(environment *common.DiscordBotEnvironment, requestType chan<- pair.RequestPair, responsePairType <-chan pair.ResponsePair, logger *zap.Logger) { environment.Bot.AddHandler(func(s *discordgo.Session, m *discordgo.MessageCreate) { if m.Author.ID == s.State.User.ID { return @@ -21,40 +21,31 @@ func InitDscHandlers(environment *common.DiscordBotEnvironment, requestType chan if m.Content == "/ping" { _, err := s.ChannelMessageSend(environment.ChatID, "Pong!") if err != nil { - environment.Zap.Error("failed to send a message to discord", zap.Error(err)) + logger.Error("failed to send a message to discord", zap.Error(err)) } } if m.Content == "/help" { _, err := s.ChannelMessageSend(environment.ChatID, messages.HelpInfoText) if err != nil { - environment.Zap.Error("failed to send a message to discord", zap.Error(err)) + logger.Error("failed to send a message to discord", zap.Error(err)) } } if m.Content == "/status" { - nodes, err := messaging.RequestFullNodesList(requestType, responsePairType, false) + nodes, err := messaging.RequestAllNodes(requestType, responsePairType) if err != nil { - environment.Zap.Error("failed to get a list of nodes", zap.Error(err)) - } - additionalUrls, err := messaging.RequestFullNodesList(requestType, responsePairType, true) - if err != nil { - environment.Zap.Error("failed to get a list of nodes", zap.Error(err)) - } - nodes = append(nodes, additionalUrls...) - - urls := make([]string, len(nodes)) - for i, n := range nodes { - urls[i] = n.URL + logger.Error("failed to get nodes list", zap.Error(err)) } + urls := messaging.NodesToUrls(nodes) nodesStatus, err := messaging.RequestNodesStatus(requestType, responsePairType, urls) if err != nil { - environment.Zap.Error("failed to request nodes status", zap.Error(err)) + logger.Error("failed to request nodes status", zap.Error(err)) } msg, statusCondition, err := common.HandleNodesStatus(nodesStatus, common.Markdown, nodes) if err != nil { - environment.Zap.Error("failed to handle nodes status", zap.Error(err)) + logger.Error("failed to handle nodes status", zap.Error(err)) } if statusCondition.AllNodesAreOk { msg = fmt.Sprintf("%d %s", statusCondition.NodesNumber, msg) @@ -63,7 +54,7 @@ func InitDscHandlers(environment *common.DiscordBotEnvironment, requestType chan msg = fmt.Sprintf("```yaml\n%s\n```", msg) _, err = s.ChannelMessageSend(environment.ChatID, msg) if err != nil { - environment.Zap.Error("failed to send a message to discord", zap.Error(err)) + logger.Error("failed to send a message to discord", zap.Error(err)) } } @@ -72,7 +63,7 @@ func InitDscHandlers(environment *common.DiscordBotEnvironment, requestType chan if url == "" { _, err := s.ChannelMessageSend(environment.ChatID, "Please provide a URL to add") if err != nil { - environment.Zap.Error("failed to send a message to discord", zap.Error(err)) + logger.Error("failed to send a message to discord", zap.Error(err)) } return } @@ -80,7 +71,7 @@ func InitDscHandlers(environment *common.DiscordBotEnvironment, requestType chan if err != nil { _, err := s.ChannelMessageSend(environment.ChatID, "Failed to add a node, "+err.Error()) if err != nil { - environment.Zap.Error("failed to send a message to discord", zap.Error(err)) + logger.Error("failed to send a message to discord", zap.Error(err)) } } } @@ -90,7 +81,7 @@ func InitDscHandlers(environment *common.DiscordBotEnvironment, requestType chan if url == "" { _, err := s.ChannelMessageSend(environment.ChatID, "Please provide a URL to remove") if err != nil { - environment.Zap.Error("failed to send a message to discord", zap.Error(err)) + logger.Error("failed to send a message to discord", zap.Error(err)) } return } @@ -98,7 +89,7 @@ func InitDscHandlers(environment *common.DiscordBotEnvironment, requestType chan if err != nil { _, err := s.ChannelMessageSend(environment.ChatID, "Failed to remove a node, "+err.Error()) if err != nil { - environment.Zap.Error("failed to send a message to discord", zap.Error(err)) + logger.Error("failed to send a message to discord", zap.Error(err)) } } } diff --git a/cmd/bots/internal/telegram/handlers/handlers.go b/cmd/bots/internal/telegram/handlers/handlers.go index dee8965f..d5bdd736 100644 --- a/cmd/bots/internal/telegram/handlers/handlers.go +++ b/cmd/bots/internal/telegram/handlers/handlers.go @@ -119,7 +119,7 @@ func InitTgHandlers(environment *common.TelegramBotEnvironment, requestType chan if err != nil { return nil } - urls, err := messaging.RequestNodesList(requestType, responsePairType, false) + urls, err := messaging.RequestNodesUrls(requestType, responsePairType, false) if err != nil { return errors.Wrap(err, "failed to request nodes list buttons") } @@ -159,17 +159,9 @@ func InitTgHandlers(environment *common.TelegramBotEnvironment, requestType chan environment.Bot.Handle("/add_alias", func(c tele.Context) error { args := c.Args() - if len(args) > 2 { + if len(args) != 2 { return c.Send( - messages.RemovedMoreThanOne, - &tele.SendOptions{ - ParseMode: tele.ModeDefault, - }, - ) - } - if len(args) < 1 { - return c.Send( - messages.RemovedLessThanOne, + messages.AliasWrongFormat, &tele.SendOptions{ ParseMode: tele.ModeDefault, }, @@ -179,17 +171,10 @@ func InitTgHandlers(environment *common.TelegramBotEnvironment, requestType chan }) environment.Bot.Handle("/aliases", func(c tele.Context) error { - nodes, err := messaging.RequestFullNodesList(requestType, responsePairType, false) - if err != nil { - environment.Zap.Error("failed to request nodes list buttons", zap.Error(err)) - return err - } - additionalNodes, err := messaging.RequestFullNodesList(requestType, responsePairType, true) + nodes, err := messaging.RequestAllNodes(requestType, responsePairType) if err != nil { - environment.Zap.Error("failed to request list of specific nodes", zap.Error(err)) - return err + environment.Zap.Error("failed to get nodes list", zap.Error(err)) } - nodes = append(nodes, additionalNodes...) var msg string for _, n := range nodes { if n.Alias != "" { @@ -328,21 +313,11 @@ func InitTgHandlers(environment *common.TelegramBotEnvironment, requestType chan }) environment.Bot.Handle("/status", func(c tele.Context) error { - nodes, err := messaging.RequestFullNodesList(requestType, responsePairType, false) - if err != nil { - environment.Zap.Error("failed to request nodes list buttons", zap.Error(err)) - return err - } - additionalUrls, err := messaging.RequestFullNodesList(requestType, responsePairType, true) + nodes, err := messaging.RequestAllNodes(requestType, responsePairType) if err != nil { - environment.Zap.Error("failed to request list of specific nodes", zap.Error(err)) - return err - } - nodes = append(nodes, additionalUrls...) - urls := make([]string, len(nodes)) - for i, n := range nodes { - urls[i] = n.URL + environment.Zap.Error("failed to get nodes list", zap.Error(err)) } + urls := messaging.NodesToUrls(nodes) nodesStatus, err := messaging.RequestNodesStatus(requestType, responsePairType, urls) if err != nil { @@ -376,7 +351,7 @@ func EditPool( requestType chan<- pair.RequestPair, responsePairType <-chan pair.ResponsePair) error { - urls, err := messaging.RequestNodesList(requestType, responsePairType, false) + urls, err := messaging.RequestNodesUrls(requestType, responsePairType, false) if err != nil { return errors.Wrap(err, "failed to request nodes list buttons") } diff --git a/cmd/bots/internal/telegram/handlers/text.go b/cmd/bots/internal/telegram/handlers/text.go index 412648c5..5bf3a891 100644 --- a/cmd/bots/internal/telegram/handlers/text.go +++ b/cmd/bots/internal/telegram/handlers/text.go @@ -34,7 +34,7 @@ func AddNewNodeHandler( if err != nil { return nil } - urls, err := messaging.RequestNodesList(requestType, responsePairType, false) + urls, err := messaging.RequestNodesUrls(requestType, responsePairType, false) if err != nil { return errors.Wrap(err, "failed to request nodes list buttons") } @@ -73,7 +73,7 @@ func RemoveNodeHandler( return err } - urls, err := messaging.RequestNodesList(requestType, responsePairType, false) + urls, err := messaging.RequestNodesUrls(requestType, responsePairType, false) if err != nil { return errors.Wrap(err, "failed to request nodes list buttons") } @@ -98,7 +98,7 @@ func UpdateAliasHandler( response, err := messaging.UpdateAliasHandler(strconv.FormatInt(c.Chat().ID, 10), environment, requestType, url, alias) if err != nil { - if err == messaging.IncorrectUrlError || err == messaging.InsufficientPermissionsError { + if errors.Is(err, messaging.IncorrectUrlError) || errors.Is(err, messaging.InsufficientPermissionsError) { return c.Send( response, &tele.SendOptions{ParseMode: tele.ModeDefault}, diff --git a/cmd/bots/internal/telegram/messages/error_messages.go b/cmd/bots/internal/telegram/messages/error_messages.go index ec7568ca..650175d4 100644 --- a/cmd/bots/internal/telegram/messages/error_messages.go +++ b/cmd/bots/internal/telegram/messages/error_messages.go @@ -5,7 +5,7 @@ const ( AddedLessThanOne = "You should add a node" RemovedMoreThanOne = "You can remove only one node at a time" RemovedLessThanOne = "You should remove a node" - UpdateWrongFormat = "Format: /add_alias " + AliasWrongFormat = "Format: /add_alias " SubscribedToMoreThanOne = "You can subscribe to only one node at a time" SubscribedToLessThanOne = "You should subscribe to a node" UnsubscribedFromMoreThanOne = "You can unsubscribe from only one node at a time" diff --git a/pkg/messaging/pair/server.go b/pkg/messaging/pair/server.go index 03da4d5e..89d028e5 100644 --- a/pkg/messaging/pair/server.go +++ b/pkg/messaging/pair/server.go @@ -59,8 +59,7 @@ func StartPairMessagingServer(ctx context.Context, nanomsgURL string, ns *nodes. return err } } - var nodeList NodesListResponse - nodeList.Nodes = nodes + nodeList := NodesListResponse{Nodes: nodes} response, err := json.Marshal(nodeList) if err != nil { logger.Error("Failed to marshal node list to json", zap.Error(err)) From 7d22993345bb55150ae270c4f71391c1768df13e Mon Sep 17 00:00:00 2001 From: esuwu Date: Thu, 26 Jan 2023 21:20:09 -0600 Subject: [PATCH 08/20] Added new lines --- cmd/bots/internal/common/templates/alerts/alert_fixed.md | 2 +- cmd/bots/internal/common/templates/alerts/base_target_alert.md | 2 +- cmd/bots/internal/common/templates/alerts/incomplete_alert.md | 2 +- .../internal/common/templates/alerts/internal_error_alert.md | 2 +- .../internal/common/templates/alerts/invalid_height_alert.md | 2 +- cmd/bots/internal/common/templates/alerts/state_hash_alert.html | 2 +- cmd/bots/internal/common/templates/alerts/state_hash_alert.md | 2 +- cmd/bots/internal/common/templates/alerts/unreachable_alert.md | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cmd/bots/internal/common/templates/alerts/alert_fixed.md b/cmd/bots/internal/common/templates/alerts/alert_fixed.md index c607c8fb..07a11106 100644 --- a/cmd/bots/internal/common/templates/alerts/alert_fixed.md +++ b/cmd/bots/internal/common/templates/alerts/alert_fixed.md @@ -4,4 +4,4 @@ Alert type: Resolved ✅ Level: Info ℹ Details: The issue has been resolved, {{ .PreviousAlert}} -``` \ No newline at end of file +``` diff --git a/cmd/bots/internal/common/templates/alerts/base_target_alert.md b/cmd/bots/internal/common/templates/alerts/base_target_alert.md index ec409c1b..20a1f1cf 100644 --- a/cmd/bots/internal/common/templates/alerts/base_target_alert.md +++ b/cmd/bots/internal/common/templates/alerts/base_target_alert.md @@ -10,4 +10,4 @@ Details: Base target is greater than the threshold value. The threshold value is Node: {{ .Node}} Base Target: {{ .BaseTarget}} {{end}} -``` \ No newline at end of file +``` diff --git a/cmd/bots/internal/common/templates/alerts/incomplete_alert.md b/cmd/bots/internal/common/templates/alerts/incomplete_alert.md index f2720499..58687b59 100644 --- a/cmd/bots/internal/common/templates/alerts/incomplete_alert.md +++ b/cmd/bots/internal/common/templates/alerts/incomplete_alert.md @@ -4,4 +4,4 @@ Alert type: Incomplete ❔ Level: Warning ❗ Details: Incomplete statement for node {{ .Node}} {{ .Version}} at height {{ .Height}} -``` \ No newline at end of file +``` diff --git a/cmd/bots/internal/common/templates/alerts/internal_error_alert.md b/cmd/bots/internal/common/templates/alerts/internal_error_alert.md index cdbe7849..d7c59ce1 100644 --- a/cmd/bots/internal/common/templates/alerts/internal_error_alert.md +++ b/cmd/bots/internal/common/templates/alerts/internal_error_alert.md @@ -4,4 +4,4 @@ Alert type: InternalErrorAlert ❗️ Level: Warning ❗ Details: An internal error has occurred, {{ .Error}} -``` \ No newline at end of file +``` diff --git a/cmd/bots/internal/common/templates/alerts/invalid_height_alert.md b/cmd/bots/internal/common/templates/alerts/invalid_height_alert.md index 4ea640a3..4f1274f7 100644 --- a/cmd/bots/internal/common/templates/alerts/invalid_height_alert.md +++ b/cmd/bots/internal/common/templates/alerts/invalid_height_alert.md @@ -4,4 +4,4 @@ Alert type: Invalid Height ❌ Level: Warning ❗ Details: Node {{ .Node}} {{ .Version}} has an invalid height {{ .Height}} -``` \ No newline at end of file +``` diff --git a/cmd/bots/internal/common/templates/alerts/state_hash_alert.html b/cmd/bots/internal/common/templates/alerts/state_hash_alert.html index 9e1eae62..14081739 100644 --- a/cmd/bots/internal/common/templates/alerts/state_hash_alert.html +++ b/cmd/bots/internal/common/templates/alerts/state_hash_alert.html @@ -28,4 +28,4 @@ Fork occurred after block {{ .ForkHeight}} BlockID: {{ .ForkBlockID}} State Hash: {{ .ForkStateHash}} -{{ end }} \ No newline at end of file +{{ end }} diff --git a/cmd/bots/internal/common/templates/alerts/state_hash_alert.md b/cmd/bots/internal/common/templates/alerts/state_hash_alert.md index 49670848..bd285bb6 100644 --- a/cmd/bots/internal/common/templates/alerts/state_hash_alert.md +++ b/cmd/bots/internal/common/templates/alerts/state_hash_alert.md @@ -30,4 +30,4 @@ Fork occurred after block {{ .ForkHeight}} BlockID: {{ .ForkBlockID}} State Hash: {{ .ForkStateHash}} {{ end }} -``` \ No newline at end of file +``` diff --git a/cmd/bots/internal/common/templates/alerts/unreachable_alert.md b/cmd/bots/internal/common/templates/alerts/unreachable_alert.md index 417664b1..266aa03d 100644 --- a/cmd/bots/internal/common/templates/alerts/unreachable_alert.md +++ b/cmd/bots/internal/common/templates/alerts/unreachable_alert.md @@ -4,4 +4,4 @@ Alert type: Unreachable ❌ Level: Error ❌ Details: Node {{ .Node}} is unreachable -``` \ No newline at end of file +``` From 054ef8d94e388feb96f83ce190449bc1d877bf52 Mon Sep 17 00:00:00 2001 From: esuwu Date: Thu, 26 Jan 2023 21:29:44 -0600 Subject: [PATCH 09/20] Removed a useless function --- pkg/messaging/pubsub/server.go | 54 ++-------------------------------- 1 file changed, 2 insertions(+), 52 deletions(-) diff --git a/pkg/messaging/pubsub/server.go b/pkg/messaging/pubsub/server.go index 907c4882..d6f6f0bd 100644 --- a/pkg/messaging/pubsub/server.go +++ b/pkg/messaging/pubsub/server.go @@ -41,9 +41,9 @@ func StartPubMessagingServer(ctx context.Context, nanomsgURL string, alerts <-ch case alert := <-alerts: logger.Sugar().Infof("Alert has been generated: %v", alert) - jsonAlert, err := AlertToJson(alert) + jsonAlert, err := json.Marshal(alert) if err != nil { - logger.Error("Failed to marshal alert to json", zap.Error(err)) + return err } message := &bytes.Buffer{} @@ -56,53 +56,3 @@ func StartPubMessagingServer(ctx context.Context, nanomsgURL string, alerts <-ch } } } - -func AlertToJson(alert entities.Alert) ([]byte, error) { - var jsonAlert []byte - var err error - switch a := alert.(type) { - case *entities.UnreachableAlert: - jsonAlert, err = json.Marshal(a) - if err != nil { - return nil, err - } - case *entities.IncompleteAlert: - jsonAlert, err = json.Marshal(a) - if err != nil { - return nil, err - } - case *entities.InvalidHeightAlert: - jsonAlert, err = json.Marshal(a) - if err != nil { - return nil, err - } - case *entities.HeightAlert: - jsonAlert, err = json.Marshal(a) - if err != nil { - return nil, err - } - case *entities.StateHashAlert: - jsonAlert, err = json.Marshal(a) - if err != nil { - return nil, err - } - case *entities.AlertFixed: - jsonAlert, err = json.Marshal(a) - if err != nil { - return nil, err - } - case *entities.BaseTargetAlert: - jsonAlert, err = json.Marshal(a) - if err != nil { - return nil, err - } - case *entities.InternalErrorAlert: - jsonAlert, err = json.Marshal(a) - if err != nil { - return nil, err - } - default: - return nil, errors.New("unknown alert type") - } - return jsonAlert, nil -} From a76cd7f994e4556ef8b98ffaa56ad95da31ee68f Mon Sep 17 00:00:00 2001 From: esuwu Date: Thu, 26 Jan 2023 21:35:42 -0600 Subject: [PATCH 10/20] Logged an error instead of returning --- pkg/messaging/pubsub/server.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/messaging/pubsub/server.go b/pkg/messaging/pubsub/server.go index d6f6f0bd..dbd4407a 100644 --- a/pkg/messaging/pubsub/server.go +++ b/pkg/messaging/pubsub/server.go @@ -43,7 +43,7 @@ func StartPubMessagingServer(ctx context.Context, nanomsgURL string, alerts <-ch jsonAlert, err := json.Marshal(alert) if err != nil { - return err + logger.Error("Failed to marshal an alert to json", zap.Error(err)) } message := &bytes.Buffer{} From bc9c094157cec1ec603bce9b78c261f909552ed9 Mon Sep 17 00:00:00 2001 From: Nikolay Eskov Date: Fri, 27 Jan 2023 06:47:30 +0300 Subject: [PATCH 11/20] Remove unused param in 'StartPubMessagingServer'. --- pkg/messaging/pubsub/server.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/messaging/pubsub/server.go b/pkg/messaging/pubsub/server.go index dbd4407a..c83ad42d 100644 --- a/pkg/messaging/pubsub/server.go +++ b/pkg/messaging/pubsub/server.go @@ -12,10 +12,9 @@ import ( _ "go.nanomsg.org/mangos/v3/transport/all" "go.uber.org/zap" "nodemon/pkg/entities" - "nodemon/pkg/storing/nodes" ) -func StartPubMessagingServer(ctx context.Context, nanomsgURL string, alerts <-chan entities.Alert, logger *zap.Logger, ns *nodes.Storage) error { +func StartPubMessagingServer(ctx context.Context, nanomsgURL string, alerts <-chan entities.Alert, logger *zap.Logger) error { if len(nanomsgURL) == 0 || len(strings.Fields(nanomsgURL)) > 1 { return errors.New("invalid nanomsg IPC URL for pub sub socket") } From c603fbd9d4b800afd49e177d4a7fbc4ca25d803b Mon Sep 17 00:00:00 2001 From: esuwu Date: Thu, 26 Jan 2023 21:58:39 -0600 Subject: [PATCH 12/20] Removed spaces in one of the templates --- cmd/bots/internal/common/templates/alerts/base_target_alert.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/bots/internal/common/templates/alerts/base_target_alert.md b/cmd/bots/internal/common/templates/alerts/base_target_alert.md index 20a1f1cf..450547e1 100644 --- a/cmd/bots/internal/common/templates/alerts/base_target_alert.md +++ b/cmd/bots/internal/common/templates/alerts/base_target_alert.md @@ -9,5 +9,5 @@ Details: Base target is greater than the threshold value. The threshold value is {{range .}} Node: {{ .Node}} Base Target: {{ .BaseTarget}} - {{end}} +{{end}} ``` From 73e328ab96fbe1a2ea29b5d0eedb33dca7b8c14c Mon Sep 17 00:00:00 2001 From: esuwu Date: Thu, 26 Jan 2023 22:01:51 -0600 Subject: [PATCH 13/20] Returned an error --- cmd/bots/internal/telegram/handlers/handlers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/bots/internal/telegram/handlers/handlers.go b/cmd/bots/internal/telegram/handlers/handlers.go index d5bdd736..b619cb0c 100644 --- a/cmd/bots/internal/telegram/handlers/handlers.go +++ b/cmd/bots/internal/telegram/handlers/handlers.go @@ -173,7 +173,7 @@ func InitTgHandlers(environment *common.TelegramBotEnvironment, requestType chan environment.Bot.Handle("/aliases", func(c tele.Context) error { nodes, err := messaging.RequestAllNodes(requestType, responsePairType) if err != nil { - environment.Zap.Error("failed to get nodes list", zap.Error(err)) + return errors.Wrap(err, "failed to get nodes list") } var msg string for _, n := range nodes { From 8ba2186b9aea1c2a8913ba5a7d0e7ce873d669a2 Mon Sep 17 00:00:00 2001 From: esuwu Date: Thu, 26 Jan 2023 22:06:47 -0600 Subject: [PATCH 14/20] Removed a useless argument --- cmd/nodemon/nodemon.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/nodemon/nodemon.go b/cmd/nodemon/nodemon.go index 43eb840c..6546454c 100644 --- a/cmd/nodemon/nodemon.go +++ b/cmd/nodemon/nodemon.go @@ -177,7 +177,7 @@ func run() error { alerts := analyzer.Start(notifications) go func() { - err := pubsub.StartPubMessagingServer(ctx, nanomsgPubSubURL, alerts, zap, ns) + err := pubsub.StartPubMessagingServer(ctx, nanomsgPubSubURL, alerts, zap) if err != nil { zap.Fatal("failed to start pub messaging server", zapLogger.Error(err)) } From 1497af1916bc2ee04e68facddbaa10801eb17bfc Mon Sep 17 00:00:00 2001 From: esuwu Date: Thu, 26 Jan 2023 22:10:50 -0600 Subject: [PATCH 15/20] Added a log --- cmd/bots/internal/telegram/handlers/handlers.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/bots/internal/telegram/handlers/handlers.go b/cmd/bots/internal/telegram/handlers/handlers.go index b619cb0c..a036bdff 100644 --- a/cmd/bots/internal/telegram/handlers/handlers.go +++ b/cmd/bots/internal/telegram/handlers/handlers.go @@ -173,6 +173,7 @@ func InitTgHandlers(environment *common.TelegramBotEnvironment, requestType chan environment.Bot.Handle("/aliases", func(c tele.Context) error { nodes, err := messaging.RequestAllNodes(requestType, responsePairType) if err != nil { + environment.Zap.Error("failed to request nodes list", zap.Error(err)) return errors.Wrap(err, "failed to get nodes list") } var msg string From 6e758ff793c80ef322cb3487ec77a5034a92759c Mon Sep 17 00:00:00 2001 From: esuwu Date: Thu, 26 Jan 2023 22:55:26 -0600 Subject: [PATCH 16/20] Added tests for alert templates --- cmd/bots/internal/common/environment.go | 18 +- .../templates/alerts/base_target_alert.html | 1 + .../templates/alerts/base_target_alert.md | 7 +- .../common/templates/alerts/height_alert.md | 1 - cmd/bots/internal/common/templates_test.go | 255 ++++++++++++++++++ 5 files changed, 269 insertions(+), 13 deletions(-) create mode 100644 cmd/bots/internal/common/templates_test.go diff --git a/cmd/bots/internal/common/environment.go b/cmd/bots/internal/common/environment.go index 10b3bd94..8e236384 100644 --- a/cmd/bots/internal/common/environment.go +++ b/cmd/bots/internal/common/environment.go @@ -38,11 +38,11 @@ var ( templateFiles embed.FS ) -type expectedExtension string +type ExpectedExtension string const ( - Html expectedExtension = ".html" - Markdown expectedExtension = ".md" + Html ExpectedExtension = ".html" + Markdown ExpectedExtension = ".md" ) var errUnknownAlertType = errors.New("received unknown alert type") @@ -505,7 +505,7 @@ func sortNodesStatuses(statuses []NodeStatus) { }) } -func executeTemplate(template string, data any, extension expectedExtension) (string, error) { +func executeTemplate(template string, data any, extension ExpectedExtension) (string, error) { switch extension { case Html: tmpl, err := htmlTemplate.ParseFS(templateFiles, template+string(extension)) @@ -543,7 +543,7 @@ func replaceNodeWithAlias(node string, nodesAlias map[string]string) string { return node } -func executeAlertTemplate(alertType entities.AlertType, alertJson []byte, extension expectedExtension, allNodes []entities.Node) (string, error) { +func executeAlertTemplate(alertType entities.AlertType, alertJson []byte, extension ExpectedExtension, allNodes []entities.Node) (string, error) { nodesAliases := make(map[string]string) for _, n := range allNodes { if n.Alias != "" { @@ -739,7 +739,7 @@ type StatusCondition struct { Height string } -func HandleNodesStatusError(nodesStatusResp *pair.NodesStatusResponse, extension expectedExtension) (string, StatusCondition, error) { +func HandleNodesStatusError(nodesStatusResp *pair.NodesStatusResponse, extension ExpectedExtension) (string, StatusCondition, error) { statusCondition := StatusCondition{AllNodesAreOk: false, NodesNumber: 0, Height: ""} var differentHeightsNodes []NodeStatus @@ -781,7 +781,7 @@ func HandleNodesStatusError(nodesStatusResp *pair.NodesStatusResponse, extension } func HandleNodesStatus(nodesStatusResp *pair.NodesStatusResponse, - extension expectedExtension, allNodes []entities.Node) (string, StatusCondition, error) { + extension ExpectedExtension, allNodes []entities.Node) (string, StatusCondition, error) { statusCondition := StatusCondition{AllNodesAreOk: false, NodesNumber: 0, Height: ""} nodesAliases := make(map[string]string) @@ -857,7 +857,7 @@ func HandleNodesStatus(nodesStatusResp *pair.NodesStatusResponse, return msg, statusCondition, nil } -func HandleNodeStatement(nodeStatementResp *pair.NodeStatementResponse, extension expectedExtension) (string, error) { +func HandleNodeStatement(nodeStatementResp *pair.NodeStatementResponse, extension ExpectedExtension) (string, error) { nodeStatementResp.NodeStatement.Node = strings.ReplaceAll(nodeStatementResp.NodeStatement.Node, entities.HttpsScheme+"://", "") nodeStatementResp.NodeStatement.Node = strings.ReplaceAll(nodeStatementResp.NodeStatement.Node, entities.HttpScheme+"://", "") @@ -886,7 +886,7 @@ func HandleNodeStatement(nodeStatementResp *pair.NodeStatementResponse, extensio return msg, nil } -func constructMessage(alertType entities.AlertType, alertJson []byte, extension expectedExtension, allNodes []entities.Node) (string, error) { +func constructMessage(alertType entities.AlertType, alertJson []byte, extension ExpectedExtension, allNodes []entities.Node) (string, error) { alert := generalMessaging.Alert{} err := json.Unmarshal(alertJson, &alert) if err != nil { diff --git a/cmd/bots/internal/common/templates/alerts/base_target_alert.html b/cmd/bots/internal/common/templates/alerts/base_target_alert.html index 34432a1a..3c4862c8 100644 --- a/cmd/bots/internal/common/templates/alerts/base_target_alert.html +++ b/cmd/bots/internal/common/templates/alerts/base_target_alert.html @@ -9,3 +9,4 @@ Node: {{ .Node}} Base Target: {{ .BaseTarget}} {{end}} +{{end}} \ No newline at end of file diff --git a/cmd/bots/internal/common/templates/alerts/base_target_alert.md b/cmd/bots/internal/common/templates/alerts/base_target_alert.md index 450547e1..08fb9243 100644 --- a/cmd/bots/internal/common/templates/alerts/base_target_alert.md +++ b/cmd/bots/internal/common/templates/alerts/base_target_alert.md @@ -3,11 +3,12 @@ Alert type: Base Target Level: Error ❌ -Details: Base target is greater than the threshold value. The threshold value is {{ .Threshold}} +Details: Base target is greater than the threshold value. The threshold value is {{ .Threshold }} {{ with .BaseTargetValues }} -{{range .}} +{{ range . }} Node: {{ .Node}} Base Target: {{ .BaseTarget}} {{end}} -``` +{{end}} +``` \ No newline at end of file diff --git a/cmd/bots/internal/common/templates/alerts/height_alert.md b/cmd/bots/internal/common/templates/alerts/height_alert.md index e2419a36..b51903fb 100644 --- a/cmd/bots/internal/common/templates/alerts/height_alert.md +++ b/cmd/bots/internal/common/templates/alerts/height_alert.md @@ -13,7 +13,6 @@ First group with height {{ .Height}}: {{end}} {{end}} - {{ with .SecondGroup }} Second group with height {{ .Height}}: {{range .Nodes}} diff --git a/cmd/bots/internal/common/templates_test.go b/cmd/bots/internal/common/templates_test.go new file mode 100644 index 00000000..7513246e --- /dev/null +++ b/cmd/bots/internal/common/templates_test.go @@ -0,0 +1,255 @@ +package common + +import ( + "encoding/binary" + "testing" + + "github.com/wavesplatform/gowaves/pkg/crypto" + "github.com/wavesplatform/gowaves/pkg/proto" + "nodemon/pkg/entities" +) + +var formats = []ExpectedExtension{Html, Markdown} + +func TestBaseTargetTemplate(t *testing.T) { + data := &entities.BaseTargetAlert{ + Timestamp: 100, + BaseTargetValues: []entities.BaseTargetValue{ + { + Node: "test1", + BaseTarget: 150, + }, + { + Node: "test2", + BaseTarget: 510, + }, + { + Node: "test1", + BaseTarget: 150, + }, + { + Node: "test2", + BaseTarget: 510, + }, + { + Node: "test1", + BaseTarget: 150, + }, + { + Node: "test2", + BaseTarget: 510, + }, + }, + Threshold: 101, + } + for _, f := range formats { + _, err := executeTemplate("templates/alerts/base_target_alert", data, f) + if err != nil { + t.Fatal(err) + } + } +} + +func TestUnreachableTemplate(t *testing.T) { + data := &entities.UnreachableAlert{ + Timestamp: 100, + Node: "node", + } + for _, f := range formats { + _, err := executeTemplate("templates/alerts/unreachable_alert", data, f) + if err != nil { + t.Fatal(err) + } + } +} + +func TestAlertFixed(t *testing.T) { + unreachable := &entities.UnreachableAlert{ + Timestamp: 100, + Node: "blabla", + } + + data := &entities.AlertFixed{ + Timestamp: 100, + Fixed: unreachable, + } + + fixedStatement := struct { + PreviousAlert string + }{ + PreviousAlert: data.Fixed.Message(), + } + for _, f := range formats { + _, err := executeTemplate("templates/alerts/alert_fixed", fixedStatement, f) + if err != nil { + t.Fatal(err) + } + } +} + +func TestHeightTemplate(t *testing.T) { + heightAlert := &entities.HeightAlert{ + Timestamp: 100, + MaxHeightGroup: entities.HeightGroup{ + Height: 2, + Nodes: entities.Nodes{"node 3", "node 4"}, + }, + OtherHeightGroup: entities.HeightGroup{ + Height: 1, + Nodes: entities.Nodes{"node 1", "node 2"}, + }, + } + + type group struct { + Nodes []string + Height int + } + + heightStatement := struct { + HeightDifference int + FirstGroup group + SecondGroup group + }{ + HeightDifference: heightAlert.MaxHeightGroup.Height - heightAlert.OtherHeightGroup.Height, + FirstGroup: group{ + Nodes: heightAlert.MaxHeightGroup.Nodes, + Height: heightAlert.MaxHeightGroup.Height, + }, + SecondGroup: group{ + Nodes: heightAlert.OtherHeightGroup.Nodes, + Height: heightAlert.OtherHeightGroup.Height, + }, + } + for _, f := range formats { + _, err := executeTemplate("templates/alerts/height_alert", heightStatement, f) + + if err != nil { + t.Fatal(err) + } + } +} + +type shInfo struct { + id proto.BlockID + sh proto.StateHash +} + +func sequentialBlockID(i int) proto.BlockID { + d := crypto.Digest{} + binary.BigEndian.PutUint64(d[:8], uint64(i)) + return proto.NewBlockIDFromDigest(d) +} + +func sequentialStateHash(blockID proto.BlockID, i int) proto.StateHash { + d := crypto.Digest{} + binary.BigEndian.PutUint64(d[:8], uint64(i)) + return proto.StateHash{ + BlockID: blockID, + SumHash: d, + FieldsHashes: proto.FieldsHashes{}, + } +} + +func generateStateHashes(o, n int) []shInfo { + r := make([]shInfo, n) + for i := 0; i < n; i++ { + id := sequentialBlockID(o + i + 1) + sh := sequentialStateHash(id, o+i+101) + r[i] = shInfo{id: id, sh: sh} + } + return r +} + +func TestStateHashTemplate(t *testing.T) { + + shInfo := generateStateHashes(1, 5) + stateHashAlert := &entities.StateHashAlert{ + CurrentGroupsBucketHeight: 100, + LastCommonStateHashExist: true, + LastCommonStateHashHeight: 1, + LastCommonStateHash: shInfo[0].sh, + FirstGroup: entities.StateHashGroup{ + Nodes: entities.Nodes{"a"}, + StateHash: shInfo[0].sh, + }, + SecondGroup: entities.StateHashGroup{ + Nodes: entities.Nodes{"b"}, + StateHash: shInfo[0].sh, + }, + } + + type stateHashGroup struct { + BlockID string + Nodes []string + StateHash string + } + stateHashStatement := struct { + SameHeight int + LastCommonStateHashExist bool + ForkHeight int + ForkBlockID string + ForkStateHash string + + FirstGroup stateHashGroup + SecondGroup stateHashGroup + }{ + SameHeight: stateHashAlert.CurrentGroupsBucketHeight, + LastCommonStateHashExist: stateHashAlert.LastCommonStateHashExist, + ForkHeight: stateHashAlert.LastCommonStateHashHeight, + ForkBlockID: stateHashAlert.LastCommonStateHash.BlockID.String(), + ForkStateHash: stateHashAlert.LastCommonStateHash.SumHash.Hex(), + + FirstGroup: stateHashGroup{ + BlockID: stateHashAlert.FirstGroup.StateHash.BlockID.String(), + Nodes: stateHashAlert.FirstGroup.Nodes, + StateHash: stateHashAlert.FirstGroup.StateHash.SumHash.Hex(), + }, + SecondGroup: stateHashGroup{ + BlockID: stateHashAlert.SecondGroup.StateHash.BlockID.String(), + Nodes: stateHashAlert.SecondGroup.Nodes, + StateHash: stateHashAlert.SecondGroup.StateHash.SumHash.Hex(), + }, + } + for _, f := range formats { + _, err := executeTemplate("templates/alerts/state_hash_alert", stateHashStatement, f) + if err != nil { + t.Fatal(err) + } + } +} + +func TestIncompleteTemplate(t *testing.T) { + data := &entities.IncompleteAlert{ + NodeStatement: entities.NodeStatement{Node: "a", Version: "1", Height: 1}, + } + for _, f := range formats { + _, err := executeTemplate("templates/alerts/incomplete_alert", data, f) + if err != nil { + t.Fatal(err) + } + } +} + +func TestInternalErrorTemplate(t *testing.T) { + data := &entities.InternalErrorAlert{ + Error: "error", + } + for _, f := range formats { + _, err := executeTemplate("templates/alerts/internal_error_alert", data, f) + if err != nil { + t.Fatal(err) + } + } +} + +func TestInvalidHeightTemplate(t *testing.T) { + data := &entities.InvalidHeightAlert{ + NodeStatement: entities.NodeStatement{Node: "a", Version: "1", Height: 1}, + } + for _, f := range formats { + _, err := executeTemplate("templates/alerts/invalid_height_alert", data, f) + if err != nil { + t.Fatal(err) + } + } +} From eefa1cc1c04ff91b7dc00e434c2906bbf906fc37 Mon Sep 17 00:00:00 2001 From: Nikolay Eskov Date: Fri, 27 Jan 2023 12:12:30 +0300 Subject: [PATCH 17/20] Add newlines. --- .../internal/common/templates/alerts/base_target_alert.html | 2 +- cmd/bots/internal/common/templates/alerts/base_target_alert.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/bots/internal/common/templates/alerts/base_target_alert.html b/cmd/bots/internal/common/templates/alerts/base_target_alert.html index 3c4862c8..a87c3fb7 100644 --- a/cmd/bots/internal/common/templates/alerts/base_target_alert.html +++ b/cmd/bots/internal/common/templates/alerts/base_target_alert.html @@ -9,4 +9,4 @@ Node: {{ .Node}} Base Target: {{ .BaseTarget}} {{end}} -{{end}} \ No newline at end of file +{{end}} diff --git a/cmd/bots/internal/common/templates/alerts/base_target_alert.md b/cmd/bots/internal/common/templates/alerts/base_target_alert.md index 08fb9243..d5ee1475 100644 --- a/cmd/bots/internal/common/templates/alerts/base_target_alert.md +++ b/cmd/bots/internal/common/templates/alerts/base_target_alert.md @@ -11,4 +11,4 @@ Node: {{ .Node}} Base Target: {{ .BaseTarget}} {{end}} {{end}} -``` \ No newline at end of file +``` From aa6b5435137398dd8d3f90a8d0b32ae8725eccf7 Mon Sep 17 00:00:00 2001 From: Nikolay Eskov Date: Fri, 27 Jan 2023 17:30:26 +0300 Subject: [PATCH 18/20] Add types for templates rendering. --- cmd/bots/internal/common/environment.go | 70 ++++++++++++++----------- 1 file changed, 39 insertions(+), 31 deletions(-) diff --git a/cmd/bots/internal/common/environment.go b/cmd/bots/internal/common/environment.go index 8e236384..e5d0630f 100644 --- a/cmd/bots/internal/common/environment.go +++ b/cmd/bots/internal/common/environment.go @@ -543,6 +543,37 @@ func replaceNodeWithAlias(node string, nodesAlias map[string]string) string { return node } +type heightStatementGroup struct { + Nodes []string + Height int +} + +type heightStatement struct { + HeightDifference int + FirstGroup heightStatementGroup + SecondGroup heightStatementGroup +} + +type stateHashStatementGroup struct { + BlockID string + Nodes []string + StateHash string +} + +type stateHashStatement struct { + SameHeight int + LastCommonStateHashExist bool + ForkHeight int + ForkBlockID string + ForkStateHash string + FirstGroup stateHashStatementGroup + SecondGroup stateHashStatementGroup +} + +type fixedStatement struct { + PreviousAlert string +} + func executeAlertTemplate(alertType entities.AlertType, alertJson []byte, extension ExpectedExtension, allNodes []entities.Node) (string, error) { nodesAliases := make(map[string]string) for _, n := range allNodes { @@ -606,21 +637,13 @@ func executeAlertTemplate(alertType entities.AlertType, alertJson []byte, extens heightAlert.OtherHeightGroup.Nodes[i] = replaceNodeWithAlias(heightAlert.OtherHeightGroup.Nodes[i], nodesAliases) } - type group struct { - Nodes []string - Height int - } - heightStatement := struct { - HeightDifference int - FirstGroup group - SecondGroup group - }{ + heightStatement := heightStatement{ HeightDifference: heightAlert.MaxHeightGroup.Height - heightAlert.OtherHeightGroup.Height, - FirstGroup: group{ + FirstGroup: heightStatementGroup{ Nodes: heightAlert.MaxHeightGroup.Nodes, Height: heightAlert.MaxHeightGroup.Height, }, - SecondGroup: group{ + SecondGroup: heightStatementGroup{ Nodes: heightAlert.OtherHeightGroup.Nodes, Height: heightAlert.OtherHeightGroup.Height, }, @@ -643,33 +666,20 @@ func executeAlertTemplate(alertType entities.AlertType, alertJson []byte, extens for i := range stateHashAlert.SecondGroup.Nodes { stateHashAlert.SecondGroup.Nodes[i] = replaceNodeWithAlias(stateHashAlert.SecondGroup.Nodes[i], nodesAliases) } - type stateHashGroup struct { - BlockID string - Nodes []string - StateHash string - } - stateHashStatement := struct { - SameHeight int - LastCommonStateHashExist bool - ForkHeight int - ForkBlockID string - ForkStateHash string - - FirstGroup stateHashGroup - SecondGroup stateHashGroup - }{ + + stateHashStatement := stateHashStatement{ SameHeight: stateHashAlert.CurrentGroupsBucketHeight, LastCommonStateHashExist: stateHashAlert.LastCommonStateHashExist, ForkHeight: stateHashAlert.LastCommonStateHashHeight, ForkBlockID: stateHashAlert.LastCommonStateHash.BlockID.String(), ForkStateHash: stateHashAlert.LastCommonStateHash.SumHash.Hex(), - FirstGroup: stateHashGroup{ + FirstGroup: stateHashStatementGroup{ BlockID: stateHashAlert.FirstGroup.StateHash.BlockID.String(), Nodes: stateHashAlert.FirstGroup.Nodes, StateHash: stateHashAlert.FirstGroup.StateHash.SumHash.Hex(), }, - SecondGroup: stateHashGroup{ + SecondGroup: stateHashStatementGroup{ BlockID: stateHashAlert.SecondGroup.StateHash.BlockID.String(), Nodes: stateHashAlert.SecondGroup.Nodes, StateHash: stateHashAlert.SecondGroup.StateHash.SumHash.Hex(), @@ -689,9 +699,7 @@ func executeAlertTemplate(alertType entities.AlertType, alertJson []byte, extens // TODO there is no alias here right now, but AlertFixed needs to be changed. Make previous alert to look like a number - fixedStatement := struct { - PreviousAlert string - }{ + fixedStatement := fixedStatement{ PreviousAlert: alertFixed.Fixed.Message(), } From db7e71081b2276ab9ae39a46b76781a704974b5b Mon Sep 17 00:00:00 2001 From: Nikolay Eskov Date: Fri, 27 Jan 2023 17:31:01 +0300 Subject: [PATCH 19/20] Used types for templates rendering in tests. --- cmd/bots/internal/common/templates_test.go | 39 ++++------------------ 1 file changed, 7 insertions(+), 32 deletions(-) diff --git a/cmd/bots/internal/common/templates_test.go b/cmd/bots/internal/common/templates_test.go index 7513246e..3d2b992d 100644 --- a/cmd/bots/internal/common/templates_test.go +++ b/cmd/bots/internal/common/templates_test.go @@ -74,9 +74,7 @@ func TestAlertFixed(t *testing.T) { Fixed: unreachable, } - fixedStatement := struct { - PreviousAlert string - }{ + fixedStatement := fixedStatement{ PreviousAlert: data.Fixed.Message(), } for _, f := range formats { @@ -100,22 +98,13 @@ func TestHeightTemplate(t *testing.T) { }, } - type group struct { - Nodes []string - Height int - } - - heightStatement := struct { - HeightDifference int - FirstGroup group - SecondGroup group - }{ + heightStatement := heightStatement{ HeightDifference: heightAlert.MaxHeightGroup.Height - heightAlert.OtherHeightGroup.Height, - FirstGroup: group{ + FirstGroup: heightStatementGroup{ Nodes: heightAlert.MaxHeightGroup.Nodes, Height: heightAlert.MaxHeightGroup.Height, }, - SecondGroup: group{ + SecondGroup: heightStatementGroup{ Nodes: heightAlert.OtherHeightGroup.Nodes, Height: heightAlert.OtherHeightGroup.Height, }, @@ -178,33 +167,19 @@ func TestStateHashTemplate(t *testing.T) { }, } - type stateHashGroup struct { - BlockID string - Nodes []string - StateHash string - } - stateHashStatement := struct { - SameHeight int - LastCommonStateHashExist bool - ForkHeight int - ForkBlockID string - ForkStateHash string - - FirstGroup stateHashGroup - SecondGroup stateHashGroup - }{ + stateHashStatement := stateHashStatement{ SameHeight: stateHashAlert.CurrentGroupsBucketHeight, LastCommonStateHashExist: stateHashAlert.LastCommonStateHashExist, ForkHeight: stateHashAlert.LastCommonStateHashHeight, ForkBlockID: stateHashAlert.LastCommonStateHash.BlockID.String(), ForkStateHash: stateHashAlert.LastCommonStateHash.SumHash.Hex(), - FirstGroup: stateHashGroup{ + FirstGroup: stateHashStatementGroup{ BlockID: stateHashAlert.FirstGroup.StateHash.BlockID.String(), Nodes: stateHashAlert.FirstGroup.Nodes, StateHash: stateHashAlert.FirstGroup.StateHash.SumHash.Hex(), }, - SecondGroup: stateHashGroup{ + SecondGroup: stateHashStatementGroup{ BlockID: stateHashAlert.SecondGroup.StateHash.BlockID.String(), Nodes: stateHashAlert.SecondGroup.Nodes, StateHash: stateHashAlert.SecondGroup.StateHash.SumHash.Hex(), From 1c0e43d4a722a430d47a57c77dfa851542758284 Mon Sep 17 00:00:00 2001 From: Nikolay Eskov Date: Fri, 27 Jan 2023 18:28:31 +0300 Subject: [PATCH 20/20] Change a bit height alert '.md' template. --- cmd/bots/internal/common/templates/alerts/height_alert.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cmd/bots/internal/common/templates/alerts/height_alert.md b/cmd/bots/internal/common/templates/alerts/height_alert.md index b51903fb..7ffa879f 100644 --- a/cmd/bots/internal/common/templates/alerts/height_alert.md +++ b/cmd/bots/internal/common/templates/alerts/height_alert.md @@ -7,7 +7,6 @@ Details: Some node(s) are {{ .HeightDifference}} blocks behind {{ with .FirstGroup }} First group with height {{ .Height}}: - {{range .Nodes}} {{.}} {{end}} @@ -19,4 +18,4 @@ Second group with height {{ .Height}}: {{.}} {{end}} {{end}} -``` \ No newline at end of file +```