package database import ( "fmt" "math" "strings" tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api" ethmineapi "gogs.veloe.link/toomanysugar/GoEthemineTelegramBot/api/ethermineapi" "gogs.veloe.link/toomanysugar/GoEthemineTelegramBot/cmd/settings" log "gogs.veloe.link/toomanysugar/GoEthemineTelegramBot/internal/logger" ) func (c Connection) UpdateData() { _ = tgbotapi.MessageConfig{} log.LogInfo.Println("Updating data!") walletList, err := c.UniqueWallets() if err != nil { log.LogError.Println(err); return } for _, wallet := range walletList { c.UpdateWallet(wallet) } } func (c Connection) UpdateWallet(wallet string) { log.LogInfo.Printf(">> Getting data for wallet %s\n", wallet) log.LogInfo.Printf("From: %s/miner/%s/currentStats\n", settings.ApiUrl(), wallet) // Get current stats for miner currentStats, err := ethmineapi.MinerStats(settings.ApiUrl(), wallet) if err != nil { if strings.Contains(err.Error(), "no data for miner") { log.LogWarn.Println(err) } else { log.LogError.Println(err) } return } if currentStats.Status != "OK" { log.LogError.Printf("Error getting response from pool for %s!\n", wallet); return } // Line 42 of UpdateData.cs // Search for the latest record for miner lastMinerRecord, err := c.LatestMinerRecord(wallet) if err != nil { log.LogError.Println(err) return } // Exist previous record with the same time if lastMinerRecord.Time == currentStats.Data.Time { log.LogInfo.Printf("Row with wallet: %s and time: %d already exists!", wallet, currentStats.Data.Time) return } log.LogInfo.Printf("Creating new record for miner %s, time %d\n", wallet, currentStats.Data.Time) // Line 28 of UpdateData.cs newMinerRecord := Miner { Wallet: wallet, Time: currentStats.Data.Time, ReportedHashrate: currentStats.Data.ReportedHashrate, CurrentHashrate: currentStats.Data.CurrentHashrate, ValidShares: currentStats.Data.ValidShares, StaleShares: currentStats.Data.StaleShares, InvalidShares: currentStats.Data.InvalidShares, Workers: currentStats.Data.ActiveWorkers, Unpaid: currentStats.Data.Unpaid, } result := c.GormDb.Create(&newMinerRecord) if result.Error != nil { log.LogError.Println(result.Error) return } log.LogInfo.Printf("Added new row for miner %s\n", newMinerRecord.Wallet) if (newMinerRecord.Unpaid < lastMinerRecord.Unpaid) { // TODO // err := ChatsToNotify(wallet) // if err != nil { // log.LogError.Println(err) // } } c.UpdateWorkers(newMinerRecord, lastMinerRecord) } // at main... or somewhere else func (c Connection) ChatsToNotify(wallet string) []int64 { walletChats, err := c.ChatsWithWallet(wallet) if err != nil { panic(err) } // for _, chat := range walletChats { // log.LogInfo.Println("Sended 'Payout detected!' message to chat ", chat) // go myBotClient.Send(tgbotapi.NewMessage(chat, "Payout detected!")) // } return walletChats } // UpdateWorkers updates data on workers of newMinerRecord func (c *Connection) UpdateWorkers(newMinerRecord Miner, lastMinerRecord Miner) { // Line 64 of UpdateData.cs log.LogInfo.Printf("Getting workers data for wallet %s\n", newMinerRecord.Wallet) log.LogInfo.Printf("From: %s/miner/%s", settings.ApiUrl(), newMinerRecord.Wallet) currentWorker, err := ethmineapi.Workers(settings.ApiUrl(), newMinerRecord.Wallet) if err != nil { log.LogWarn.Println(err); return } if currentWorker.Status != "OK" { return } // Unsure is it occurs if len(currentWorker.Data) == 0 { log.LogInfo.Printf("data in response from %s for workers of wallet %s not contains workers!\n", settings.ApiUrl(), newMinerRecord.Wallet) return } //Update for each individual worker for _, workerData := range currentWorker.Data { // In perfection: // worker, err := workerData.Update() // if err != nil {...} // if worker.Payout { // c.getPayout() // ... // } // // In reality c.updateWorker(workerData, newMinerRecord, lastMinerRecord) } } // updateWorker updates data on workerData func (c *Connection) updateWorker(workerData ethmineapi.WorkerData, newMinerRecord Miner, lastMinerRecord Miner) { log.LogInfo.Printf("Creating new worker record for %s, time %d\n", workerData.Worker, workerData.Time) newWorkerRecord := Worker{ Wallet: newMinerRecord.Wallet, Time: workerData.Time, Worker: workerData.Worker, ReportedHashrate: workerData.ReportedHashrate, CurrentHashrate: workerData.CurrentHashrate, ValidShares: workerData.ValidShares, StaleShares: workerData.StaleShares, InvalidShares: workerData.InvalidShares, } log.LogInfo.Printf("New worker record creating complete %s", newWorkerRecord.Worker) //Search for latest record for worker lastWorkerRecord, err := c.LatestWorkerRecord(workerData.Worker) if err != nil { log.LogError.Println(err); return } // Line 196 of UpdateData.cs if lastWorkerRecord == (Worker{}) { // TODO check default value of WorkerUnpaid log.LogDebug.Println("Setting WorkerUnpaid to 0") newWorkerRecord.WorkerUnpaid = 0 } // Line 85 of UpdateData.cs // check for payout // maybe newWorkerRecord.WorkerUnpaid, err := c.{}payout{}(newMinerRecord, lastMinerRecord) //Repeating of line 75 due to update of individual worker if lastWorkerRecord != (Worker{}) && newMinerRecord.Unpaid < lastMinerRecord.Unpaid { // Adding new payout field to db payouts, err := ethmineapi.Payouts(settings.ApiUrl(), newWorkerRecord.Wallet) if err != nil { log.LogError.Println(err); return } if (len(payouts.Data) == 0) { log.LogWarn.Println("No actual payouts for wallet", newWorkerRecord.Wallet) return } lastPayout := payouts.Data[0] log.LogInfo.Println("Last payout time =", lastPayout.PaidOn) newPayoutRecord := Payout{ Wallet: newWorkerRecord.Wallet, Time: lastPayout.PaidOn, Amount: lastPayout.Amount, Worker: workerData.Worker, } workerAmount := float64(lastWorkerRecord.WorkerUnpaid+ (float64(lastPayout.Amount-lastMinerRecord.Unpaid))) * (float64(workerData.ReportedHashrate) / float64(newMinerRecord.ReportedHashrate)) if math.IsNaN(workerAmount) || math.IsInf(workerAmount, 0) { workerAmount = lastWorkerRecord.WorkerUnpaid } newPayoutRecord.WorkerAmount = workerAmount workerUnpaid := float64(newMinerRecord.Unpaid) * (float64(workerData.ReportedHashrate) / float64(newMinerRecord.ReportedHashrate)) log.LogDebug.Println("newMinerRecord.Unpaid:", newMinerRecord.Unpaid) log.LogDebug.Println("lastMinerRecord.Unpaid:", lastMinerRecord.Unpaid) log.LogDebug.Println("workerData.ReportedHashrate:", workerData.ReportedHashrate) log.LogDebug.Println("newMinerRecord.ReportedHashrate:", newMinerRecord.ReportedHashrate) log.LogDebug.Println("workerUnpaid:", workerUnpaid) if math.IsNaN(workerUnpaid) || math.IsInf(workerUnpaid, 0) { log.LogDebug.Println("workerUnpaid is NaN or Inf") workerUnpaid = 0 } newWorkerRecord.WorkerUnpaid = workerUnpaid if result := c.GormDb.Create(&newPayoutRecord); result.Error != nil { log.LogError.Println(result.Error) return } log.LogInfo.Println("Added newPayoutRecord, time =", newPayoutRecord.Time) //removing old records result := c.GormDb. Where("wallet = ? AND time < ?", newPayoutRecord.Wallet, newMinerRecord.Time). Delete(Worker{}) if result.Error != nil { log.LogError.Println(result.Error) } result = c.GormDb. Where("wallet = ? AND time < ?", newPayoutRecord.Wallet, newMinerRecord.Time). Delete(Miner{}) if result.Error != nil { log.LogError.Println(result.Error) } result = c.GormDb. Where("wallet = ? AND time < ?", newPayoutRecord.Wallet, newMinerRecord.Time). Delete(Payout{}) if result.Error != nil { log.LogError.Println(result.Error) } //Line 135 of UpdateData.cs } else { //Payout not happened //no check that last balance and prev balance are the same //don't sure > or >= //TODO rewrite this var max int64 // max, err := c.LastPayoutTime(wallet) result := c.GormDb.Model(&Payout{}). Where("wallet = ?", lastWorkerRecord.Wallet). Order("time desc"). Limit(1). Select("time"). Scan(&max) if result.Error != nil { log.LogWarn.Printf("No payouts data for %s! Time is set to 0!\n", lastWorkerRecord.Wallet) log.LogError.Println(result.Error) max = 0 } if lastWorkerRecord.Time > max || lastWorkerRecord.WorkerUnpaid == 0 { workerUnpaid := float64(lastWorkerRecord.WorkerUnpaid+ float64(newMinerRecord.Unpaid-lastMinerRecord.Unpaid)) * (float64(workerData.ReportedHashrate) / float64(newMinerRecord.ReportedHashrate)) if math.IsNaN(workerUnpaid) || math.IsInf(workerUnpaid, 0) { workerUnpaid = lastWorkerRecord.WorkerUnpaid } newWorkerRecord.WorkerUnpaid = workerUnpaid // Line 169 of UpdateData.cs } else { workerUnpaid := float64((newMinerRecord.Unpaid - lastMinerRecord.Unpaid)) * (float64(workerData.ReportedHashrate) / float64(newMinerRecord.ReportedHashrate)) if math.IsNaN(workerUnpaid) || math.IsInf(workerUnpaid, 0) { workerUnpaid = lastWorkerRecord.WorkerUnpaid } newWorkerRecord.WorkerUnpaid = workerUnpaid targetedChats, err := c.ChatsWithWallet(newMinerRecord.Wallet) if err != nil { log.LogError.Println(err) } if err == nil { msg := fmt.Sprintf("Debug info: Your worker %s hasn't been zeroed on payout!", workerData.Worker) for _, chatId := range targetedChats { // TODO _ = chatId _ = msg //go myBotClient.Send(tgbotapi.NewMessage(int64(chatId), msg)) } log.LogDebug.Printf("Worker %s on address %s hasn't been zeroed on payout!\n", workerData.Worker, newMinerRecord.Wallet) } } } rowExists, err := c.IsWorkerRowExists(newWorkerRecord.Worker, newWorkerRecord.Time) if err != nil { log.LogError.Println(err); return } if rowExists { log.LogInfo.Printf("Error adding new row: row with worker: %s, time: %d already exists!\n", newWorkerRecord.Worker, newWorkerRecord.Time) return } if result := c.GormDb.Create(&newWorkerRecord); result.Error != nil { log.LogError.Println(result.Error) return } log.LogInfo.Printf("Added new row for worker %s\n", newWorkerRecord.Worker) }