update_data.go 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. package main
  2. import (
  3. "fmt"
  4. "math"
  5. "strings"
  6. tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api"
  7. ethmineapi "GoEthemineTelegramBot/ethermineapi"
  8. "GoEthemineTelegramBot/botsettings"
  9. )
  10. func UpdateData() {
  11. LogInfo.Println("Updating data!")
  12. walletList, err := dBConnector.UniqueWallets()
  13. if err != nil {
  14. LogError.Println(err); return
  15. }
  16. for _, wallet := range walletList {
  17. UpdateWallet(wallet)
  18. }
  19. }
  20. func UpdateWallet(wallet string) {
  21. LogInfo.Printf(">> Getting data for wallet %s\n", wallet)
  22. LogInfo.Printf("From: %s/miner/%s/currentStats\n", botsettings.ApiUrl(), wallet)
  23. // Get current stats for miner
  24. currentStats, err := ethmineapi.MinerStats(botsettings.ApiUrl(), wallet)
  25. if err != nil {
  26. if strings.Contains(err.Error(), "no data for miner") {
  27. LogWarn.Println(err)
  28. } else {
  29. LogError.Println(err)
  30. }
  31. return
  32. }
  33. if currentStats.Status != "OK" {
  34. LogError.Printf("Error getting response from pool for %s!\n", wallet);
  35. return
  36. }
  37. // Line 42 of UpdateData.cs
  38. // Search for the latest record for miner
  39. lastMinerRecord, err := dBConnector.LatestMinerRecord(wallet)
  40. if err != nil {
  41. LogError.Println(err)
  42. return
  43. }
  44. // Exist previous record with the same time
  45. if lastMinerRecord.Time == currentStats.Data.Time {
  46. LogInfo.Printf("Row with wallet: %s and time: %d already exists!", wallet, currentStats.Data.Time)
  47. return
  48. }
  49. LogInfo.Printf("Creating new record for miner %s, time %d\n", wallet, currentStats.Data.Time)
  50. // Line 28 of UpdateData.cs
  51. newMinerRecord := Miner {
  52. Wallet: wallet,
  53. Time: currentStats.Data.Time,
  54. ReportedHashrate: currentStats.Data.ReportedHashrate,
  55. CurrentHashrate: currentStats.Data.CurrentHashrate,
  56. ValidShares: currentStats.Data.ValidShares,
  57. StaleShares: currentStats.Data.StaleShares,
  58. InvalidShares: currentStats.Data.InvalidShares,
  59. Workers: currentStats.Data.ActiveWorkers,
  60. Unpaid: currentStats.Data.Unpaid,
  61. }
  62. result := dBConnector.GormDb.Create(&newMinerRecord)
  63. if result.Error != nil {
  64. LogError.Println(result.Error)
  65. return
  66. }
  67. LogInfo.Printf("Added new row for miner %s\n", newMinerRecord.Wallet)
  68. if (newMinerRecord.Unpaid < lastMinerRecord.Unpaid) {
  69. err = NotifyChats(wallet)
  70. if err != nil {
  71. LogError.Println(err)
  72. }
  73. }
  74. dBConnector.UpdateWorkers(newMinerRecord, lastMinerRecord)
  75. }
  76. // at main... or somewhere else
  77. func NotifyChats(wallet string) (err error) {
  78. walletChats, err := dBConnector.ChatsWithWallet(wallet)
  79. if err != nil {
  80. return err
  81. }
  82. for _, chat := range walletChats {
  83. LogInfo.Println("Sended 'Payout detected!' message to chat ", chat)
  84. go myBotClient.Send(tgbotapi.NewMessage(chat, "Payout detected!"))
  85. }
  86. return nil
  87. }
  88. // UpdateWorkers updates data on workers of newMinerRecord
  89. func (c *Connection) UpdateWorkers(newMinerRecord Miner, lastMinerRecord Miner) {
  90. // Line 64 of UpdateData.cs
  91. LogInfo.Printf("Getting workers data for wallet %s\n", newMinerRecord.Wallet)
  92. LogInfo.Printf("From: %s/miner/%s", botsettings.ApiUrl(), newMinerRecord.Wallet)
  93. currentWorker, err := ethmineapi.Workers(botsettings.ApiUrl(), newMinerRecord.Wallet)
  94. if err != nil {
  95. LogWarn.Println(err); return
  96. }
  97. if currentWorker.Status != "OK" {
  98. return
  99. }
  100. // Unsure is it occurs
  101. if len(currentWorker.Data) == 0 {
  102. LogInfo.Printf("data in response from %s for workers of wallet %s not contains workers!\n",
  103. botsettings.ApiUrl(), newMinerRecord.Wallet)
  104. return
  105. }
  106. //Update for each individual worker
  107. for _, workerData := range currentWorker.Data {
  108. // In perfection:
  109. // worker, err := workerData.Update()
  110. // if err != nil {...}
  111. // if worker.Payout {
  112. // c.getPayout()
  113. // ...
  114. // }
  115. //
  116. // In reality
  117. c.updateWorker(workerData, newMinerRecord, lastMinerRecord)
  118. }
  119. }
  120. // updateWorker updates data on workerData
  121. func (c *Connection) updateWorker(workerData ethmineapi.WorkerData,
  122. newMinerRecord Miner, lastMinerRecord Miner) {
  123. LogInfo.Printf("Creating new worker record for %s, time %d\n", workerData.Worker, workerData.Time)
  124. newWorkerRecord := Worker{
  125. Wallet: newMinerRecord.Wallet,
  126. Time: workerData.Time,
  127. Worker: workerData.Worker,
  128. ReportedHashrate: workerData.ReportedHashrate,
  129. CurrentHashrate: workerData.CurrentHashrate,
  130. ValidShares: workerData.ValidShares,
  131. StaleShares: workerData.StaleShares,
  132. InvalidShares: workerData.InvalidShares,
  133. }
  134. LogInfo.Printf("New worker record creating complete %s", newWorkerRecord.Worker)
  135. //Search for latest record for worker
  136. lastWorkerRecord, err := c.LatestWorkerRecord(workerData.Worker)
  137. if err != nil {
  138. LogError.Println(err);
  139. return
  140. }
  141. // Line 196 of UpdateData.cs
  142. if lastWorkerRecord == (Worker{}) {
  143. // TODO check default value of WorkerUnpaid
  144. LogDebug.Println("Setting WorkerUnpaid to 0")
  145. newWorkerRecord.WorkerUnpaid = 0
  146. }
  147. // Line 85 of UpdateData.cs
  148. // check for payout
  149. // maybe newWorkerRecord.WorkerUnpaid, err := c.{}payout{}(newMinerRecord, lastMinerRecord)
  150. //Repeating of line 75 due to update of individual worker
  151. if lastWorkerRecord != (Worker{}) && newMinerRecord.Unpaid < lastMinerRecord.Unpaid {
  152. // Adding new payout field to db
  153. payouts, err := ethmineapi.Payouts(botsettings.ApiUrl(), newWorkerRecord.Wallet)
  154. if err != nil {
  155. LogError.Println(err); return
  156. }
  157. if (len(payouts.Data) == 0) {
  158. LogWarn.Println("No actual payouts for wallet", newWorkerRecord.Wallet)
  159. return
  160. }
  161. lastPayout := payouts.Data[0]
  162. LogInfo.Println("Last payout time =", lastPayout.PaidOn)
  163. newPayoutRecord := Payout{
  164. Wallet: newWorkerRecord.Wallet,
  165. Time: lastPayout.PaidOn,
  166. Amount: lastPayout.Amount,
  167. Worker: workerData.Worker,
  168. }
  169. workerAmount := float64(lastWorkerRecord.WorkerUnpaid+
  170. (float64(lastPayout.Amount-lastMinerRecord.Unpaid))) *
  171. (float64(workerData.ReportedHashrate) / float64(newMinerRecord.ReportedHashrate))
  172. if math.IsNaN(workerAmount) || math.IsInf(workerAmount, 0) {
  173. workerAmount = lastWorkerRecord.WorkerUnpaid
  174. }
  175. newPayoutRecord.WorkerAmount = workerAmount
  176. workerUnpaid := float64(newMinerRecord.Unpaid) *
  177. (float64(workerData.ReportedHashrate) / float64(newMinerRecord.ReportedHashrate))
  178. LogDebug.Println("newMinerRecord.Unpaid:", newMinerRecord.Unpaid)
  179. LogDebug.Println("lastMinerRecord.Unpaid:", lastMinerRecord.Unpaid)
  180. LogDebug.Println("workerData.ReportedHashrate:", workerData.ReportedHashrate)
  181. LogDebug.Println("newMinerRecord.ReportedHashrate:", newMinerRecord.ReportedHashrate)
  182. LogDebug.Println("workerUnpaid:", workerUnpaid)
  183. if math.IsNaN(workerUnpaid) || math.IsInf(workerUnpaid, 0) {
  184. LogDebug.Println("workerUnpaid is NaN or Inf")
  185. workerUnpaid = 0
  186. }
  187. newWorkerRecord.WorkerUnpaid = workerUnpaid
  188. if result := c.GormDb.Create(&newPayoutRecord); result.Error != nil {
  189. LogError.Println(result.Error)
  190. return
  191. }
  192. LogInfo.Println("Added newPayoutRecord, time =", newPayoutRecord.Time)
  193. //removing old records
  194. result := c.GormDb.
  195. Where("wallet = ? AND time < ?", newPayoutRecord.Wallet, newMinerRecord.Time).
  196. Delete(Worker{})
  197. if result.Error != nil {
  198. LogError.Println(result.Error)
  199. }
  200. result = c.GormDb.
  201. Where("wallet = ? AND time < ?", newPayoutRecord.Wallet, newMinerRecord.Time).
  202. Delete(Miner{})
  203. if result.Error != nil {
  204. LogError.Println(result.Error)
  205. }
  206. result = c.GormDb.
  207. Where("wallet = ? AND time < ?", newPayoutRecord.Wallet, newMinerRecord.Time).
  208. Delete(Payout{})
  209. if result.Error != nil {
  210. LogError.Println(result.Error)
  211. }
  212. //Line 135 of UpdateData.cs
  213. } else {
  214. //Payout not happened
  215. //no check that last balance and prev balance are the same
  216. //don't sure > or >=
  217. //TODO rewrite this
  218. var max int64
  219. // max, err := c.LastPayoutTime(wallet)
  220. result := c.GormDb.Model(&Payout{}).
  221. Where("wallet = ?", lastWorkerRecord.Wallet).
  222. Order("time desc").
  223. Limit(1).
  224. Select("time").
  225. Scan(&max)
  226. if result.Error != nil {
  227. LogWarn.Printf("No payouts data for %s! Time is set to 0!\n", lastWorkerRecord.Wallet)
  228. LogError.Println(result.Error)
  229. max = 0
  230. }
  231. if lastWorkerRecord.Time > max || lastWorkerRecord.WorkerUnpaid == 0 {
  232. workerUnpaid := float64(lastWorkerRecord.WorkerUnpaid+
  233. float64(newMinerRecord.Unpaid-lastMinerRecord.Unpaid)) *
  234. (float64(workerData.ReportedHashrate) / float64(newMinerRecord.ReportedHashrate))
  235. if math.IsNaN(workerUnpaid) || math.IsInf(workerUnpaid, 0) {
  236. workerUnpaid = lastWorkerRecord.WorkerUnpaid
  237. }
  238. newWorkerRecord.WorkerUnpaid = workerUnpaid
  239. // Line 169 of UpdateData.cs
  240. } else {
  241. workerUnpaid := float64((newMinerRecord.Unpaid - lastMinerRecord.Unpaid)) *
  242. (float64(workerData.ReportedHashrate) / float64(newMinerRecord.ReportedHashrate))
  243. if math.IsNaN(workerUnpaid) || math.IsInf(workerUnpaid, 0) {
  244. workerUnpaid = lastWorkerRecord.WorkerUnpaid
  245. }
  246. newWorkerRecord.WorkerUnpaid = workerUnpaid
  247. targetedChats, err := c.ChatsWithWallet(newMinerRecord.Wallet)
  248. if err != nil {
  249. LogError.Println(err)
  250. }
  251. if err == nil {
  252. msg := fmt.Sprintf("Debug info: Your worker %s hasn't been zeroed on payout!",
  253. workerData.Worker)
  254. for _, chatId := range targetedChats {
  255. go myBotClient.Send(tgbotapi.NewMessage(int64(chatId), msg))
  256. }
  257. LogDebug.Printf("Worker %s on address %s hasn't been zeroed on payout!\n",
  258. workerData.Worker, newMinerRecord.Wallet)
  259. }
  260. }
  261. }
  262. rowExists, err := c.IsWorkerRowExists(newWorkerRecord.Worker, newWorkerRecord.Time)
  263. if err != nil {
  264. LogError.Println(err); return
  265. }
  266. if rowExists {
  267. LogInfo.Printf("Error adding new row: row with worker: %s, time: %d already exists!\n",
  268. newWorkerRecord.Worker, newWorkerRecord.Time)
  269. return
  270. }
  271. if result := c.GormDb.Create(&newWorkerRecord); result.Error != nil {
  272. LogError.Println(result.Error)
  273. return
  274. }
  275. LogInfo.Printf("Added new row for worker %s\n", newWorkerRecord.Worker)
  276. }