feat: Add notification templates (#2)
Signed-off-by: Julien Riou <julien@riou.xyz>
This commit is contained in:
parent
b9902f0623
commit
632da28954
11 changed files with 154 additions and 67 deletions
27
README.md
27
README.md
|
@ -78,6 +78,33 @@ Reference:
|
||||||
* `token`: token of the Telegram bot
|
* `token`: token of the Telegram bot
|
||||||
* `chat-id` (optional if `channel-name` is present): chat identifier to send Telegram notifications
|
* `chat-id` (optional if `channel-name` is present): chat identifier to send Telegram notifications
|
||||||
* `channel-name` (optional if `chat-id` is present): channel name to send Telegram notifications
|
* `channel-name` (optional if `chat-id` is present): channel name to send Telegram notifications
|
||||||
|
* `notification-templates` (optional): path to [template](https://pkg.go.dev/text/template) files for each notification type
|
||||||
|
* `balance` (optional): path to template file to format balance notifications
|
||||||
|
* `payment` (optional): path to template file to format payment notifications
|
||||||
|
* `block` (optional): path to template file to format block notifications
|
||||||
|
* `offline-worker` (optional): path to template file to format offline worker notifications
|
||||||
|
|
||||||
|
## Templating
|
||||||
|
|
||||||
|
Notifications can be customized with [templating](https://pkg.go.dev/text/template).
|
||||||
|
|
||||||
|
The following **functions** are available to templates:
|
||||||
|
* `upper(str string)`: convert string to upper case
|
||||||
|
* `lower(str string)`: convert string to lower case
|
||||||
|
* `convertCurrency(coin string, value int64)`: convert the smallest unit of a coin to a human readable unit
|
||||||
|
* `convertAction(coin string)`: return "Farmed" word for Chia coin or "Mined" for other coins
|
||||||
|
* `formatBlockURL(coin string, hash string)`: return the URL on the explorer website of the coin of the block identified by its hash
|
||||||
|
* `formatTransactionURL(coin string, hash string)`: return the URL on the explorer website of the coin of the transaction identified by its hash
|
||||||
|
|
||||||
|
The following **data** is available to templates:
|
||||||
|
* balance: `.Miner`
|
||||||
|
* payment: `.Miner`, `.Payment`
|
||||||
|
* block: `.Pool`, `.Block`
|
||||||
|
* offline-worker: `.Worker`
|
||||||
|
|
||||||
|
Default templates are available in the [templates](templates) directory.
|
||||||
|
|
||||||
|
Custom template files can be used with the `notification-templates` settings (see _Configuration_ section).
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
|
21
config.go
21
config.go
|
@ -8,12 +8,13 @@ import (
|
||||||
|
|
||||||
// Config to receive settings from the configuration file
|
// Config to receive settings from the configuration file
|
||||||
type Config struct {
|
type Config struct {
|
||||||
DatabaseFile string `yaml:"database-file"`
|
DatabaseFile string `yaml:"database-file"`
|
||||||
MaxBlocks int `yaml:"max-blocks"`
|
MaxBlocks int `yaml:"max-blocks"`
|
||||||
MaxPayments int `yaml:"max-payments"`
|
MaxPayments int `yaml:"max-payments"`
|
||||||
Pools []PoolConfig `yaml:"pools"`
|
Pools []PoolConfig `yaml:"pools"`
|
||||||
Miners []MinerConfig `yaml:"miners"`
|
Miners []MinerConfig `yaml:"miners"`
|
||||||
TelegramConfig TelegramConfig `yaml:"telegram"`
|
TelegramConfig TelegramConfig `yaml:"telegram"`
|
||||||
|
NotificationTemplates NotificationTemplatesConfig `yaml:"notification-templates"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// PoolConfig to store Pool configuration
|
// PoolConfig to store Pool configuration
|
||||||
|
@ -37,6 +38,14 @@ type TelegramConfig struct {
|
||||||
ChannelName string `yaml:"channel-name"`
|
ChannelName string `yaml:"channel-name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NotificationTemplatesConfig to store notifications templates configuration
|
||||||
|
type NotificationTemplatesConfig struct {
|
||||||
|
Balance string `yaml:"balance"`
|
||||||
|
Payment string `yaml:"payment"`
|
||||||
|
Block string `yaml:"block"`
|
||||||
|
OfflineWorker string `yaml:"offline-worker"`
|
||||||
|
}
|
||||||
|
|
||||||
// NewConfig creates a Config with default values
|
// NewConfig creates a Config with default values
|
||||||
func NewConfig() *Config {
|
func NewConfig() *Config {
|
||||||
return &Config{
|
return &Config{
|
||||||
|
|
|
@ -20,3 +20,8 @@ telegram:
|
||||||
chat-id: 000000000
|
chat-id: 000000000
|
||||||
channel-name: MyTelegramChannel
|
channel-name: MyTelegramChannel
|
||||||
token: 0000000000000000000000000000000000000000000000
|
token: 0000000000000000000000000000000000000000000000
|
||||||
|
notification-templates:
|
||||||
|
balance: balance.tmpl
|
||||||
|
block: block.tmpl
|
||||||
|
offline-worker; offline-worker.tmpl
|
||||||
|
payment: payment.tmpl
|
1
go.mod
1
go.mod
|
@ -4,7 +4,6 @@ go 1.16
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.0.0-rc1
|
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.0.0-rc1
|
||||||
github.com/leekchan/accounting v1.0.0 // indirect
|
|
||||||
github.com/sirupsen/logrus v1.8.1
|
github.com/sirupsen/logrus v1.8.1
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
|
||||||
gorm.io/driver/sqlite v1.1.5
|
gorm.io/driver/sqlite v1.1.5
|
||||||
|
|
9
go.sum
9
go.sum
|
@ -1,5 +1,3 @@
|
||||||
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
|
|
||||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.0.0-rc1 h1:Mr8jIV7wDfLw5Fw6BPupm0aduTFdLjhI3wFuIIZKvO4=
|
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.0.0-rc1 h1:Mr8jIV7wDfLw5Fw6BPupm0aduTFdLjhI3wFuIIZKvO4=
|
||||||
|
@ -8,17 +6,10 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD
|
||||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||||
github.com/jinzhu/now v1.1.2 h1:eVKgfIdy9b6zbWBMgFpfDPoAMifwSZagU9HmEU6zgiI=
|
github.com/jinzhu/now v1.1.2 h1:eVKgfIdy9b6zbWBMgFpfDPoAMifwSZagU9HmEU6zgiI=
|
||||||
github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||||
github.com/leekchan/accounting v1.0.0 h1:+Wd7dJ//dFPa28rc1hjyy+qzCbXPMR91Fb6F1VGTQHg=
|
|
||||||
github.com/leekchan/accounting v1.0.0/go.mod h1:3timm6YPhY3YDaGxl0q3eaflX0eoSx3FXn7ckHe4tO0=
|
|
||||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
|
||||||
github.com/mattn/go-sqlite3 v1.14.8 h1:gDp86IdQsN/xWjIEmr9MF6o9mpksUgh0fu+9ByFxzIU=
|
github.com/mattn/go-sqlite3 v1.14.8 h1:gDp86IdQsN/xWjIEmr9MF6o9mpksUgh0fu+9ByFxzIU=
|
||||||
github.com/mattn/go-sqlite3 v1.14.8/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
github.com/mattn/go-sqlite3 v1.14.8/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 h1:pntxY8Ary0t43dCZ5dqY4YTJCObLY1kIXl0uzMv+7DE=
|
|
||||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
|
||||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||||
|
|
2
main.go
2
main.go
|
@ -84,7 +84,7 @@ func main() {
|
||||||
client := NewFlexpoolClient()
|
client := NewFlexpoolClient()
|
||||||
|
|
||||||
// Notifications
|
// Notifications
|
||||||
notifier, err := NewTelegramNotifier(&config.TelegramConfig)
|
notifier, err := NewTelegramNotifier(&config.TelegramConfig, &config.NotificationTemplates)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Could not create notifier: %v", err)
|
log.Fatalf("Could not create notifier: %v", err)
|
||||||
}
|
}
|
||||||
|
|
141
notification.go
141
notification.go
|
@ -1,15 +1,30 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"embed"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
"text/template"
|
||||||
"github.com/leekchan/accounting"
|
|
||||||
|
|
||||||
telegram "github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
telegram "github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//go:embed templates
|
||||||
|
var templateFiles embed.FS
|
||||||
|
|
||||||
|
// Attachment is used to attach objects to templates
|
||||||
|
type Attachment struct {
|
||||||
|
Miner Miner
|
||||||
|
Payment Payment
|
||||||
|
Pool Pool
|
||||||
|
Block Block
|
||||||
|
Worker Worker
|
||||||
|
}
|
||||||
|
|
||||||
// Notifier interface to define how to send all kind of notifications
|
// Notifier interface to define how to send all kind of notifications
|
||||||
type Notifier interface {
|
type Notifier interface {
|
||||||
NotifyBalance(miner Miner, difference float64) error
|
NotifyBalance(miner Miner, difference float64) error
|
||||||
|
@ -21,13 +36,14 @@ type Notifier interface {
|
||||||
// TelegramNotifier to send notifications using Telegram
|
// TelegramNotifier to send notifications using Telegram
|
||||||
// Implements the Notifier interface
|
// Implements the Notifier interface
|
||||||
type TelegramNotifier struct {
|
type TelegramNotifier struct {
|
||||||
bot *telegram.BotAPI
|
bot *telegram.BotAPI
|
||||||
chatID int64
|
chatID int64
|
||||||
channelName string
|
channelName string
|
||||||
|
templatesConfig *NotificationTemplatesConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTelegramNotifier to create a TelegramNotifier
|
// NewTelegramNotifier to create a TelegramNotifier
|
||||||
func NewTelegramNotifier(config *TelegramConfig) (*TelegramNotifier, error) {
|
func NewTelegramNotifier(config *TelegramConfig, templatesConfig *NotificationTemplatesConfig) (*TelegramNotifier, error) {
|
||||||
bot, err := telegram.NewBotAPI(config.Token)
|
bot, err := telegram.NewBotAPI(config.Token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -35,9 +51,10 @@ func NewTelegramNotifier(config *TelegramConfig) (*TelegramNotifier, error) {
|
||||||
log.Debugf("Connected to Telegram as %s", bot.Self.UserName)
|
log.Debugf("Connected to Telegram as %s", bot.Self.UserName)
|
||||||
|
|
||||||
return &TelegramNotifier{
|
return &TelegramNotifier{
|
||||||
bot: bot,
|
bot: bot,
|
||||||
chatID: config.ChatID,
|
chatID: config.ChatID,
|
||||||
channelName: config.ChannelName,
|
channelName: config.ChannelName,
|
||||||
|
templatesConfig: templatesConfig,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,77 +77,103 @@ func (t *TelegramNotifier) sendMessage(message string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// formatMessage to create a message with a template file name (either embeded or on disk)
|
||||||
|
func (t *TelegramNotifier) formatMessage(templateFileName string, attachment interface{}) (message string, err error) {
|
||||||
|
// Deduce if template file is embeded or is a file on disk
|
||||||
|
embeded := true
|
||||||
|
if _, err = os.Stat(templateFileName); os.IsExist(err) {
|
||||||
|
embeded = false
|
||||||
|
}
|
||||||
|
// Reinitialize the error because it was only used for the test
|
||||||
|
err = nil
|
||||||
|
|
||||||
|
// Create template
|
||||||
|
templateName := path.Base(templateFileName)
|
||||||
|
templateFunctions := template.FuncMap{
|
||||||
|
"upper": strings.ToUpper,
|
||||||
|
"lower": strings.ToLower,
|
||||||
|
"convertCurrency": ConvertCurrency,
|
||||||
|
"convertAction": ConvertAction,
|
||||||
|
"formatBlockURL": FormatBlockURL,
|
||||||
|
"formatTransactionURL": FormatTransactionURL,
|
||||||
|
}
|
||||||
|
tmpl := template.New(templateName).Funcs(templateFunctions)
|
||||||
|
|
||||||
|
// Parse template
|
||||||
|
if embeded {
|
||||||
|
log.Debugf("Parsing embeded template file %s", templateFileName)
|
||||||
|
tmpl, err = tmpl.ParseFS(templateFiles, templateFileName)
|
||||||
|
} else {
|
||||||
|
log.Debugf("Parsing template file %s", templateFileName)
|
||||||
|
tmpl, err = tmpl.ParseFiles(templateFileName)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("parse failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute template
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
err = tmpl.Execute(&buffer, attachment)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("execute failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract and return the formatted message
|
||||||
|
message = buffer.String()
|
||||||
|
return message, nil
|
||||||
|
}
|
||||||
|
|
||||||
// NotifyBalance to format and send a notification when the unpaid balance has changed
|
// NotifyBalance to format and send a notification when the unpaid balance has changed
|
||||||
// Implements the Notifier interface
|
// Implements the Notifier interface
|
||||||
func (t *TelegramNotifier) NotifyBalance(miner Miner) error {
|
func (t *TelegramNotifier) NotifyBalance(miner Miner) (err error) {
|
||||||
ac := accounting.Accounting{
|
templateName := "templates/balance.tmpl"
|
||||||
Symbol: strings.ToUpper(miner.Coin),
|
if t.templatesConfig.Balance != "" {
|
||||||
Precision: 6,
|
templateName = t.templatesConfig.Balance
|
||||||
Format: "%v %s",
|
|
||||||
}
|
}
|
||||||
convertedBalance, err := ConvertCurrency(miner.Coin, miner.Balance)
|
message, err := t.formatMessage(templateName, Attachment{Miner: miner})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
message := fmt.Sprintf("💰 *Balance* _%s_", ac.FormatMoney(convertedBalance))
|
|
||||||
return t.sendMessage(message)
|
return t.sendMessage(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyPayment to format and send a notification when a new payment has been detected
|
// NotifyPayment to format and send a notification when a new payment has been detected
|
||||||
// Implements the Notifier interface
|
// Implements the Notifier interface
|
||||||
func (t *TelegramNotifier) NotifyPayment(miner Miner, payment Payment) error {
|
func (t *TelegramNotifier) NotifyPayment(miner Miner, payment Payment) error {
|
||||||
ac := accounting.Accounting{
|
templateName := "templates/payment.tmpl"
|
||||||
Symbol: strings.ToUpper(miner.Coin),
|
if t.templatesConfig.Payment != "" {
|
||||||
Precision: 6,
|
templateName = t.templatesConfig.Payment
|
||||||
Format: "%v %s",
|
|
||||||
}
|
}
|
||||||
convertedValue, err := ConvertCurrency(miner.Coin, payment.Value)
|
message, err := t.formatMessage(templateName, Attachment{Miner: miner, Payment: payment})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
message := fmt.Sprintf("💵 *Payment* _%s_", ac.FormatMoney(convertedValue))
|
|
||||||
return t.sendMessage(message)
|
return t.sendMessage(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyBlock to format and send a notification when a new block has been detected
|
// NotifyBlock to format and send a notification when a new block has been detected
|
||||||
// Implements the Notifier interface
|
// Implements the Notifier interface
|
||||||
func (t *TelegramNotifier) NotifyBlock(pool Pool, block Block) error {
|
func (t *TelegramNotifier) NotifyBlock(pool Pool, block Block) error {
|
||||||
precision := 6
|
templateName := "templates/block.tmpl"
|
||||||
if pool.Coin == "xch" {
|
if t.templatesConfig.Block != "" {
|
||||||
precision = 2
|
templateName = t.templatesConfig.Block
|
||||||
}
|
}
|
||||||
ac := accounting.Accounting{
|
message, err := t.formatMessage(templateName, Attachment{Pool: pool, Block: block})
|
||||||
Symbol: strings.ToUpper(pool.Coin),
|
|
||||||
Precision: precision,
|
|
||||||
Format: "%v %s",
|
|
||||||
}
|
|
||||||
|
|
||||||
convertedValue, err := ConvertCurrency(pool.Coin, block.Reward)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
verb, err := ConvertAction(pool.Coin)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
url, err := FormatBlockURL(pool.Coin, block.Hash)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
message := fmt.Sprintf("🎉 *%s* [#%d](%s) _%s_", verb, block.Number, url, ac.FormatMoney(convertedValue))
|
|
||||||
return t.sendMessage(message)
|
return t.sendMessage(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyOfflineWorker sends a message when a worker is online or offline
|
// NotifyOfflineWorker sends a message when a worker is online or offline
|
||||||
func (t *TelegramNotifier) NotifyOfflineWorker(worker Worker) error {
|
func (t *TelegramNotifier) NotifyOfflineWorker(worker Worker) error {
|
||||||
stateIcon := "🟢"
|
templateName := "templates/offline-worker.tmpl"
|
||||||
stateMessage := "online"
|
if t.templatesConfig.OfflineWorker != "" {
|
||||||
if !worker.IsOnline {
|
templateName = t.templatesConfig.OfflineWorker
|
||||||
stateIcon = "🔴"
|
}
|
||||||
stateMessage = "offline"
|
message, err := t.formatMessage(templateName, Attachment{Worker: worker})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
message := fmt.Sprintf("%s *Worker* _%s_ is %s", stateIcon, worker.Name, stateMessage)
|
|
||||||
return t.sendMessage(message)
|
return t.sendMessage(message)
|
||||||
}
|
}
|
||||||
|
|
1
templates/balance.tmpl
Normal file
1
templates/balance.tmpl
Normal file
|
@ -0,0 +1 @@
|
||||||
|
💰 *Balance* _{{ printf "%.6f" (convertCurrency .Miner.Coin .Miner.Balance) }} {{ upper .Miner.Coin }}_
|
6
templates/block.tmpl
Normal file
6
templates/block.tmpl
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
🎉 *{{ convertAction .Pool.Coin }}* [#{{ .Block.Number }}]({{ formatBlockURL .Pool.Coin .Block.Hash }}) _
|
||||||
|
{{- if (eq .Pool.Coin "xch") -}}
|
||||||
|
{{ printf "%.2f" (convertCurrency .Pool.Coin .Block.Reward) }}
|
||||||
|
{{- else -}}
|
||||||
|
{{ printf "%.6f" (convertCurrency .Pool.Coin .Block.Reward) }}
|
||||||
|
{{- end }} {{ upper .Pool.Coin }}_
|
5
templates/offline-worker.tmpl
Normal file
5
templates/offline-worker.tmpl
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{{ if .Worker.IsOnline -}}
|
||||||
|
🟢 *Worker* _{{ .Worker.Name }}_ is online
|
||||||
|
{{- else -}}
|
||||||
|
🔴 *Worker* _{{ .Worker.Name }}_ is offline
|
||||||
|
{{- end -}}
|
1
templates/payment.tmpl
Normal file
1
templates/payment.tmpl
Normal file
|
@ -0,0 +1 @@
|
||||||
|
💵 *Payment* _{{ printf "%.6f" (convertCurrency .Miner.Coin .Payment.Value) }} {{ upper .Miner.Coin }}_
|
Reference in a new issue