func (c *Controller) NewPhoto() (string, error) { c.r.ParseForm() userId := int64(utils.StrToFloat64(c.r.FormValue("user_id"))) data, err := c.OneRow("SELECT photo_block_id, photo_max_miner_id, miners_keepers FROM miners_data WHERE user_id = ?", userId).String() if err != nil { return "", utils.ErrInfo(err) } // получим ID майнеров, у которых лежат фото нужного нам юзера minersIds := utils.GetMinersKeepers(data["photo_block_id"], data["photo_max_miner_id"], data["miners_keepers"], true) // берем 1 случайный из 10-и ID майнеров k := utils.RandInt(0, len(minersIds)) minerId := minersIds[k] host, err := c.Single("SELECT http_host FROM miners_data WHERE miner_id = ?", minerId).String() if err != nil { return "", utils.ErrInfo(err) } result, err := json.Marshal(map[string]string{"face": host + "public/face_" + utils.Int64ToStr(userId) + ".jpg", "profile": host + "public/profile_" + utils.Int64ToStr(userId) + ".jpg"}) if err != nil { return "", utils.ErrInfo(err) } return string(result), nil }
func NodeVoting(chBreaker chan bool, chAnswer chan string) { defer func() { if r := recover(); r != nil { log.Error("daemon Recovered", r) panic(r) } }() const GoroutineName = "NodeVoting" d := new(daemon) d.DCDB = DbConnect(chBreaker, chAnswer, GoroutineName) if d.DCDB == nil { return } d.goRoutineName = GoroutineName d.chAnswer = chAnswer d.chBreaker = chBreaker if utils.Mobile() { d.sleepTime = 3600 } else { d.sleepTime = 60 } if !d.CheckInstall(chBreaker, chAnswer, GoroutineName) { return } d.DCDB = DbConnect(chBreaker, chAnswer, GoroutineName) if d.DCDB == nil { return } err = d.notMinerSetSleepTime(1800) if err != nil { log.Error("%v", err) return } BEGIN: for { log.Info(GoroutineName) MonitorDaemonCh <- []string{GoroutineName, utils.Int64ToStr(utils.Time())} // проверим, не нужно ли нам выйти из цикла if CheckDaemonsRestart(chBreaker, chAnswer, GoroutineName) { break BEGIN } err, restart := d.dbLock() if restart { break BEGIN } if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } // берем данные, которые находятся на голосовании нодов rows, err := d.Query(d.FormatQuery(` SELECT miners_data.user_id, http_host as host, face_hash, profile_hash, photo_block_id, photo_max_miner_id, miners_keepers, id as vote_id, miner_id FROM votes_miners LEFT JOIN miners_data ON votes_miners.user_id = miners_data.user_id WHERE cron_checked_time < ? AND votes_end = 0 AND type = 'node_voting' `), utils.Time()-consts.CRON_CHECKED_TIME_SEC) if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } if ok := rows.Next(); ok { var vote_id, miner_id int64 var user_id, host, row_face_hash, row_profile_hash, photo_block_id, photo_max_miner_id, miners_keepers string err = rows.Scan(&user_id, &host, &row_face_hash, &row_profile_hash, &photo_block_id, &photo_max_miner_id, &miners_keepers, &vote_id, &miner_id) if err != nil { rows.Close() if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } // проверим, не нужно нам выйти, т.к. обновилась версия софта if CheckDaemonsRestart(chBreaker, chAnswer, GoroutineName) { rows.Close() utils.Sleep(1) break } minersIds := utils.GetMinersKeepers(photo_block_id, photo_max_miner_id, miners_keepers, true) myUsersIds, err := d.GetMyUsersIds(true, true) myMinersIds, err := d.GetMyMinersIds(myUsersIds) // нет ли нас среди тех, кто должен скачать фото к себе и проголосовать var intersectMyMiners []int64 for _, id := range minersIds { if utils.InSliceInt64(int64(id), myMinersIds) { intersectMyMiners = append(intersectMyMiners, int64(id)) } } var vote int64 if len(intersectMyMiners) > 0 { var downloadError bool var faceHash, profileHash string var faceFile, profileFile []byte // копируем фото к себе profilePath := *utils.Dir + "/public/profile_" + user_id + ".jpg" _, err = utils.DownloadToFile(host+"/public/"+user_id+"_user_profile.jpg", profilePath, 60, chBreaker, chAnswer, GoroutineName) if err != nil { log.Error("%s", utils.ErrInfo(err)) downloadError = true } facePath := *utils.Dir + "/public/face_" + user_id + ".jpg" _, err = utils.DownloadToFile(host+"/public/"+user_id+"_user_face.jpg", facePath, 60, chBreaker, chAnswer, GoroutineName) if err != nil { log.Error("%s", utils.ErrInfo(err)) downloadError = true } if !downloadError { // хэши скопированных фото profileFile, err = ioutil.ReadFile(profilePath) if err != nil { rows.Close() if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } profileHash = string(utils.DSha256(profileFile)) log.Info("%v", "profileHash", profileHash) faceFile, err = ioutil.ReadFile(facePath) if err != nil { rows.Close() if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } faceHash = string(utils.DSha256(faceFile)) log.Info("%v", "faceHash", faceHash) } // проверяем хэш. Если сходится, то голосуем за, если нет - против и размер не должен быть более 200 Kb. if profileHash == row_profile_hash && faceHash == row_face_hash && len(profileFile) < 204800 && len(faceFile) < 204800 { vote = 1 } else { log.Error("%s %s %s %s %d %d", profileHash, row_face_hash, faceHash, row_profile_hash, len(profileFile), len(faceFile)) vote = 0 // если хэш не сходится, то удаляем только что скаченное фото os.Remove(profilePath) os.Remove(facePath) } // проходимся по всем нашим майнерам, если это пул и по одному, если это сингл-мод for _, myMinerId := range intersectMyMiners { myUserId, err := d.Single("SELECT user_id FROM miners_data WHERE miner_id = ?", myMinerId).Int64() if err != nil { rows.Close() if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } curTime := utils.Time() forSign := fmt.Sprintf("%v,%v,%v,%v,%v", utils.TypeInt("VotesNodeNewMiner"), curTime, myUserId, vote_id, vote) binSign, err := d.GetBinSign(forSign, myUserId) if err != nil { rows.Close() if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } data := utils.DecToBin(utils.TypeInt("VotesNodeNewMiner"), 1) data = append(data, utils.DecToBin(curTime, 4)...) data = append(data, utils.EncodeLengthPlusData(utils.Int64ToByte(myUserId))...) data = append(data, utils.EncodeLengthPlusData(utils.Int64ToByte(vote_id))...) data = append(data, utils.EncodeLengthPlusData(utils.Int64ToByte(vote))...) data = append(data, utils.EncodeLengthPlusData([]byte(binSign))...) err = d.InsertReplaceTxInQueue(data) if err != nil { rows.Close() if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } } } // отмечаем, чтобы больше не брать эту строку err = d.ExecSql("UPDATE votes_miners SET cron_checked_time = ? WHERE id = ?", utils.Time(), vote_id) if err != nil { rows.Close() if d.unlockPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } } rows.Close() d.dbUnlock() if d.dSleep(d.sleepTime) { break BEGIN } } log.Debug("break BEGIN %v", GoroutineName) }
func (c *Controller) NewUser() (string, error) { txType := "NewUser" txTypeId := utils.TypeInt(txType) timeNow := utils.Time() param := utils.ParamType{X: 176, Y: 100, Width: 100, Bg_path: "static/img/k_bg.png"} refPhotos := make(map[int64][]string) myRefsKeys := make(map[int64]map[string]string) if c.SessRestricted == 0 { join := c.MyPrefix + `my_new_users.user_id` if c.ConfigIni["db_type"] == "sqlite" || c.ConfigIni["db_type"] == "postgresql" { join = `"` + c.MyPrefix + `my_new_users".user_id` } rows, err := c.Query(c.FormatQuery(` SELECT users.user_id, private_key, log_id FROM ` + c.MyPrefix + `my_new_users LEFT JOIN users ON users.user_id = ` + join + ` WHERE status = 'approved' `)) if err != nil { return "", utils.ErrInfo(err) } defer rows.Close() for rows.Next() { var user_id, log_id int64 var private_key string err = rows.Scan(&user_id, &private_key, &log_id) if err != nil { return "", utils.ErrInfo(err) } // проверим, не сменил ли уже юзер свой ключ StrUserId := utils.Int64ToStr(user_id) if log_id != 0 { myRefsKeys[user_id] = map[string]string{"user_id": StrUserId} } else { myRefsKeys[user_id] = map[string]string{"user_id": StrUserId, "private_key": private_key} md5 := string(utils.Md5(private_key)) kPath := *utils.Dir + "/public/" + md5[0:16] kPathPng := kPath + ".png" kPathTxt := kPath + ".txt" if _, err := os.Stat(kPathPng); os.IsNotExist(err) { privKey := strings.Replace(private_key, "-----BEGIN RSA PRIVATE KEY-----", "", -1) privKey = strings.Replace(privKey, "-----END RSA PRIVATE KEY-----", "", -1) _, err = utils.KeyToImg(privKey, kPathPng, user_id, c.TimeFormat, param) if err != nil { return "", utils.ErrInfo(err) } err := ioutil.WriteFile(kPathTxt, []byte(privKey), 0644) if err != nil { return "", utils.ErrInfo(err) } /*$gd = key_to_img($private_key, $param, $row['user_id']); imagepng($gd, $k_path_png); file_put_contents($k_path_txt, trim($private_key));*/ } } } } refs := make(map[int64]map[int64]float64) // инфа по рефам юзера rows, err := c.Query(c.FormatQuery(` SELECT referral, sum(amount) as amount, currency_id FROM referral_stats WHERE user_id = ? GROUP BY currency_id, referral `), c.SessUserId) if err != nil { return "", utils.ErrInfo(err) } defer rows.Close() for rows.Next() { var referral, currency_id int64 var amount float64 err = rows.Scan(&referral, &amount, ¤cy_id) if err != nil { return "", utils.ErrInfo(err) } refs[referral] = map[int64]float64{currency_id: amount} } myRefsAmounts := make(map[int64]myRefsType) for refUserId, refData := range refs { data, err := c.OneRow("SELECT * FROM miners_data WHERE user_id = ?", refUserId).String() if err != nil { return "", utils.ErrInfo(err) } // получим ID майнеров, у которых лежат фото нужного нам юзера if len(data) == 0 { continue } minersIds := utils.GetMinersKeepers(data["photo_block_id"], data["photo_max_miner_id"], data["miners_keepers"], true) if len(minersIds) > 0 { hosts, err := c.GetList("SELECT http_host FROM miners_data WHERE miner_id IN (" + utils.JoinInts(minersIds, ",") + ")").String() if err != nil { return "", utils.ErrInfo(err) } myRefsAmounts[refUserId] = myRefsType{Amounts: refData, Hosts: hosts} refPhotos[refUserId] = hosts } } myRefs := make(map[int64]myRefsType) for refUserId, refData := range myRefsAmounts { myRefs[refUserId] = refData } for refUserId, refData := range myRefsKeys { md5 := string(utils.Md5(refData["private_key"])) myRefs[refUserId] = myRefsType{Key: refData["private_key"], KeyUrl: c.NodeConfig["pool_url"] + "public/" + md5[0:16]} } /* * Общая стата по рефам */ globalRefs := make(map[int64]globalRefsType) // берем лидеров по USD rows, err = c.Query(c.FormatQuery(` SELECT user_id, sum(amount) as amount FROM referral_stats WHERE currency_id = 72 GROUP BY user_id ORDER BY amount DESC `)) if err != nil { return "", utils.ErrInfo(err) } defer rows.Close() for rows.Next() { var user_id int64 var amount float64 err = rows.Scan(&user_id, &amount) if err != nil { return "", utils.ErrInfo(err) } // вся прибыль с рефов у данного юзера refAmounts, err := c.GetAll(` SELECT ROUND(sum(amount)) as amount, currency_id FROM referral_stats WHERE user_id = ? GROUP BY currency_id `, -1, user_id) if err != nil { return "", utils.ErrInfo(err) } data, err := c.OneRow("SELECT * FROM miners_data WHERE user_id = ?", user_id).String() if err != nil { return "", utils.ErrInfo(err) } // получим ID майнеров, у которых лежат фото нужного нам юзера minersIds := utils.GetMinersKeepers(data["photo_block_id"], data["photo_max_miner_id"], data["miners_keepers"], true) hosts, err := c.GetList("SELECT http_host FROM miners_data WHERE miner_id IN (" + utils.JoinInts(minersIds, ",") + ")").String() if err != nil { return "", utils.ErrInfo(err) } globalRefs[user_id] = globalRefsType{Amounts: refAmounts, Hosts: hosts} refPhotos[user_id] = hosts } lastTx, err := c.GetLastTx(c.SessUserId, utils.TypesToIds([]string{"NewUser"}), 1, c.TimeFormat) lastTxFormatted := "" if len(lastTx) > 0 { lastTxFormatted, _ = utils.MakeLastTx(lastTx, c.Lang) } TemplateStr, err := makeTemplate("new_user", "newUser", &newUserPage{ Alert: c.Alert, Lang: c.Lang, CountSignArr: c.CountSignArr, ShowSignData: c.ShowSignData, UserId: c.SessUserId, TimeNow: timeNow, TxType: txType, TxTypeId: txTypeId, SignData: "", LastTxFormatted: lastTxFormatted, MyRefs: myRefs, GlobalRefs: globalRefs, CurrencyList: c.CurrencyList, RefPhotos: refPhotos, PoolUrl: c.NodeConfig["pool_url"]}) if err != nil { return "", utils.ErrInfo(err) } return TemplateStr, nil }
func (p *Parser) VotesNodeNewMiner() error { var votes [2]int64 votesData, err := p.OneRow("SELECT user_id, votes_start_time, votes_0, votes_1 FROM votes_miners WHERE id = ?", p.TxMaps.Int64["vote_id"]).Int64() if err != nil { return p.ErrInfo(err) } log.Debug("votesData", votesData) log.Debug("votesData[user_id]", votesData["user_id"]) minersData, err := p.OneRow("SELECT photo_block_id, photo_max_miner_id, miners_keepers, log_id FROM miners_data WHERE user_id = ?", votesData["user_id"]).String() log.Debug("minersData", minersData) // $votes_data['user_id'] - это юзер, за которого голосуют if err != nil { return p.ErrInfo(err) } votes[0] = votesData["votes_0"] votes[1] = votesData["votes_1"] // прибавим голос votes[p.TxMaps.Int64["result"]]++ // обновляем голоса. При откате просто вычитаем err = p.ExecSql("UPDATE votes_miners SET votes_"+utils.Int64ToStr(p.TxMaps.Int64["result"])+" = ? WHERE id = ?", votes[p.TxMaps.Int64["result"]], p.TxMaps.Int64["vote_id"]) if err != nil { return p.ErrInfo(err) } // логируем, чтобы юзер {$this->tx_data['user_id']} не смог повторно проголосовать err = p.ExecSql("INSERT INTO log_votes (user_id, voting_id, type) VALUES (?, ?, 'votes_miners')", p.TxMaps.Int64["user_id"], p.TxMaps.Int64["vote_id"]) if err != nil { return p.ErrInfo(err) } // ID майнеров, у которых сохраняются фотки minersIds := utils.GetMinersKeepers(minersData["photo_block_id"], minersData["photo_max_miner_id"], minersData["miners_keepers"], true) log.Debug("minersIds", minersIds, len(minersIds)) // данные для проверки окончания голосования minerData := new(MinerData) minerData.myMinersIds, err = p.getMyMinersIds() if err != nil { return p.ErrInfo(err) } minerData.adminUiserId, err = p.GetAdminUserId() if err != nil { return p.ErrInfo(err) } minerData.minersIds = minersIds minerData.votes0 = votes[0] minerData.votes1 = votes[1] minerData.minMinersKeepers = p.Variables.Int64["min_miners_keepers"] log.Debug("minerData.adminUiserId %v", minerData.adminUiserId) log.Debug("minerData.myMinersIds %v", minerData.myMinersIds) log.Debug("minerData.minersIds %v", minerData.minersIds) log.Debug("minerData.votes0 %v", minerData.votes0) log.Debug("minerData.votes1 %v", minerData.votes1) log.Debug("minerData.minMinersKeepers %v", minerData.minMinersKeepers) if p.minersCheckVotes1(minerData) || (minerData.votes0 > minerData.minMinersKeepers || int(minerData.votes0) == len(minerData.minersIds)) { // отмечаем, что голосование нодов закончено err = p.ExecSql("UPDATE votes_miners SET votes_end = 1, end_block_id = ? WHERE id = ?", p.BlockData.BlockId, p.TxMaps.Int64["vote_id"]) if err != nil { return p.ErrInfo(err) } } if p.minersCheckVotes1(minerData) || p.minersCheckMyMinerIdAndVotes0(minerData) { // отметим del_block_id всем, кто голосовал за данного юзера, // чтобы через N блоков по крону удалить бесполезные записи err = p.ExecSql("UPDATE log_votes SET del_block_id = ? WHERE voting_id = ? AND type = 'votes_miners'", p.BlockData.BlockId, p.TxMaps.Int64["vote_id"]) if err != nil { return p.ErrInfo(err) } } // если набрано >=X голосов "за", то пишем в БД, что юзер готов к проверке людьми // либо если набранное кол-во голосов= кол-ву майнеров (актуально в самом начале запуска проекта) if p.minersCheckVotes1(minerData) { err = p.ExecSql("INSERT INTO votes_miners ( user_id, type, votes_start_time ) VALUES ( ?, 'user_voting', ? )", votesData["user_id"], p.BlockData.Time) if err != nil { return p.ErrInfo(err) } // и отмечаем лицо как готовое участвовать в поиске дублей err = p.ExecSql("UPDATE faces SET status = 'used' WHERE user_id = ?", votesData["user_id"]) if err != nil { return p.ErrInfo(err) } } else if p.minersCheckMyMinerIdAndVotes0(minerData) { // если набрано >5 голосов "против" и мы среди тех X майнеров, которые копировали фото к себе // либо если набранное кол-во голосов = кол-ву майнеров (актуально в самом начале запуска проекта) facePath := fmt.Sprintf(*utils.Dir+"/public/face_%v.jpg", votesData["user_id"]) profilePath := fmt.Sprintf(*utils.Dir+"/public/profile_%v.jpg", votesData["user_id"]) faceRandName := "" profileRandName := "" // возможно фото к нам не было скопировано, т.к. хост был недоступен. if _, err := os.Stat(profilePath); os.IsNotExist(err) { faceRandName = "" profileRandName = "" } else if _, err := os.Stat(facePath); os.IsNotExist(err) { faceRandName = "" profileRandName = "" } else { faceRandName = utils.RandSeq(30) profileRandName = utils.RandSeq(30) // перемещаем фото в корзину, откуда по крону будем удалять данные err = utils.CopyFileContents(facePath, faceRandName) if err != nil { return p.ErrInfo(err) } err = os.Remove(facePath) if err != nil { return p.ErrInfo(err) } err = utils.CopyFileContents(profilePath, profileRandName) if err != nil { return p.ErrInfo(err) } err = os.Remove(profilePath) if err != nil { return p.ErrInfo(err) } // если в корзине что-то есть, то логируем // отсутствие файлов также логируем, т.к. больше негде, а при откате эти данные очень важны. logData, err := p.OneRow("SELECT * FROM recycle_bin WHERE user_id = ?", votesData["user_id"]).String() if err != nil { return p.ErrInfo(err) } if len(logData) > 0 { logId, err := p.ExecSqlGetLastInsertId("INSERT INTO log_recycle_bin ( user_id, profile_file_name, face_file_name, block_id, prev_log_id ) VALUES ( ?, ?, ?, ?, ? )", "log_id", logData["user_id"], logData["profile_file_name"], logData["face_file_name"], p.BlockData.BlockId, logData["log_id"]) if err != nil { return p.ErrInfo(err) } err = p.ExecSql("UPDATE recycle_bin SET profile_file_name = ?, face_file_name = ?, log_id = ? WHERE user_id = ?", profileRandName, faceRandName, logId, logData["user_id"]) if err != nil { return p.ErrInfo(err) } } else { err = p.ExecSql("INSERT INTO recycle_bin ( user_id, profile_file_name, face_file_name ) VALUES ( ?, ?, ? )", votesData["user_id"], profileRandName, faceRandName) if err != nil { return p.ErrInfo(err) } } } } return nil }
func (p *Parser) VotesNodeNewMinerRollback() error { votesData, err := p.OneRow("SELECT user_id, votes_start_time, votes_0, votes_1 FROM votes_miners WHERE id = ?", p.TxMaps.Int64["vote_id"]).Int64() if err != nil { return p.ErrInfo(err) } minersData, err := p.OneRow("SELECT photo_block_id, photo_max_miner_id, miners_keepers, log_id FROM miners_data WHERE user_id = ?", votesData["user_id"]).String() if err != nil { return p.ErrInfo(err) } minerData := new(MinerData) // запомним голоса- пригодится чуть ниже в minersCheckVotes1 minerData.votes0 = votesData["votes_0"] minerData.votes1 = votesData["votes_1"] var votes [2]int64 votes[0] = votesData["votes_0"] votes[1] = votesData["votes_1"] // вычтем голос votes[p.TxMaps.Int64["result"]]-- // обновляем голоса err = p.ExecSql("UPDATE votes_miners SET votes_"+utils.Int64ToStr(p.TxMaps.Int64["result"])+" = ? WHERE id = ?", votes[p.TxMaps.Int64["result"]], p.TxMaps.Int64["vote_id"]) if err != nil { return p.ErrInfo(err) } // удаляем нашу запись из log_votes err = p.ExecSql("DELETE FROM log_votes WHERE user_id = ? AND voting_id = ? AND type = 'votes_miners'", p.TxMaps.Int64["user_id"], p.TxMaps.Int64["vote_id"]) if err != nil { return p.ErrInfo(err) } minersIds := utils.GetMinersKeepers(minersData["photo_block_id"], minersData["photo_max_miner_id"], minersData["miners_keepers"], true) minerData.myMinersIds, err = p.getMyMinersIds() if err != nil { return p.ErrInfo(err) } minerData.minersIds = minersIds minerData.minMinersKeepers = p.Variables.Int64["min_miners_keepers"] if p.minersCheckVotes1(minerData) || p.minersCheckMyMinerIdAndVotes0(minerData) { // отменяем отметку о том, что голосование нодов закончено err = p.ExecSql("UPDATE votes_miners SET votes_end = 0, end_block_id = 0 WHERE id = ?", p.TxMaps.Int64["vote_id"]) if err != nil { return p.ErrInfo(err) } // всем, кому ставили del_block_id, его убираем, т.е. отменяем будущее удаление по крону err = p.ExecSql("UPDATE log_votes SET del_block_id = 0 WHERE voting_id = ? AND type = 'votes_miners' AND del_block_id = ? ", p.TxMaps.Int64["vote_id"], p.BlockData.BlockId) if err != nil { return p.ErrInfo(err) } } // если набрано >=5 голосов, то отменяем в БД, что юзер готов к проверке людьми if p.minersCheckVotes1(minerData) { // отменяем созданное юзерское голосование err = p.ExecSql("DELETE FROM votes_miners WHERE user_id = ? AND votes_start_time = ? AND type = 'user_voting'", votesData["user_id"], p.BlockData.Time) if err != nil { return p.ErrInfo(err) } err = p.rollbackAI("votes_miners", 1) if err != nil { return p.ErrInfo(err) } // и отмечаем лицо как неучаствующее в поиске клонов err = p.ExecSql("UPDATE faces SET status = 'pending' WHERE user_id = ?", votesData["user_id"]) if err != nil { return p.ErrInfo(err) } } else if p.minersCheckMyMinerIdAndVotes0(minerData) { // если фото плохое и мы среди тех 10 майнеров, которые копировали (или нет) фото к себе, // а затем переместили фото в корзину // получаем rand_name из логов data, err := p.OneRow("SELECT profile_file_name, face_file_name FROM recycle_bin WHERE user_id = ?", votesData["user_id"]).String() if err != nil { return p.ErrInfo(err) } // перемещаем фото из корзины, если есть, что перемещать if len(data["profile_file_name"]) > 0 && len(data["face_file_name"]) > 0 { utils.CopyFileContents("recycle_bin/"+data["face_file_name"], *utils.Dir+"/public/face_"+utils.Int64ToStr(votesData["user_id"])+".jpg") utils.CopyFileContents("recycle_bin/"+data["profile_file_name"], *utils.Dir+"/public/profile_"+utils.Int64ToStr(votesData["user_id"])+".jpg") } p.generalRollback("recycle_bin", votesData["user_id"], "", false) } return nil }
func (c *Controller) Statistic() (string, error) { var err error sumWallets := make(map[int64]float64) // получаем кол-во DC на кошельках rows, err := c.Query(` SELECT currency_id, sum(amount) as sum_amount FROM wallets GROUP BY currency_id `) if err != nil { return "", utils.ErrInfo(err) } defer rows.Close() for rows.Next() { var currency_id int64 var sum_amount float64 err = rows.Scan(¤cy_id, &sum_amount) if err != nil { return "", utils.ErrInfo(err) } sumWallets[currency_id] = sum_amount } // получаем кол-во TDC на обещанных суммах rows, err = c.Query(` SELECT currency_id, sum(tdc_amount) as sum_amount FROM promised_amount GROUP BY currency_id `) if err != nil { return "", utils.ErrInfo(err) } defer rows.Close() for rows.Next() { var currency_id int64 var sum_amount float64 err = rows.Scan(¤cy_id, &sum_amount) if err != nil { return "", utils.ErrInfo(err) } if sumWallets[currency_id] > 0 { sumWallets[currency_id] += sum_amount } else { sumWallets[currency_id] = sum_amount } } // получаем суммы обещанных сумм sumPromisedAmount, err := c.GetMap(` SELECT currency_id, sum(amount) as sum_amount FROM promised_amount WHERE status = 'mining' AND del_block_id = 0 AND (cash_request_out_time = 0 OR cash_request_out_time > ?) GROUP BY currency_id`, "currency_id", "sum_amount", utils.Time()-c.Variables.Int64["cash_request_time"]) // получаем кол-во майнеров по валютам promisedAmountMiners, err := c.GetMap(` SELECT currency_id, count(user_id) as count FROM ( SELECT currency_id, user_id FROM promised_amount WHERE del_block_id = 0 AND del_mining_block_id = 0 AND status IN ('mining', 'repaid') GROUP BY user_id, currency_id ) as t1 GROUP BY currency_id`, "currency_id", "count") // получаем кол-во анонимных юзеров по валютам walletsUsers, err := c.GetMap(` SELECT currency_id, count(user_id) as count FROM wallets WHERE amount > 0 GROUP BY currency_id`, "currency_id", "count") refPhotos := make(map[int64][]string) // таблица обмена на наличные cashRequests, err := c.GetAll(` SELECT * FROM cash_requests ORDER BY id DESC LIMIT 5`, 5) for i := 0; i < len(cashRequests); i++ { if cashRequests[i]["del_block_id"] != "0" { cashRequests[i]["status"] = "reduction closed" } else if utils.Time()-utils.StrToInt64(cashRequests[i]["time"]) > c.Variables.Int64["cash_request_time"] && cashRequests[i]["status"] != "approved" { cashRequests[i]["status"] = "rejected" } t := time.Unix(utils.StrToInt64(cashRequests[i]["time"]), 0) cashRequests[i]["time"] = t.Format(c.TimeFormat) // ### from_user_id для фоток data, err := c.OneRow("SELECT * FROM miners_data WHERE user_id = ?", cashRequests[i]["from_user_id"]).String() if err != nil { return "", utils.ErrInfo(err) } // получим ID майнеров, у которых лежат фото нужного нам юзера minersIds := utils.GetMinersKeepers(data["photo_block_id"], data["photo_max_miner_id"], data["miners_keepers"], true) hosts, err := c.GetList("SELECT http_host FROM miners_data WHERE miner_id IN (" + utils.JoinInts(minersIds, ",") + ")").String() if err != nil { return "", utils.ErrInfo(err) } refPhotos[utils.StrToInt64(cashRequests[i]["from_user_id"])] = hosts // ### to_user_id для фоток data, err = c.OneRow("SELECT * FROM miners_data WHERE user_id = ?", cashRequests[i]["to_user_id"]).String() if err != nil { return "", utils.ErrInfo(err) } // получим ID майнеров, у которых лежат фото нужного нам юзера minersIds = utils.GetMinersKeepers(data["photo_block_id"], data["photo_max_miner_id"], data["miners_keepers"], true) hosts, err = c.GetList("SELECT http_host FROM miners_data WHERE miner_id IN (" + utils.JoinInts(minersIds, ",") + ")").String() if err != nil { return "", utils.ErrInfo(err) } refPhotos[utils.StrToInt64(cashRequests[i]["to_user_id"])] = hosts } var userInfoWallets []utils.DCAmounts var promisedAmountListAccepted []utils.PromisedAmounts var credits map[string]string // поиск инфы о юзере userInfoId := int64(utils.StrToFloat64(c.Parameters["user_info_id"])) if userInfoId > 0 { userInfoWallets, err = c.GetBalances(userInfoId) if err != nil { return "", utils.ErrInfo(err) } // обещанные суммы юзера _, promisedAmountListAccepted, _, err = c.GetPromisedAmounts(userInfoId, c.Variables.Int64["cash_request_time"]) // кредиты credits, err = c.GetMap(` SELECT sum(amount) as amount, currency_id FROM credits WHERE from_user_id = ? AND del_block_id = 0 GROUP BY currency_id`, "amount", "currency_id", userInfoId) } /* * Кол-во юзеров, сменивших ключ * */ countUsers, err := c.Single("SELECT count(user_id) FROM users WHERE log_id > 0").Int64() if err != nil { return "", utils.ErrInfo(err) } /* * %/год * */ currencyPct := make(map[int64]map[string]string) for currencyId, name := range c.CurrencyList { pct, err := c.OneRow("SELECT * FROM pct WHERE currency_id = ? ORDER BY block_id DESC", currencyId).Float64() if err != nil { return "", utils.ErrInfo(err) } currencyPct[currencyId] = make(map[string]string) currencyPct[currencyId]["name"] = name currencyPct[currencyId]["miner"] = utils.Float64ToStr(utils.Round((math.Pow(1+pct["miner"], 120)-1)*100, 6)) currencyPct[currencyId]["user"] = utils.Float64ToStr(utils.Round((math.Pow(1+pct["user"], 120)-1)*100, 6)) } /* * Произошедшие сокращения * */ reduction, err := c.GetAll(` SELECT * FROM reduction ORDER BY time DESC LIMIT 20`, 20) for i := 0; i < len(reduction); i++ { if reduction[i]["type"] != "auto" { reduction[i]["type"] = "voting" } t := time.Unix(utils.StrToInt64(reduction[i]["time"]), 0) reduction[i]["time"] = t.Format(c.TimeFormat) } TemplateStr, err := makeTemplate("statistic", "statistic", &StatisticPage{ Lang: c.Lang, CurrencyList: c.CurrencyListCf, UserInfoId: userInfoId, SumWallets: sumWallets, SumPromisedAmount: sumPromisedAmount, PromisedAmountMiners: promisedAmountMiners, WalletsUsers: walletsUsers, CashRequests: cashRequests, UserInfoWallets: userInfoWallets, Credits: credits, PromisedAmountListAccepted: promisedAmountListAccepted, CountUsers: countUsers, CurrencyPct: currencyPct, Reduction: reduction, RefPhotos: refPhotos, UserId: c.SessUserId}) if err != nil { return "", utils.ErrInfo(err) } return TemplateStr, nil }
func (c *Controller) Assignments() (string, error) { var randArr []int64 // Нельзя завершить голосование юзеров раньше чем через сутки, даже если набрано нужное кол-во голосов. // В голосовании нодов ждать сутки не требуется, т.к. там нельзя поставить поддельных нодов // Модерация новых майнеров // берем тех, кто прошел проверку нодов (type='node_voting') num, err := c.Single("SELECT count(id) FROM votes_miners WHERE votes_end = 0 AND type = 'user_voting'").Int64() if err != nil { return "", utils.ErrInfo(err) } if num > 0 { randArr = append(randArr, 1) } // Модерация promised_amount // вначале получим ID валют, которые мы можем проверять. currency, err := c.GetList("SELECT currency_id FROM promised_amount WHERE status IN ('mining', 'repaid') AND user_id = ?", c.SessUserId).String() if err != nil { return "", utils.ErrInfo(err) } addSql := "" currencyIds := strings.Join(currency, ",") if len(currencyIds) > 0 || c.SessUserId == 1 { if c.SessUserId != 1 { addSql = "AND currency_id IN (" + currencyIds + ")" } num, err := c.Single("SELECT count(id) FROM promised_amount WHERE status = 'pending' AND del_block_id = 0 " + addSql + "").Int64() if err != nil { return "", utils.ErrInfo(err) } if num > 0 { randArr = append(randArr, 2) } } log.Debug("randArr %v", randArr) var AssignType int64 if len(randArr) > 0 { AssignType = randArr[utils.RandInt(0, len(randArr))] } cloneHosts := make(map[int64][]string) var photoHosts []string examplePoints := make(map[string]string) tplName := "assignments" tplTitle := "assignments" var txType string var txTypeId int64 var timeNow int64 var myRace, myCountry, mainQuestion, newPromiseAmount, videoHost string var promisedAmountData, userInfo map[string]string switch AssignType { case 1: // *********************************** // задания по модерации новых майнеров // *********************************** txType = "VotesMiner" txTypeId = utils.TypeInt(txType) timeNow = utils.Time() userInfo, err = c.OneRow(` SELECT miners_data.user_id, votes_miners.id as vote_id, face_coords, profile_coords, video_type, video_url_id, photo_block_id, photo_max_miner_id, miners_keepers, http_host FROM votes_miners LEFT JOIN miners_data ON miners_data.user_id = votes_miners.user_id LEFT JOIN `+c.MyPrefix+`my_tasks ON `+c.MyPrefix+`my_tasks.id = votes_miners.id WHERE votes_end = 0 AND votes_miners.type = 'user_voting' AND (`+c.MyPrefix+`my_tasks.time IS NULL OR (`+c.MyPrefix+`my_tasks.time < ? AND `+c.MyPrefix+`my_tasks.type = 'miner')) `, utils.Time()-consts.ASSIGN_TIME).String() if err != nil { return "", utils.ErrInfo(err) } if len(userInfo) == 0 { tplName = "assignments" break } examplePoints, err = c.GetPoints(c.Lang) if err != nil { return "", utils.ErrInfo(err) } // получим ID майнеров, у которых лежат фото нужного нам юзера minersIds := utils.GetMinersKeepers(userInfo["photo_block_id"], userInfo["photo_max_miner_id"], userInfo["miners_keepers"], true) if len(minersIds) > 0 { photoHosts, err = c.GetList("SELECT http_host FROM miners_data WHERE miner_id IN (" + utils.JoinInts(minersIds, ",") + ")").String() if err != nil { return "", utils.ErrInfo(err) } } // отрезки майнера, которого проверяем relations, err := c.OneRow("SELECT * FROM faces WHERE user_id = ?", userInfo["user_id"]).String() if err != nil { return "", utils.ErrInfo(err) } // получим допустимые расхождения между точками и совместимость версий data_, err := c.OneRow("SELECT tolerances, compatibility FROM spots_compatibility").String() if err != nil { return "", utils.ErrInfo(err) } tolerances := make(map[string]map[string]string) if err := json.Unmarshal([]byte(data_["tolerances"]), &tolerances); err != nil { return "", utils.ErrInfo(err) } var compatibility []int if err := json.Unmarshal([]byte(data_["compatibility"]), &compatibility); err != nil { return "", utils.ErrInfo(err) } // формируем кусок SQL-запроса для соотношений отрезков addSqlTolerances := "" typesArr := []string{"face", "profile"} for i := 0; i < len(typesArr); i++ { for j := 1; j <= len(tolerances[typesArr[i]]); j++ { currentRelations := utils.StrToFloat64(relations[typesArr[i][:1]+utils.IntToStr(j)]) diff := utils.StrToFloat64(tolerances[typesArr[i]][utils.IntToStr(j)]) * currentRelations if diff == 0 { continue } min := currentRelations - diff max := currentRelations + diff addSqlTolerances += typesArr[i][:1] + utils.IntToStr(j) + ">" + utils.Float64ToStr(min) + " AND " + typesArr[i][:1] + utils.IntToStr(j) + " < " + utils.Float64ToStr(max) + " AND " } } addSqlTolerances = addSqlTolerances[:len(addSqlTolerances)-4] // формируем кусок SQL-запроса для совместимости версий addSqlCompatibility := "" for i := 0; i < len(compatibility); i++ { addSqlCompatibility += fmt.Sprintf(`%d,`, compatibility[i]) } addSqlCompatibility = addSqlCompatibility[:len(addSqlCompatibility)-1] // получаем из БД похожие фото rows, err := c.Query(c.FormatQuery(` SELECT miners_data.user_id, photo_block_id, photo_max_miner_id, miners_keepers FROM faces LEFT JOIN miners_data ON miners_data.user_id = faces.user_id WHERE `+addSqlTolerances+` AND version IN (`+addSqlCompatibility+`) AND faces.status = 'used' AND miners_data.user_id != ? LIMIT 100 `), userInfo["user_id"]) if err != nil { return "", utils.ErrInfo(err) } defer rows.Close() for rows.Next() { var photo_block_id, photo_max_miner_id, miners_keepers string var user_id int64 err = rows.Scan(&user_id, &photo_block_id, &photo_max_miner_id, &miners_keepers) if err != nil { return "", utils.ErrInfo(err) } // майнеры, у которых можно получить фото нужного нам юзера minersIds := utils.GetMinersKeepers(photo_block_id, photo_max_miner_id, miners_keepers, true) if len(minersIds) > 0 { photoHosts, err = c.GetList("SELECT http_host FROM miners_data WHERE miner_id IN (" + utils.JoinInts(minersIds, ",") + ")").String() if err != nil { return "", utils.ErrInfo(err) } } cloneHosts[user_id] = photoHosts } data, err := c.OneRow("SELECT race, country FROM " + c.MyPrefix + "my_table").Int64() myRace = c.Races[data["race"]] myCountry = consts.Countries[int(data["country"])] tplName = "assignments_new_miner" tplTitle = "assignmentsNewMiner" case 2: promisedAmountData, err = c.OneRow(` SELECT id, currency_id, amount, user_id, video_type, video_url_id FROM promised_amount WHERE status = 'pending' AND del_block_id = 0 ` + addSql + ` `).String() if err != nil { return "", utils.ErrInfo(err) } promisedAmountData["currency_name"] = c.CurrencyList[utils.StrToInt64(promisedAmountData["currency_id"])] // проверим, не голосовали ли мы за это в последние 30 минут repeated, err := c.Single("SELECT id FROM "+c.MyPrefix+"my_tasks WHERE type = 'promised_amount' AND id = ? AND time > ?", promisedAmountData["id"], utils.Time()-consts.ASSIGN_TIME).Int64() if err != nil { return "", utils.ErrInfo(err) } if repeated > 0 { tplName = "assignments" tplTitle = "assignments" break } // если нету видео на ютубе, то получаем host юзера, где брать видео if promisedAmountData["video_url_id"] == "null" { videoHost, err = c.Single("SELECT http_host FROM miners_data WHERE user_id = ?", promisedAmountData["user_id"]).String() if err != nil { return "", utils.ErrInfo(err) } } // каждый раз обязательно проверяем, где находится юзер userInfo, err = c.OneRow(` SELECT latitude, user_id, longitude, photo_block_id, photo_max_miner_id, miners_keepers, http_host FROM miners_data WHERE user_id = ? `, promisedAmountData["user_id"]).String() if err != nil { return "", utils.ErrInfo(err) } // получим ID майнеров, у которых лежат фото нужного нам юзера minersIds := utils.GetMinersKeepers(userInfo["photo_block_id"], userInfo["photo_max_miner_id"], userInfo["miners_keepers"], true) if len(minersIds) > 0 { photoHosts, err = c.GetList("SELECT http_host FROM miners_data WHERE miner_id IN (" + utils.JoinInts(minersIds, ",") + ")").String() if err != nil { return "", utils.ErrInfo(err) } } txType = "VotesPromisedAmount" txTypeId = utils.TypeInt(txType) timeNow = utils.Time() newPromiseAmount = strings.Replace(c.Lang["new_promise_amount"], "[amount]", promisedAmountData["amount"], -1) newPromiseAmount = strings.Replace(newPromiseAmount, "[currency]", promisedAmountData["currency_name"], -1) mainQuestion = strings.Replace(c.Lang["main_question"], "[amount]", promisedAmountData["amount"], -1) mainQuestion = strings.Replace(mainQuestion, "[currency]", promisedAmountData["currency_name"], -1) tplName = "assignments_promised_amount" tplTitle = "assignmentsPromisedAmount" default: tplName = "assignments" tplTitle = "assignments" } TemplateStr, err := makeTemplate(tplName, tplTitle, &AssignmentsPage{ Alert: c.Alert, Lang: c.Lang, CountSignArr: c.CountSignArr, ShowSignData: c.ShowSignData, UserId: c.SessUserId, TimeNow: timeNow, TxType: txType, TxTypeId: txTypeId, SignData: "", CurrencyList: c.CurrencyList, MainQuestion: mainQuestion, NewPromiseAmount: newPromiseAmount, MyRace: myRace, MyCountry: myCountry, ExamplePoints: examplePoints, VideoHost: videoHost, PhotoHosts: photoHosts, PromisedAmountData: promisedAmountData, UserInfo: userInfo, CloneHosts: cloneHosts}) if err != nil { return "", utils.ErrInfo(err) } return TemplateStr, nil }
func (c *Controller) GetMinerData() (string, error) { c.r.ParseForm() secs := float64(3600 * 24 * 365) userId := utils.StrToInt64(c.r.FormValue("userId")) if !utils.CheckInputData(userId, "int") { return `{"result":"incorrect userId"}`, nil } minersData, err := c.OneRow("SELECT * FROM miners_data WHERE user_id = ?", userId).String() if err != nil { return "", err } // получим ID майнеров, у которых лежат фото нужного нам юзера minersIds := utils.GetMinersKeepers(minersData["photo_block_id"], minersData["photo_max_miner_id"], minersData["miners_keepers"], false) hosts, err := c.GetList("SELECT http_host as host FROM miners_data WHERE miner_id IN (" + utils.JoinIntsK(minersIds, ",") + ")").String() if err != nil { return "", err } currencyList, err := c.GetCurrencyList(false) if err != nil { return "", err } _, _, promisedAmountListGen, err := c.GetPromisedAmounts(userId, c.Variables.Int64["cash_request_time"]) log.Debug("promisedAmountListGen: %v", promisedAmountListGen) var data utils.DCAmounts if promisedAmountListGen[72].Amount > 0 { data = promisedAmountListGen[72] } else if promisedAmountListGen[23].Amount > 0 { data = promisedAmountListGen[23] } else { data = utils.DCAmounts{} } log.Debug("data: %v", data) promisedAmounts := "" prognosis := make(map[int64]float64) if data.Amount > 1 { promisedAmounts += RoundStr(utils.Float64ToStr(utils.Round(data.Amount, 0)), 0) + " " + currencyList[(data.CurrencyId)] + "<br>" prognosis[int64(data.CurrencyId)] += (math.Pow(1+data.PctSec, secs) - 1) * data.Amount } if len(promisedAmounts) > 0 { promisedAmounts = "<strong>" + promisedAmounts[:len(promisedAmounts)-4] + "</strong><br>" + c.Lang["promised"] + "<hr>" } /* * На кошельках * */ balances, err := c.GetBalances(userId) if err != nil { return "", err } walletsByCurrency := make(map[int]utils.DCAmounts) for _, data := range balances { walletsByCurrency[int(data.CurrencyId)] = data } log.Debug("walletsByCurrency[72].Amount: %v", walletsByCurrency[72].Amount) if walletsByCurrency[72].Amount > 0 { data = walletsByCurrency[72] } else if walletsByCurrency[23].Amount > 0 { data = walletsByCurrency[23] } else { data = utils.DCAmounts{} } log.Debug("data: %v", data) wallets := "" var countersIds []string var pctSec float64 if data.Amount > 0 { counterId := "map-" + utils.Int64ToStr(userId) + "-" + utils.Int64ToStr(data.CurrencyId) countersIds = append(countersIds, counterId) wallets = "<span class='dc_amount' id='" + counterId + "'>" + RoundStr(utils.Float64ToStr(data.Amount), 8) + "</span> d" + currencyList[(data.CurrencyId)] + "<br>" // прогноз prognosis[int64(data.CurrencyId)] += (math.Pow(1+data.PctSec, secs) - 1) * data.Amount pctSec = data.PctSec } if len(wallets) > 0 { wallets = wallets[:len(wallets)-4] + "<br>" + c.Lang["on_the_account"] + "<hr>" } /* * Годовой прогноз * */ prognosisHtml := "" for currencyId, amount := range prognosis { if amount < 0.01 { continue } else if amount < 1 { amount = utils.Round(amount, 2) } else { amount = amount } prognosisHtml += "<span class='amount_1year'>" + RoundStr(utils.Float64ToStr(amount), 2) + " d" + currencyList[(currencyId)] + "</span><br>" } if len(prognosisHtml) > 0 { prognosisHtml = prognosisHtml[:len(prognosisHtml)-4] + "<br> " + c.Lang["profit_forecast"] + " " + c.Lang["after_1_year"] } prognosisHtml = "" result_ := minersDataType{Hosts: hosts, Lnglat: map[string]string{"lng": minersData["longitude"], "lat": minersData["latitude"]}, Html: promisedAmounts + wallets + "<div style=\"clear:both\"></div>" + prognosisHtml + "</p>", Counters: countersIds, PctSec: pctSec} log.Debug("result_", result_) result, err := json.Marshal(result_) if err != nil { return "", err } log.Debug(string(result)) return string(result), nil }