From 71d3de620cb9c9ff8685b7afe599eb94b1450a94 Mon Sep 17 00:00:00 2001 From: Aleksandr Dolgavin <41806871+esuwu@users.noreply.github.com> Date: Tue, 26 Apr 2022 15:36:24 +0300 Subject: [PATCH] tg-bot messaging (#33) * From https://github.com/wavesplatform/nodemon/pull/28 * Fixed api * Fixed subscription * Deleted chats table, added html templates, a handler, changed initialization * Added chat init log * Added unit files * Altered ping message * Updated messages Co-authored-by: Nikolay Eskov --- Makefile | 2 +- cmd/nodemon/nodemon.go | 5 +- cmd/tg_bot/{tg_bot.go => bot.go} | 10 +- .../internal/base_messages/base_messages.go | 25 ---- cmd/tg_bot/internal/environment.go | 82 ++++++++++-- cmd/tg_bot/internal/handlers/handlers.go | 55 +++----- cmd/tg_bot/internal/init/init.go | 12 +- .../internal/messages/alert_messages.go | 6 + cmd/tg_bot/internal/messages/base_messages.go | 18 +++ cmd/tg_bot/internal/templates/alert.html | 5 + pkg/entities/alerts.go | 121 +++++++++++++----- pkg/entities/notifications.go | 4 +- pkg/messaging/client.go | 14 +- pkg/storing/chats/chats.go | 90 ------------- units/nodemon.service | 17 +++ units/tg_bot.service | 17 +++ 16 files changed, 267 insertions(+), 216 deletions(-) rename cmd/tg_bot/{tg_bot.go => bot.go} (91%) delete mode 100644 cmd/tg_bot/internal/base_messages/base_messages.go create mode 100644 cmd/tg_bot/internal/messages/alert_messages.go create mode 100644 cmd/tg_bot/internal/messages/base_messages.go create mode 100644 cmd/tg_bot/internal/templates/alert.html delete mode 100644 pkg/storing/chats/chats.go create mode 100644 units/nodemon.service create mode 100644 units/tg_bot.service diff --git a/Makefile b/Makefile index d11a79e3..602c5b2e 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,7 @@ mod-clean: go mod tidy build-bot-linux-amd64: - @CGO_ENABLE=0 GOOS=linux GOARCH=amd64 go build -o bin/nodemon-tg ./cmd/telegram_bot/bot.go + @CGO_ENABLE=0 GOOS=linux GOARCH=amd64 go build -o bin/nodemon-tg ./cmd/tg_bot/bot.go build-nodemon-linux-amd64: @CGO_ENABLE=0 GOOS=linux GOARCH=amd64 go build -o bin/nodemon ./cmd/nodemon/nodemon.go diff --git a/cmd/nodemon/nodemon.go b/cmd/nodemon/nodemon.go index db5970a9..66ac2480 100644 --- a/cmd/nodemon/nodemon.go +++ b/cmd/nodemon/nodemon.go @@ -135,7 +135,10 @@ func run() error { go func() { for alert := range alerts { log.Printf("Alert has been generated: %v", alert) - err := socket.Send([]byte(alert.Message())) + message := make([]byte, len(alert.Message())+1) + message[0] = byte(alert.Type()) + copy(message[1:], alert.Message()) + err := socket.Send(message) if err != nil { log.Printf("failed to send a message to socket, %v", err) } diff --git a/cmd/tg_bot/tg_bot.go b/cmd/tg_bot/bot.go similarity index 91% rename from cmd/tg_bot/tg_bot.go rename to cmd/tg_bot/bot.go index 14914910..aca71ffe 100755 --- a/cmd/tg_bot/tg_bot.go +++ b/cmd/tg_bot/bot.go @@ -36,14 +36,14 @@ func run() error { webhookLocalAddress string // only for webhook method publicURL string // only for webhook method botToken string - storagePath string + chatID int64 ) flag.StringVar(&nanomsgURL, "nano-msg-url", "ipc:///tmp/nano-msg-nodemon-pubsub.ipc", "Nanomsg IPC URL. Default is tcp://:8000") flag.StringVar(&behavior, "behavior", "webhook", "Behavior is either webhook or polling") flag.StringVar(&webhookLocalAddress, "webhook-local-address", ":8081", "The application's webhook address is :8081 by default") flag.StringVar(&botToken, "bot-token", "", "Temporarily: the default token is the current token") flag.StringVar(&publicURL, "public-url", "", "Default is https://mainnet-go-htz-fsn1-1.wavesnodes.com/bot") - flag.StringVar(&storagePath, "storage", "", "Path to storage") + flag.Int64Var(&chatID, "chat-id", 0, "Chat ID to send alerts through") flag.Parse() if botToken == "" { @@ -54,15 +54,15 @@ func run() error { log.Println("invalid public url") return errorInvalidParameters } - if storagePath == "" { - log.Println("invalid storage path") + if chatID == 0 { + log.Println("invalid chat ID") return errorInvalidParameters } ctx, done := signal.NotifyContext(context.Background(), os.Interrupt) defer done() - tgBotEnv, err := tgBot.InitTgBot(behavior, webhookLocalAddress, publicURL, botToken, storagePath) + tgBotEnv, err := tgBot.InitTgBot(behavior, webhookLocalAddress, publicURL, botToken, chatID) if err != nil { log.Println("failed to initialize telegram bot") return errors.Wrap(err, "failed to init tg bot") diff --git a/cmd/tg_bot/internal/base_messages/base_messages.go b/cmd/tg_bot/internal/base_messages/base_messages.go deleted file mode 100644 index 7eda9dd9..00000000 --- a/cmd/tg_bot/internal/base_messages/base_messages.go +++ /dev/null @@ -1,25 +0,0 @@ -package base_messages - -import tele "gopkg.in/telebot.v3" - -const ( - HelpInfoText2 = "This is a bot for monitoring Waves nodes. The next commands are available:\n\n" + - "/ping - a simple command to check whether the bot is available\n" + - "/hello - the command to make the bot save this chat for alerts. Needs to be done first time\n" + - "/start - the command to make the bot start getting alerts\n" + - "/mute - the command to make the bot stop listening to alerts" -) - -var commands = []string{"/ping", "/hello", "/start", "/mute", "/help"} - -func HelpCommandKeyboard() [][]tele.ReplyButton { - var keyboard = make([][]tele.ReplyButton, 0) - for i, command := range commands { - if i%2 == 0 { - keyboard = append(keyboard, []tele.ReplyButton{}) - } - keyboard[i/2] = append(keyboard[i/2], tele.ReplyButton{Text: command}) - } - - return keyboard -} diff --git a/cmd/tg_bot/internal/environment.go b/cmd/tg_bot/internal/environment.go index 295c5663..57c57f10 100644 --- a/cmd/tg_bot/internal/environment.go +++ b/cmd/tg_bot/internal/environment.go @@ -1,22 +1,37 @@ package internal import ( + "bytes" + "embed" + "html/template" "log" "github.com/pkg/errors" "gopkg.in/telebot.v3" "nodemon/pkg/entities" - "nodemon/pkg/storing/chats" ) +var ( + //go:embed templates + templateFiles embed.FS +) + +var errUnknownAlertType = errors.New("received unknown alert type") + type TelegramBotEnvironment struct { - ChatStorage *chats.Storage - Bot *telebot.Bot - Mute bool + ChatID int64 + Bot *telebot.Bot + Mute bool } -func NewTelegramBotEnvironment(bot *telebot.Bot, storage *chats.Storage, shutUp bool) *TelegramBotEnvironment { - return &TelegramBotEnvironment{Bot: bot, ChatStorage: storage, Mute: shutUp} +type Alert struct { + AlertType string + Severity string + Details string +} + +func NewTelegramBotEnvironment(bot *telebot.Bot, chatID int64, mute bool) *TelegramBotEnvironment { + return &TelegramBotEnvironment{Bot: bot, ChatID: chatID, Mute: mute} } func (tgEnv *TelegramBotEnvironment) Start() { @@ -25,23 +40,62 @@ func (tgEnv *TelegramBotEnvironment) Start() { log.Println("Telegram bot finished") } +func (tgEnv *TelegramBotEnvironment) constructMessage(alert string, msg []byte) (string, error) { + a := Alert{ + AlertType: alert, + Severity: "Error", + Details: string(msg), + } + + tmpl, err := template.ParseFS(templateFiles, "templates/alert.html") + + if err != nil { + log.Printf("failed to construct a message, %v", err) + return "", err + } + + w := &bytes.Buffer{} + err = tmpl.Execute(w, a) + if err != nil { + log.Printf("failed to construct a message, %v", err) + return "", err + } + return w.String(), nil +} + func (tgEnv *TelegramBotEnvironment) SendMessage(msg []byte) { if tgEnv.Mute { + log.Printf("received an alert, but asleep now") return } - chatID, err := tgEnv.ChatStorage.FindChatID(entities.TelegramPlatform) - if err != nil { - if errors.Is(err, chats.ErrorChatNotFound) { - log.Println("have not received a chat id yet") - } else { - log.Printf("failed to find chat id: %v", err) + chat := &telebot.Chat{ID: tgEnv.ChatID} + + alertDescription, ok := entities.AlertTypes[entities.AlertType(msg[0])] + if !ok { + log.Printf("failed to construct message, %v", errUnknownAlertType) + _, err := tgEnv.Bot.Send( + chat, + errUnknownAlertType.Error(), + &telebot.SendOptions{ParseMode: telebot.ModeHTML}, + ) + if err != nil { + log.Printf("failed to send a message to telegram, %v", err) } return } - chat := &telebot.Chat{ID: int64(*chatID)} - _, err = tgEnv.Bot.Send(chat, string(msg)) + messageToBot, err := tgEnv.constructMessage(alertDescription, msg[1:]) + if err != nil { + log.Printf("failed to construct message, %v", err) + return + } + _, err = tgEnv.Bot.Send( + chat, + messageToBot, + &telebot.SendOptions{ParseMode: telebot.ModeHTML}, + ) + if err != nil { log.Printf("failed to send a message to telegram, %v", err) } diff --git a/cmd/tg_bot/internal/handlers/handlers.go b/cmd/tg_bot/internal/handlers/handlers.go index fc076128..bab6f783 100644 --- a/cmd/tg_bot/internal/handlers/handlers.go +++ b/cmd/tg_bot/internal/handlers/handlers.go @@ -1,59 +1,44 @@ package handlers import ( - "log" + "fmt" tele "gopkg.in/telebot.v3" "nodemon/cmd/tg_bot/internal" - "nodemon/cmd/tg_bot/internal/base_messages" - "nodemon/pkg/entities" + "nodemon/cmd/tg_bot/internal/messages" ) func InitHandlers(bot *tele.Bot, environment *internal.TelegramBotEnvironment) { - bot.Handle("/hello", func(c tele.Context) error { - oldChatID, err := environment.ChatStorage.FindChatID(entities.TelegramPlatform) - if err != nil { - log.Printf("failed to insert chat id into db: %v", err) - return c.Send("An error occurred while finding the chat id in database") - } - if oldChatID != nil { - return c.Send("Hello! I remember this chat.") - } - chatID := entities.ChatID(c.Chat().ID) - - err = environment.ChatStorage.InsertChatID(chatID, entities.TelegramPlatform) - if err != nil { - log.Printf("failed to insert chat id into db: %v", err) - return c.Send("I failed to save this chat id") - } - return c.Send("Hello! This new chat has been saved for alerting.") + bot.Handle("/chat", func(c tele.Context) error { + return c.Send(fmt.Sprintf("I am sending alerts through %d chat id", environment.ChatID)) }) bot.Handle("/ping", func(c tele.Context) error { - return c.Send("pong!") + if environment.Mute { + return c.Send(messages.PongText + " I am currently sleeping" + messages.SleepingMsg) + } + return c.Send(messages.PongText + " I am monitoring" + messages.MonitoringMsg) }) bot.Handle("/start", func(c tele.Context) error { - environment.Mute = true - return c.Send("Started working...") + if environment.Mute { + environment.Mute = false + return c.Send("I had been asleep, but started monitoring now... " + messages.MonitoringMsg) + } + return c.Send("I had already been monitoring" + messages.MonitoringMsg) }) bot.Handle("/mute", func(c tele.Context) error { - environment.Mute = false - return c.Send("Say no more..") + if environment.Mute { + return c.Send("I had already been sleeping, continue sleeping.." + messages.SleepingMsg) + } + environment.Mute = true + return c.Send("I had been monitoring, but going to sleep now.." + messages.SleepingMsg) }) bot.Handle("/help", func(c tele.Context) error { - replyKeyboard := base_messages.HelpCommandKeyboard() return c.Send( - base_messages.HelpInfoText2, - &tele.SendOptions{ - ParseMode: tele.ModeHTML, - ReplyMarkup: &tele.ReplyMarkup{ - OneTimeKeyboard: true, - ResizeKeyboard: true, - ReplyKeyboard: replyKeyboard, - }, - }) + messages.HelpInfoText, + &tele.SendOptions{ParseMode: tele.ModeHTML}) }) } diff --git a/cmd/tg_bot/internal/init/init.go b/cmd/tg_bot/internal/init/init.go index 689a7a8b..cf4d78a1 100644 --- a/cmd/tg_bot/internal/init/init.go +++ b/cmd/tg_bot/internal/init/init.go @@ -1,19 +1,20 @@ package init import ( + "log" + "github.com/pkg/errors" tele "gopkg.in/telebot.v3" "nodemon/cmd/tg_bot/internal" "nodemon/cmd/tg_bot/internal/config" "nodemon/cmd/tg_bot/internal/handlers" - "nodemon/pkg/storing/chats" ) func InitTgBot(behavior string, webhookLocalAddress string, publicURL string, botToken string, - storagePath string, + chatID int64, ) (*internal.TelegramBotEnvironment, error) { botSettings, err := config.NewBotSettings(behavior, webhookLocalAddress, publicURL, botToken) if err != nil { @@ -24,12 +25,9 @@ func InitTgBot(behavior string, return nil, errors.Wrap(err, "failed to start bot") } - stor, err := chats.NewStorage(storagePath) - if err != nil { - return nil, errors.Wrap(err, "failed to initialize storage") - } + log.Printf("chat id for sending alerts is %d", chatID) - tgBotEnv := internal.NewTelegramBotEnvironment(bot, stor, false) + tgBotEnv := internal.NewTelegramBotEnvironment(bot, chatID, false) handlers.InitHandlers(bot, tgBotEnv) return tgBotEnv, nil } diff --git a/cmd/tg_bot/internal/messages/alert_messages.go b/cmd/tg_bot/internal/messages/alert_messages.go new file mode 100644 index 00000000..08a1ab20 --- /dev/null +++ b/cmd/tg_bot/internal/messages/alert_messages.go @@ -0,0 +1,6 @@ +package messages + +const ( + ErrorMsg = "❌" + infoMsg = "ℹī¸" +) diff --git a/cmd/tg_bot/internal/messages/base_messages.go b/cmd/tg_bot/internal/messages/base_messages.go new file mode 100644 index 00000000..9b1170e9 --- /dev/null +++ b/cmd/tg_bot/internal/messages/base_messages.go @@ -0,0 +1,18 @@ +package messages + +const ( + MonitoringMsg = "📡" + SleepingMsg = "💤" + PongMsg = "🏓" + + HelpInfoText = infoMsg + " This is a bot for monitoring Waves nodes. The next commands are available:\n\n" + + "/ping - the command to check whether the bot is available and what his current state is\n" + + "/hello - the command to make the bot save this chat for alerts. Needs to be done first time\n" + + "/start - the command to make the bot start getting alerts\n" + + "/mute - the command to make the bot stop listening to alerts" + + "/help - the command to see information about bot and available commands" + + MuteText = "Say no more..." + SleepingMsg + PongText = "Pong!" + PongMsg + StartText = "Started monitoring..." + MonitoringMsg +) diff --git a/cmd/tg_bot/internal/templates/alert.html b/cmd/tg_bot/internal/templates/alert.html new file mode 100644 index 00000000..783d6a31 --- /dev/null +++ b/cmd/tg_bot/internal/templates/alert.html @@ -0,0 +1,5 @@ +Alert type: {{ .AlertType}} + +Severity: {{ .Severity}} + +Details: {{ .Details}} diff --git a/pkg/entities/alerts.go b/pkg/entities/alerts.go index 65506024..b2fab1e6 100644 --- a/pkg/entities/alerts.go +++ b/pkg/entities/alerts.go @@ -10,14 +10,36 @@ import ( "github.com/wavesplatform/gowaves/pkg/proto" ) +type AlertType byte + +const ( + SimpleAlertType AlertType = iota + 1 + UnreachableAlertType + IncompleteAlertType + InvalidHeightAlertType + HeightAlertType + StateHashAlertType + AlertFixedType +) + +var AlertTypes = map[AlertType]string{ + SimpleAlertType: SimpleAlertNotification, + UnreachableAlertType: UnreachableAlertNotification, + IncompleteAlertType: IncompleteAlertNotification, + InvalidHeightAlertType: InvalidHeightAlertNotification, + HeightAlertType: HeightAlertNotification, + StateHashAlertType: StateHashAlertNotification, + AlertFixedType: AlertFixedNotification, +} + const ( - SimpleAlertNotificationType = "SimpleAlert" - UnreachableAlertNotificationType = "UnreachableAlert" - IncompleteAlertNotificationType = "IncompleteAlert" - InvalidHeightAlertNotificationType = "InvalidHeightAlert" - HeightAlertNotificationType = "HeightAlert" - StateHashAlertNotificationType = "StateHashAlert" - AlertFixedNotificationType = "AlertFixed" + SimpleAlertNotification = "SimpleAlert" + UnreachableAlertNotification = "UnreachableAlert" + IncompleteAlertNotification = "IncompleteAlert" + InvalidHeightAlertNotification = "InvalidHeightAlert" + HeightAlertNotification = "HeightAlert" + StateHashAlertNotification = "StateHashAlert" + AlertFixedNotification = "AlertFixed" ) type Alert interface { @@ -25,6 +47,7 @@ type Alert interface { ID() string Message() string Time() time.Time + Type() AlertType fmt.Stringer } @@ -33,8 +56,8 @@ type SimpleAlert struct { Description string `json:"description"` } -func (a *SimpleAlert) Type() string { - return SimpleAlertNotificationType +func (a *SimpleAlert) ShortDescription() string { + return SimpleAlertNotification } func (a *SimpleAlert) Message() string { @@ -46,12 +69,16 @@ func (a *SimpleAlert) Time() time.Time { } func (a *SimpleAlert) ID() string { - digest := crypto.MustFastHash([]byte(a.Type() + a.Description)) + digest := crypto.MustFastHash([]byte(a.ShortDescription() + a.Description)) return digest.String() } func (a *SimpleAlert) String() string { - return fmt.Sprintf("%s: %s", a.Type(), a.Message()) + return fmt.Sprintf("%s: %s", a.ShortDescription(), a.Message()) +} + +func (a *SimpleAlert) Type() AlertType { + return SimpleAlertType } type UnreachableAlert struct { @@ -59,8 +86,8 @@ type UnreachableAlert struct { Node string `json:"node"` } -func (a *UnreachableAlert) Type() string { - return UnreachableAlertNotificationType +func (a *UnreachableAlert) ShortDescription() string { + return UnreachableAlertNotification } func (a *UnreachableAlert) Message() string { @@ -72,20 +99,24 @@ func (a *UnreachableAlert) Time() time.Time { } func (a *UnreachableAlert) ID() string { - digest := crypto.MustFastHash([]byte(a.Type() + a.Node)) + digest := crypto.MustFastHash([]byte(a.ShortDescription() + a.Node)) return digest.String() } func (a *UnreachableAlert) String() string { - return fmt.Sprintf("%s: %s", a.Type(), a.Message()) + return fmt.Sprintf("%s: %s", a.ShortDescription(), a.Message()) +} + +func (a *UnreachableAlert) Type() AlertType { + return UnreachableAlertType } type IncompleteAlert struct { NodeStatement } -func (a *IncompleteAlert) Type() string { - return IncompleteAlertNotificationType +func (a *IncompleteAlert) ShortDescription() string { + return IncompleteAlertNotification } func (a *IncompleteAlert) Message() string { @@ -97,20 +128,24 @@ func (a *IncompleteAlert) Time() time.Time { } func (a *IncompleteAlert) String() string { - return fmt.Sprintf("%s: %s", a.Type(), a.Message()) + return fmt.Sprintf("%s: %s", a.ShortDescription(), a.Message()) } func (a *IncompleteAlert) ID() string { - digest := crypto.MustFastHash([]byte(a.Type() + a.Node)) + digest := crypto.MustFastHash([]byte(a.ShortDescription() + a.Node)) return digest.String() } +func (a *IncompleteAlert) Type() AlertType { + return IncompleteAlertType +} + type InvalidHeightAlert struct { NodeStatement } -func (a *InvalidHeightAlert) Type() string { - return InvalidHeightAlertNotificationType +func (a *InvalidHeightAlert) ShortDescription() string { + return InvalidHeightAlertNotification } func (a *InvalidHeightAlert) Message() string { @@ -122,14 +157,18 @@ func (a *InvalidHeightAlert) Time() time.Time { } func (a *InvalidHeightAlert) String() string { - return fmt.Sprintf("%s: %s", a.Type(), a.Message()) + return fmt.Sprintf("%s: %s", a.ShortDescription(), a.Message()) } func (a *InvalidHeightAlert) ID() string { - digest := crypto.MustFastHash([]byte(a.Type() + a.Node)) + digest := crypto.MustFastHash([]byte(a.ShortDescription() + a.Node)) return digest.String() } +func (a *InvalidHeightAlert) Type() AlertType { + return InvalidHeightAlertType +} + type HeightGroup struct { Height int `json:"height"` Nodes Nodes `json:"group"` @@ -141,8 +180,8 @@ type HeightAlert struct { OtherHeightGroup HeightGroup `json:"other_height_group"` } -func (a *HeightAlert) Type() string { - return HeightAlertNotificationType +func (a *HeightAlert) ShortDescription() string { + return HeightAlertNotification } func (a *HeightAlert) Message() string { @@ -160,12 +199,12 @@ func (a *HeightAlert) Time() time.Time { } func (a *HeightAlert) String() string { - return fmt.Sprintf("%s: %s", a.Type(), a.Message()) + return fmt.Sprintf("%s: %s", a.ShortDescription(), a.Message()) } func (a *HeightAlert) ID() string { var buff bytes.Buffer - buff.WriteString(a.Type()) + buff.WriteString(a.ShortDescription()) for _, node := range a.MaxHeightGroup.Nodes { buff.WriteString(node) @@ -179,6 +218,10 @@ func (a *HeightAlert) ID() string { return digest.String() } +func (a *HeightAlert) Type() AlertType { + return HeightAlertType +} + type StateHashGroup struct { Nodes Nodes `json:"nodes"` StateHash proto.StateHash `json:"state_hash"` @@ -194,8 +237,8 @@ type StateHashAlert struct { SecondGroup StateHashGroup `json:"second_group"` } -func (a *StateHashAlert) Type() string { - return StateHashAlertNotificationType +func (a *StateHashAlert) ShortDescription() string { + return StateHashAlertNotification } func (a *StateHashAlert) Message() string { @@ -227,12 +270,12 @@ func (a *StateHashAlert) Time() time.Time { } func (a *StateHashAlert) String() string { - return fmt.Sprintf("%s: %s", a.Type(), a.Message()) + return fmt.Sprintf("%s: %s", a.ShortDescription(), a.Message()) } func (a *StateHashAlert) ID() string { var buff bytes.Buffer - buff.WriteString(a.Type()) + buff.WriteString(a.ShortDescription()) if a.LastCommonStateHashExist { buff.WriteString(strconv.Itoa(a.LastCommonStateHashHeight)) @@ -250,17 +293,21 @@ func (a *StateHashAlert) ID() string { return digest.String() } +func (a *StateHashAlert) Type() AlertType { + return StateHashAlertType +} + type AlertFixed struct { Timestamp int64 `json:"timestamp"` Fixed Alert `json:"fixed"` } -func (a *AlertFixed) Type() string { - return AlertFixedNotificationType +func (a *AlertFixed) ShortDescription() string { + return AlertFixedNotification } func (a *AlertFixed) ID() string { - digest := crypto.MustFastHash([]byte(a.Type() + a.Fixed.ID())) + digest := crypto.MustFastHash([]byte(a.ShortDescription() + a.Fixed.ID())) return digest.String() } @@ -273,5 +320,9 @@ func (a *AlertFixed) Time() time.Time { } func (a *AlertFixed) String() string { - return fmt.Sprintf("%s: %s", a.Type(), a.Message()) + return fmt.Sprintf("%s: %s", a.ShortDescription(), a.Message()) +} + +func (a *AlertFixed) Type() AlertType { + return AlertFixedType } diff --git a/pkg/entities/notifications.go b/pkg/entities/notifications.go index f84a6e5b..b0c98045 100644 --- a/pkg/entities/notifications.go +++ b/pkg/entities/notifications.go @@ -5,7 +5,7 @@ const ( ) type Notification interface { - Type() string + ShortDescription() string } type OnPollingComplete struct { @@ -17,7 +17,7 @@ func NewOnPollingComplete(nodes []string, ts int64) *OnPollingComplete { return &OnPollingComplete{nodes: nodes, ts: ts} } -func (n *OnPollingComplete) Type() string { +func (n *OnPollingComplete) ShortDescription() string { return OnPollingCompleteNotificationType } diff --git a/pkg/messaging/client.go b/pkg/messaging/client.go index 1e9d91a3..88f54a91 100644 --- a/pkg/messaging/client.go +++ b/pkg/messaging/client.go @@ -5,10 +5,22 @@ import ( "log" "go.nanomsg.org/mangos/v3" + "go.nanomsg.org/mangos/v3/protocol" "go.nanomsg.org/mangos/v3/protocol/sub" _ "go.nanomsg.org/mangos/v3/transport/all" + "nodemon/pkg/entities" ) +func subscribeToAlerts(socket protocol.Socket) error { + for alertType := range entities.AlertTypes { + err := socket.SetOption(mangos.OptionSubscribe, []byte{byte(alertType)}) + if err != nil { + return err + } + } + return nil +} + func StartMessagingClient(ctx context.Context, nanomsgURL string, bot Bot) error { socket, err := sub.NewSocket() if err != nil { @@ -19,7 +31,7 @@ func StartMessagingClient(ctx context.Context, nanomsgURL string, bot Bot) error log.Printf("failed to dial on sub socket: %v", err) return err } - err = socket.SetOption(mangos.OptionSubscribe, []byte("")) + err = subscribeToAlerts(socket) if err != nil { log.Printf("failed to subscribe on empty topic: %v", err) return err diff --git a/pkg/storing/chats/chats.go b/pkg/storing/chats/chats.go deleted file mode 100644 index d6e306fd..00000000 --- a/pkg/storing/chats/chats.go +++ /dev/null @@ -1,90 +0,0 @@ -package chats - -import ( - "log" - - "github.com/jameycribbs/hare" - "github.com/jameycribbs/hare/datastores/disk" - "github.com/pkg/errors" - "nodemon/pkg/entities" - "nodemon/pkg/storing/common" -) - -const ( - chatsTableName = "chats" -) - -var ( - ErrorChatNotFound = errors.New("Chat ID is not found") -) - -type chat struct { - ID int `json:"id"` - Chat entities.Chat -} - -func (c *chat) GetID() int { - return c.ID -} - -func (c *chat) SetID(id int) { - c.ID = id -} - -// AfterFind required by Hare function -func (c *chat) AfterFind(_ *hare.Database) error { - return nil -} - -type Storage struct { - db *hare.Database -} - -func NewStorage(path string) (*Storage, error) { - ds, err := disk.New(path, common.DefaultStorageExtension) - if err != nil { - return nil, errors.Wrapf(err, "failed to open nodes storage at '%s'", path) - } - db, err := hare.New(ds) - if err != nil { - return nil, errors.Wrapf(err, "failed to open nodes storage at '%s'", path) - } - if !db.TableExists(chatsTableName) { - if err := db.CreateTable(chatsTableName); err != nil { - return nil, errors.Wrapf(err, "failed to initialize chat storage at '%s'", path) - } - } - cs := &Storage{db: db} - - return cs, nil -} - -func (cs *Storage) InsertChatID(chatID entities.ChatID, platform entities.Platform) error { - id, err := cs.db.Insert(chatsTableName, &chat{Chat: entities.Chat{ChatID: chatID, Platform: platform}}) - if err != nil { - return err - } - log.Printf("New chat #%d stored", id) - return nil -} - -func (cs *Storage) FindChatID(platform entities.Platform) (*entities.ChatID, error) { - ids, err := cs.db.IDs(chatsTableName) - if err != nil { - return nil, err - } - var chats []chat - for _, id := range ids { - var ch chat - if err := cs.db.Find(chatsTableName, id, &ch); err != nil { - return nil, err - } - chats = append(chats, ch) - } - for _, chat := range chats { - if chat.Chat.Platform == platform { - return &chat.Chat.ChatID, nil - } - } - return nil, ErrorChatNotFound -} diff --git a/units/nodemon.service b/units/nodemon.service new file mode 100644 index 00000000..09c3041a --- /dev/null +++ b/units/nodemon.service @@ -0,0 +1,17 @@ +[Unit] +Description=Waves nodes monitoring + +Wants=network.target +After=syslog.target network-online.target + +[Service] +Type=simple +ExecStart= +Restart=on-failure +RestartSec=10 +KillMode=process +StandardOutput=syslog +StandardError=syslog + +[Install] +WantedBy=multi-user.target diff --git a/units/tg_bot.service b/units/tg_bot.service new file mode 100644 index 00000000..fb4b6766 --- /dev/null +++ b/units/tg_bot.service @@ -0,0 +1,17 @@ +[Unit] +Description=Telegram bot for monitoring display + +Wants=network.target +After=syslog.target network-online.target + +[Service] +Type=simple +ExecStart= +Restart=on-failure +RestartSec=10 +KillMode=process +StandardOutput=syslog +StandardError=syslog + +[Install] +WantedBy=multi-user.target