|
@@ -0,0 +1,336 @@
|
|
|
+// Response creators
|
|
|
+package main
|
|
|
+
|
|
|
+import (
|
|
|
+ "fmt"
|
|
|
+ "strings"
|
|
|
+ "time"
|
|
|
+ "math"
|
|
|
+
|
|
|
+ tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api"
|
|
|
+)
|
|
|
+
|
|
|
+func (c *Connection) AddUser(reqChat *tgbotapi.Chat) (string, error) {
|
|
|
+ // Check if user already registered
|
|
|
+ var userCount int64
|
|
|
+ result := c.GormDb.Model(&User{}).
|
|
|
+ Where("chat_id = ?", reqChat.ID).
|
|
|
+ Count(&userCount)
|
|
|
+ if result.Error != nil {
|
|
|
+ return "", fmt.Errorf("failed creating user: %w", result.Error)
|
|
|
+ }
|
|
|
+ if userCount != 0 {
|
|
|
+ return "Already registered", nil
|
|
|
+ }
|
|
|
+
|
|
|
+ // Adding new user to database
|
|
|
+ newUser := User{ChatId: reqChat.ID}
|
|
|
+ result = c.GormDb.Create(newUser)
|
|
|
+ if result.Error != nil {
|
|
|
+ return "", fmt.Errorf("failed creating user: %w", result.Error)
|
|
|
+ }
|
|
|
+ LogInfo.Println("User was created:", newUser)
|
|
|
+ return "Added new user to database. Now you can connect your miner wallet using command /setwallet <address>", nil
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+func (c *Connection) SetWallet(reqMsg *tgbotapi.Message) (string, error) {
|
|
|
+ // Check if user already registered
|
|
|
+ var userCount int64
|
|
|
+ result := c.GormDb.Model(&User{}).
|
|
|
+ Where("chat_id = ?", reqMsg.Chat.ID).
|
|
|
+ Count(&userCount)
|
|
|
+ if result.Error != nil {
|
|
|
+ return "", fmt.Errorf("failed wallet set: %w", result.Error)
|
|
|
+ }
|
|
|
+ if userCount == 0 {
|
|
|
+ return "You are not registered! Type /start first!", nil
|
|
|
+ }
|
|
|
+
|
|
|
+ // *Strange* check for length of predifined eth wallet hash
|
|
|
+ if len(strings.Split(reqMsg.Text, " ")[1]) > 2 {
|
|
|
+ // Check if wallet hash typed with 0x
|
|
|
+ // TODO Should be: starts with '0x' or in format 0x....
|
|
|
+ if strings.Contains(strings.Split(reqMsg.Text, " ")[1], "0x") {
|
|
|
+ // TODO replace inefficient branching
|
|
|
+ result = c.GormDb.Model(&User{}).
|
|
|
+ Where("chat_id = ?", reqMsg.Chat.ID).
|
|
|
+ Update("wallet", strings.Split(reqMsg.Text, " ")[1])
|
|
|
+ if result.Error != nil {
|
|
|
+ return "", fmt.Errorf("failed querying user: %w", result.Error)
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ result = c.GormDb.Model(&User{}).
|
|
|
+ Where("chat_id = ?", reqMsg.Chat.ID).
|
|
|
+ Update("wallet", "0x"+strings.Split(reqMsg.Text, " ")[1])
|
|
|
+ if result.Error != nil {
|
|
|
+ return "", fmt.Errorf("failed querying user: %w", result.Error)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ LogInfo.Printf("Updated wallet of user %d to %s\n", reqMsg.Chat.ID, strings.Split(reqMsg.Text, " ")[1])
|
|
|
+ // TODO this is ▼▼ lame bro
|
|
|
+ return fmt.Sprintf("0x%s set!", strings.Split(reqMsg.Text, " ")[1]), nil
|
|
|
+ } else {
|
|
|
+ return "Too short!", nil
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func (c *Connection) DeleteUser(reqChat *tgbotapi.Chat) (string, error) {
|
|
|
+ // Check for user existance
|
|
|
+ var userCount int64
|
|
|
+ result := c.GormDb.Model(&User{}).
|
|
|
+ Where("chat_id = ?", reqChat.ID).
|
|
|
+ Count(&userCount)
|
|
|
+ if result.Error != nil {
|
|
|
+ return "", fmt.Errorf("failed creating user: %w", result.Error)
|
|
|
+ }
|
|
|
+ if userCount == 0 {
|
|
|
+ return "Already deleted", nil
|
|
|
+ }
|
|
|
+
|
|
|
+ // Taking target for deletion
|
|
|
+ var user User
|
|
|
+ result = c.GormDb.Take(&user, "chat_id = ?", reqChat.ID)
|
|
|
+ if result.Error != nil {
|
|
|
+ return "", fmt.Errorf("failed querying user: %w", result.Error)
|
|
|
+ }
|
|
|
+
|
|
|
+ var walletHoldersCount int64
|
|
|
+ result = c.GormDb.Model(&User{}).
|
|
|
+ Where("wallet = ?", user.Wallet).
|
|
|
+ Count(&walletHoldersCount)
|
|
|
+ if result.Error != nil {
|
|
|
+ return "", fmt.Errorf("failed querying user: %w", result.Error)
|
|
|
+ }
|
|
|
+
|
|
|
+ // TODO Remove code repition
|
|
|
+ if walletHoldersCount > 1 {
|
|
|
+ // Wallet in multiple chats
|
|
|
+ result = c.GormDb.Where("chat_id = ?", reqChat.ID).Delete(User{})
|
|
|
+ if result.Error != nil {
|
|
|
+ return "", fmt.Errorf("failed deleting user: %w", result.Error)
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // Wallet in single chat
|
|
|
+ result = c.GormDb.Where("chat_id = ?", reqChat.ID).Delete(User{})
|
|
|
+ if result.Error != nil {
|
|
|
+ return "", fmt.Errorf("failed deleting user: %w", result.Error)
|
|
|
+ }
|
|
|
+ // TODO Delete from workers, miners, payouts
|
|
|
+ }
|
|
|
+
|
|
|
+ LogInfo.Println("User was deleted:", user)
|
|
|
+ return "Done!", nil
|
|
|
+}
|
|
|
+
|
|
|
+func (c *Connection) GetActualDataFromDatabase(chatId int64) string {
|
|
|
+ errMsgToUser := "An exception occurred on sending messages while executing /actual command"
|
|
|
+ var wallet string
|
|
|
+ result := c.GormDb.Model(&User{}).
|
|
|
+ Where("chat_id = ?", chatId).
|
|
|
+ Select("wallet").
|
|
|
+ Scan(&wallet)
|
|
|
+ if result.Error != nil {
|
|
|
+ LogError.Println(result.Error)
|
|
|
+ return errMsgToUser
|
|
|
+ }
|
|
|
+ if wallet == "" {
|
|
|
+ return "Set wallet at first! Use /setwallet"
|
|
|
+ }
|
|
|
+
|
|
|
+ var lastMinerRecord Miner
|
|
|
+ result = c.GormDb.
|
|
|
+ Where(&Miner{Wallet: wallet}).
|
|
|
+ Order("time desc").
|
|
|
+ Limit(1).
|
|
|
+ Find(&lastMinerRecord)
|
|
|
+ if result.Error != nil {
|
|
|
+ LogError.Println(result.Error)
|
|
|
+ return "No miner data for now!"
|
|
|
+ }
|
|
|
+
|
|
|
+ var lastTime int64
|
|
|
+ result = c.GormDb.Model(&Worker{}).
|
|
|
+ Where("wallet = ?", wallet).
|
|
|
+ Select("MAX(time)").
|
|
|
+ Scan(&lastTime)
|
|
|
+ if result.Error != nil {
|
|
|
+ LogError.Println(result.Error)
|
|
|
+ return errMsgToUser
|
|
|
+ }
|
|
|
+
|
|
|
+ var lastWorkerRecord []Worker
|
|
|
+ result = c.GormDb.
|
|
|
+ Where(&Worker{Wallet: wallet, Time: lastTime}).
|
|
|
+ Find(&lastWorkerRecord)
|
|
|
+ if result.Error != nil {
|
|
|
+ LogError.Println(result.Error)
|
|
|
+ return errMsgToUser
|
|
|
+ }
|
|
|
+
|
|
|
+ if len(lastWorkerRecord) == 0 {
|
|
|
+ return "No workers data for now!"
|
|
|
+ }
|
|
|
+
|
|
|
+ msgText := fmt.Sprintf("Miner %s stats:\n", lastMinerRecord.Wallet)
|
|
|
+ msgText += fmt.Sprintf("Updated: %s\n", time.Unix(lastMinerRecord.Time, 0).Format("Monday, January 2, 2006 3:04 PM"))
|
|
|
+ msgText += fmt.Sprintf("Reported Hashrate: %.3f MH/s\n", math.Round(float64(lastMinerRecord.ReportedHashrate)/1000)/1000)
|
|
|
+ msgText += fmt.Sprintf("Current Hashrate: %.3f MH/s\n", math.Round(float64(lastMinerRecord.CurrentHashrate)/1000)/1000)
|
|
|
+ msgText += fmt.Sprintf("Valid Shares: %d\n", lastMinerRecord.ValidShares)
|
|
|
+ msgText += fmt.Sprintf("Stale Shares: %d\n", lastMinerRecord.StaleShares)
|
|
|
+ msgText += fmt.Sprintf("Workers: %d\n", lastMinerRecord.Workers)
|
|
|
+ msgText += fmt.Sprintf("Unpaid Balance: %.5f ETH\n", float64(lastMinerRecord.Unpaid)/math.Pow10(18)) //TODO ETH = AppSettings.currency
|
|
|
+
|
|
|
+ msg := tgbotapi.NewMessage(chatId, msgText)
|
|
|
+ myBotClient.Send(msg)
|
|
|
+ LogInfo.Printf("Replied with: %s", strings.ReplaceAll(msg.Text, "\n", "\\n"))
|
|
|
+
|
|
|
+ for i := range lastWorkerRecord {
|
|
|
+ // Per worker message
|
|
|
+ time.Sleep(1 * time.Second)
|
|
|
+
|
|
|
+ // Anti spam filter
|
|
|
+ if i != 0 && i%20 == 0 { //TODO SOMETIHNG BETTER THAN USUAL TIMER
|
|
|
+ time.Sleep(30 * time.Second)
|
|
|
+ }
|
|
|
+
|
|
|
+ msgText := fmt.Sprintf("Worker %s stats:\n", lastWorkerRecord[i].Worker)
|
|
|
+ msgText += fmt.Sprintf("Updated: %s\n", time.Unix(lastWorkerRecord[i].Time, 0).Format("Monday, January 2, 2006 3:04 PM"))
|
|
|
+ msgText += fmt.Sprintf("Reported Hashrate: %.3f MH/s\n", math.Round(float64(lastWorkerRecord[i].ReportedHashrate)/1000)/1000)
|
|
|
+ msgText += fmt.Sprintf("Current Hashrate: %.3f MH/s\n", math.Round(float64(lastWorkerRecord[i].CurrentHashrate)/1000)/1000)
|
|
|
+ msgText += fmt.Sprintf("Valid Shares: %d\n", lastWorkerRecord[i].ValidShares)
|
|
|
+ msgText += fmt.Sprintf("Stale Shares: %d\n", lastWorkerRecord[i].StaleShares)
|
|
|
+ msgText += fmt.Sprintf("Unpaid Balance: %.5f ETH\n", float64(lastWorkerRecord[i].WorkerUnpaid)/math.Pow10(18)) //TODO ETH = AppSettings.currency
|
|
|
+ msg := tgbotapi.NewMessage(chatId, msgText)
|
|
|
+ myBotClient.Send(msg)
|
|
|
+ LogInfo.Printf("Replied with: %s", strings.ReplaceAll(msg.Text, "\n", "\\n"))
|
|
|
+ }
|
|
|
+
|
|
|
+ return "nice"
|
|
|
+}
|
|
|
+
|
|
|
+func (c *Connection) GetLastPayout(chatId int64) string {
|
|
|
+ errMsgToUser := "An exception occurred on sending messages while executing /actual command"
|
|
|
+
|
|
|
+ var wallet string
|
|
|
+ result := c.GormDb.Model(&User{}).
|
|
|
+ Where(User{ChatId: chatId}).
|
|
|
+ Select("wallet").
|
|
|
+ Scan(&wallet)
|
|
|
+ if result.Error != nil {
|
|
|
+ LogError.Println(result.Error)
|
|
|
+ return errMsgToUser
|
|
|
+ }
|
|
|
+ if wallet == "" {
|
|
|
+ return "Set wallet at first! Use /setwallet"
|
|
|
+ }
|
|
|
+
|
|
|
+ var payoutTime int64
|
|
|
+ result = c.GormDb.Model(&Payout{}).
|
|
|
+ Where(&Payout{Wallet: wallet}).
|
|
|
+ Order("time desc").
|
|
|
+ Limit(1).
|
|
|
+ Select("time").
|
|
|
+ Scan(&payoutTime)
|
|
|
+ if result.Error != nil {
|
|
|
+ LogInfo.Printf("No payouts data for %s! Time is set to 0!", wallet)
|
|
|
+ LogError.Println(result.Error)
|
|
|
+ payoutTime = 0
|
|
|
+ }
|
|
|
+
|
|
|
+ // NOTE Pointless if previous 'if' statement occurs
|
|
|
+ // Must go from the start to line 235
|
|
|
+ var dbPayoutRecords []Payout
|
|
|
+ result = c.GormDb.
|
|
|
+ Where(&Payout{Wallet: wallet, Time: payoutTime}).
|
|
|
+ Find(&dbPayoutRecords)
|
|
|
+ //Line 560 of Program.cs
|
|
|
+ if len(dbPayoutRecords) == 0 {
|
|
|
+ url := fmt.Sprintf("%s/miner/%s/payouts", appSettings.ApiUrl, wallet)
|
|
|
+ var payouts JsonPayouts
|
|
|
+ err := UnmasrshalFromUrl(url, &payouts)
|
|
|
+ if err != nil {
|
|
|
+ LogError.Println(err)
|
|
|
+ return fmt.Sprintf("No payout data for %s", wallet)
|
|
|
+ }
|
|
|
+ lastPayout := payouts.Data[0]
|
|
|
+
|
|
|
+ message := fmt.Sprintf("Payout date: %s\n", time.Unix(lastPayout.PaidOn, 0).Format("Monday, January 2, 2006 3:04 PM"))
|
|
|
+ message += fmt.Sprintf("Amount: %.5f %s\n", float64(lastPayout.Amount)/math.Pow10(18), appSettings.Currency)
|
|
|
+ message += "Data source: Ethermine API \n"
|
|
|
+
|
|
|
+ return message
|
|
|
+ }
|
|
|
+ if result.Error != nil {
|
|
|
+ LogError.Println(result.Error)
|
|
|
+ return errMsgToUser
|
|
|
+ }
|
|
|
+
|
|
|
+ //Line 545 of Program.cs
|
|
|
+ message := fmt.Sprintf("Payout date: %s\n", time.Unix(dbPayoutRecords[0].Time, 0).Format("Monday, January 2, 2006 3:04 PM"))
|
|
|
+ message += fmt.Sprintf("Amount: %.5f ETH\n", float64(dbPayoutRecords[0].Amount)/math.Pow10(18))
|
|
|
+
|
|
|
+ for _, payoutRecord := range dbPayoutRecords {
|
|
|
+ message += fmt.Sprintf("Worker %s paid: %.5f %s\n", //TODO ETH = AppSettings.currency
|
|
|
+ payoutRecord.Worker,
|
|
|
+ float64(payoutRecord.Amount)/math.Pow10(18),
|
|
|
+ appSettings.Currency)
|
|
|
+ }
|
|
|
+
|
|
|
+ message += "Data source: Bot database \n"
|
|
|
+
|
|
|
+ return message
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+func GetActualRate() string {
|
|
|
+ url := fmt.Sprintf("%s/networkStats", appSettings.ApiUrl)
|
|
|
+ var networkStats JsonNetworkStats
|
|
|
+ err := UnmasrshalFromUrl(url, &networkStats)
|
|
|
+ if err != nil {
|
|
|
+ return fmt.Sprintf("Error with getting data from %s", appSettings.ApiUrl)
|
|
|
+ }
|
|
|
+ data := networkStats.Data
|
|
|
+ actualRate := fmt.Sprintf("ETH: %.2f\nBTC: %.2f", data.Usd, float64(data.Usd)/float64(data.Btc))
|
|
|
+ return actualRate
|
|
|
+}
|
|
|
+
|
|
|
+func GetActualData(miner string) string {
|
|
|
+ url := fmt.Sprintf("%s/miner/%s/currentStats", appSettings.ApiUrl, miner)
|
|
|
+ var currentStats JsonCurrentStats
|
|
|
+ err := UnmasrshalFromUrl(url, ¤tStats)
|
|
|
+ if err != nil {
|
|
|
+ // As in original...
|
|
|
+ return "An exception occurred while executing this command."
|
|
|
+ // return fmt.Sprintf("No data for specified wallet\n")
|
|
|
+ }
|
|
|
+
|
|
|
+ data := currentStats.Data
|
|
|
+
|
|
|
+ actualData := fmt.Sprintf("Stats of miner\n%s\n", miner)
|
|
|
+ actualData += fmt.Sprintf("Updated: %s\n", time.Unix(data.Time, 0).Format("Monday, January 2, 2006 3:04 PM"))
|
|
|
+ actualData += fmt.Sprintf("Reported Hashrate: %.3f MH/s\n", math.Round(float64(data.ReportedHashrate)/1000)/1000)
|
|
|
+ actualData += fmt.Sprintf("Current Hashrate: %.3f MH/s\n", math.Round(data.CurrentHashrate/1000)/1000)
|
|
|
+ actualData += fmt.Sprintf("Valid Shares: %d\n", data.ValidShares)
|
|
|
+ actualData += fmt.Sprintf("Stale Shares: %d\n", data.StaleShares)
|
|
|
+ actualData += fmt.Sprintf("Workers: %d\n", data.ActiveWorkers)
|
|
|
+ actualData += fmt.Sprintf("Unpaid Balance: %.5f ETH\n", float64(data.Unpaid)/math.Pow10(18))
|
|
|
+
|
|
|
+ return actualData
|
|
|
+}
|
|
|
+
|
|
|
+func GetHelp() (help string) {
|
|
|
+ // TODO separate help variable
|
|
|
+ help = "This is bot tracks your miner stats and calculates unpaid per worker.\n"
|
|
|
+ help += "How to start:\n"
|
|
|
+ help += "1) \"/start\" - it will add you to database\n"
|
|
|
+ help += "2) \"/setwallet <wallet>\" - it will set wallet for tracking, bot will start to add info about your miner and workers to database\n"
|
|
|
+ help += "3) \"/actual\" - it will send you up to date data about your worker\n"
|
|
|
+ help += "4) \"/lastpayout\" - it will send you last payout data with calculated worker unpaid for that period if avaliable\n"
|
|
|
+ help += "5) \"/stop\" - it will clear all data about you from database\n"
|
|
|
+ help += "Additional commands:\n"
|
|
|
+ help += "\"/rate\" - get actual ETH and BTC rate from ethermine\n"
|
|
|
+ help += "\"/actual <wallet>\" - get up to date data about any wallet without unpaid per worker\n"
|
|
|
+ return help
|
|
|
+}
|