diff --git a/.golangci.yml b/.golangci.yml index cee9361..0852cfd 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -54,3 +54,4 @@ linters: - durationcheck - gocyclo - exhaustive + - mnd diff --git a/pkg/reporters/discord/discord.go b/pkg/reporters/discord/discord.go index 4c2d666..e7405a9 100644 --- a/pkg/reporters/discord/discord.go +++ b/pkg/reporters/discord/discord.go @@ -9,6 +9,7 @@ import ( statePkg "main/pkg/state" templatesPkg "main/pkg/templates" types "main/pkg/types" + "main/pkg/utils" "strings" "sync" "time" @@ -82,6 +83,7 @@ func (reporter *Reporter) Init() { reporter.Commands = map[string]*Command{ "params": reporter.GetParamsCommand(), "missing": reporter.GetMissingCommand(), + "validators": reporter.GetValidatorsCommand(), "subscribe": reporter.GetSubscribeCommand(), "unsubscribe": reporter.GetUnsubscribeCommand(), "status": reporter.GetStatusCommand(), @@ -199,16 +201,28 @@ func (reporter *Reporter) Send(report *types.Report) error { } func (reporter *Reporter) BotRespond(s *discordgo.Session, i *discordgo.InteractionCreate, text string) { - err := s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ + chunks := utils.SplitStringIntoChunks(text, 2000) + firstChunk, rest := chunks[0], chunks[1:] + + if err := s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ - Content: text, + Content: firstChunk, }, - }) - - if err != nil { + }); err != nil { reporter.Logger.Error().Err(err).Msg("Error sending response") } + + for index, chunk := range rest { + if _, err := s.FollowupMessageCreate(i.Interaction, false, &discordgo.WebhookParams{ + Content: chunk, + }); err != nil { + reporter.Logger.Error(). + Int("chunk", index). + Err(err). + Msg("Error sending followup message") + } + } } func (reporter *Reporter) SerializeDate(date time.Time) string { diff --git a/pkg/reporters/discord/help.go b/pkg/reporters/discord/help.go index 8bea503..81392e2 100644 --- a/pkg/reporters/discord/help.go +++ b/pkg/reporters/discord/help.go @@ -24,14 +24,7 @@ func (reporter *Reporter) GetHelpCommand() *Command { return } - if err = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ - Type: discordgo.InteractionResponseChannelMessageWithSource, - Data: &discordgo.InteractionResponseData{ - Content: template, - }, - }); err != nil { - reporter.Logger.Error().Err(err).Msg("Error sending help") - } + reporter.BotRespond(s, i, template) }, } } diff --git a/pkg/reporters/discord/missing.go b/pkg/reporters/discord/missing.go index d1fae1e..429fd41 100644 --- a/pkg/reporters/discord/missing.go +++ b/pkg/reporters/discord/missing.go @@ -66,18 +66,7 @@ func (reporter *Reporter) GetMissingCommand() *Command { return } - chunks := utils.SplitStringIntoChunks(template, 2000) - - for _, chunk := range chunks { - if err = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ - Type: discordgo.InteractionResponseChannelMessageWithSource, - Data: &discordgo.InteractionResponseData{ - Content: chunk, - }, - }); err != nil { - reporter.Logger.Error().Err(err).Msg("Error sending missing") - } - } + reporter.BotRespond(s, i, template) }, } } diff --git a/pkg/reporters/discord/params.go b/pkg/reporters/discord/params.go index 2d509b8..abd5214 100644 --- a/pkg/reporters/discord/params.go +++ b/pkg/reporters/discord/params.go @@ -36,14 +36,7 @@ func (reporter *Reporter) GetParamsCommand() *Command { return } - if err = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ - Type: discordgo.InteractionResponseChannelMessageWithSource, - Data: &discordgo.InteractionResponseData{ - Content: template, - }, - }); err != nil { - reporter.Logger.Error().Err(err).Msg("Error sending params") - } + reporter.BotRespond(s, i, template) }, } } diff --git a/pkg/reporters/discord/validators.go b/pkg/reporters/discord/validators.go new file mode 100644 index 0000000..435be35 --- /dev/null +++ b/pkg/reporters/discord/validators.go @@ -0,0 +1,67 @@ +package discord + +import ( + "fmt" + "main/pkg/constants" + snapshotPkg "main/pkg/snapshot" + "main/pkg/utils" + "sort" + + "github.com/bwmarrin/discordgo" +) + +func (reporter *Reporter) GetValidatorsCommand() *Command { + return &Command{ + Info: &discordgo.ApplicationCommand{ + Name: "validators", + Description: "Get the list of all validators and their missing blocks", + }, + Handler: func(s *discordgo.Session, i *discordgo.InteractionCreate) { + reporter.MetricsManager.LogReporterQuery(reporter.Config.Name, constants.TelegramReporterName, "validators") + + snapshot, found := reporter.SnapshotManager.GetNewerSnapshot() + if !found { + reporter.Logger.Info(). + Msg("No older snapshot on discord validators query!") + reporter.BotRespond(s, i, "Error getting validators list") + return + } + + validatorEntries := snapshot.Entries.ToSlice() + activeValidatorsEntries := utils.Filter(validatorEntries, func(v snapshotPkg.Entry) bool { + return v.Validator.Active() + }) + + sort.Slice(activeValidatorsEntries, func(firstIndex, secondIndex int) bool { + first := activeValidatorsEntries[firstIndex] + second := activeValidatorsEntries[secondIndex] + + return first.SignatureInfo.GetNotSigned() < second.SignatureInfo.GetNotSigned() + }) + + render := missingValidatorsRender{ + Config: reporter.Config, + Validators: utils.Map(activeValidatorsEntries, func(v snapshotPkg.Entry) missingValidatorsEntry { + link := reporter.Config.ExplorerConfig.GetValidatorLink(v.Validator) + group, _, _ := reporter.Config.MissedBlocksGroups.GetGroup(v.SignatureInfo.GetNotSigned()) + link.Text = fmt.Sprintf("%s %s", group.EmojiEnd, v.Validator.Moniker) + + return missingValidatorsEntry{ + Validator: v.Validator, + Link: link, + NotSigned: v.SignatureInfo.GetNotSigned(), + BlocksWindow: reporter.Config.BlocksWindow, + } + }), + } + + template, err := reporter.TemplatesManager.Render("Validators", render) + if err != nil { + reporter.Logger.Error().Err(err).Msg("Error rendering missing") + return + } + + reporter.BotRespond(s, i, template) + }, + } +} diff --git a/templates/discord/Help.md b/templates/discord/Help.md index 2b78b78..147c560 100644 --- a/templates/discord/Help.md +++ b/templates/discord/Help.md @@ -10,7 +10,7 @@ The bot can understand the following commands: - [validator address] - subscribe to validator's notifications - [validator address] - unsubscribe from validator's notifications - - see the notification on validators you are subscribed to -- /missing - see the missed blocks counter of validators missing blocks -- /validators - see the missed blocks counter of all validators +- - see the missed blocks counter of validators missing blocks +- - see the missed blocks counter of all validators - - see the app config and chain params - - see notifiers for each validator diff --git a/templates/discord/Status.md b/templates/discord/Status.md index db76ddf..a70dd36 100644 --- a/templates/discord/Status.md +++ b/templates/discord/Status.md @@ -10,4 +10,4 @@ You are subscribed to the following validators' updates on {{ .ChainConfig.GetNa {{- else -}} **{{ SerializeLink .Link }}** ({{ $render.FormatVotingPower . }}): {{ .SigningInfo.GetNotSigned }} missed blocks ({{ $render.FormatNotSignedPercent . }}%) {{- end -}} -{{ end }} \ No newline at end of file +{{ end }} diff --git a/templates/discord/Validators.md b/templates/discord/Validators.md new file mode 100644 index 0000000..a39fa1f --- /dev/null +++ b/templates/discord/Validators.md @@ -0,0 +1,8 @@ +{{- if not .Validators }} +There are no active validators on {{ .Config.GetName }}! +{{- else }} +**Validators' status on {{ .Config.GetName }}:** +{{- end }} +{{ range .Validators -}} +**{{ SerializeLink .Link }}**: {{ .NotSigned }} missed blocks ({{ .FormatMissed }}%) +{{ end }}