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 Connector(chBreaker chan bool, chAnswer chan string) { defer func() { if r := recover(); r != nil { log.Error("daemon Recovered", r) panic(r) } }() if _, err := os.Stat(*utils.Dir + "/nodes.inc"); os.IsNotExist(err) { data, err := static.Asset("static/nodes.inc") if err != nil { log.Error("%v", err) } err = ioutil.WriteFile(*utils.Dir+"/nodes.inc", []byte(data), 0644) if err != nil { log.Error("%v", err) } } GoroutineName := "Connector" 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 = 600 } else { d.sleepTime = 30 } if !d.CheckInstall(chBreaker, chAnswer, GoroutineName) { return } d.DCDB = DbConnect(chBreaker, chAnswer, GoroutineName) if d.DCDB == nil { return } // соединения для чата иногда отваливаются, поэтому в цикле мониторим состояние go func() { for { if myUserIdForChat == 0 { utils.Sleep(1) continue } if len(utils.ChatOutConnections) < 5 || len(utils.ChatInConnections) < 5 { go d.chatConnector() } utils.Sleep(30) } }() BEGIN: for { log.Info(GoroutineName) MonitorDaemonCh <- []string{GoroutineName, utils.Int64ToStr(utils.Time())} // проверим, не нужно ли нам выйти из цикла if CheckDaemonsRestart(chBreaker, chAnswer, GoroutineName) { break BEGIN } nodeConfig, err := d.GetNodeConfig() if len(nodeConfig["local_gate_ip"]) > 0 { utils.Sleep(2) continue } var delMiners []string var hosts []map[string]string var nodeCount int64 idArray := make(map[int]int64) nodesInc := make(map[string]string) // ровно стольким нодам мы будем слать хэши блоков и тр-ий var maxHosts = consts.OUT_CONNECTIONS if utils.StrToInt64(nodeConfig["out_connections"]) > 0 { maxHosts = utils.StrToInt(nodeConfig["out_connections"]) } log.Info("%v", maxHosts) collective, err := d.GetCommunityUsers() if err != nil { log.Error("%v", err) return } if len(collective) == 0 { myUserId, err := d.GetMyUserId("") if err != nil { log.Error("%v", err) return } collective = append(collective, myUserId) myUserIdForChat = myUserId } else { myUserIdForChat, err = d.Single(`SELECT pool_admin_user_id FROM config`).Int64() if err != nil { log.Error("%v", err) return } } // в сингл-моде будет только $my_miners_ids[0] myMinersIds, err := d.GetMyMinersIds(collective) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue } log.Info("%v", myMinersIds) nodesBan, err := d.GetMap(` SELECT tcp_host, ban_start FROM nodes_ban LEFT JOIN miners_data ON miners_data.user_id = nodes_ban.user_id `, "tcp_host", "ban_start") log.Info("%v", nodesBan) nodesConnections, err := d.GetAll(` SELECT nodes_connection.host, nodes_connection.user_id, ban_start, miner_id FROM nodes_connection LEFT JOIN nodes_ban ON nodes_ban.user_id = nodes_connection.user_id LEFT JOIN miners_data ON miners_data.user_id = nodes_connection.user_id `, -1) //fmt.Println("nodesConnections", nodesConnections) log.Debug("nodesConnections: %v", nodesConnections) for _, data := range nodesConnections { // проверим, не нужно нам выйти, т.к. обновилась версия софта if CheckDaemonsRestart(chBreaker, chAnswer, GoroutineName) { break BEGIN } /*// проверим соотвествие хоста и user_id ok, err := d.Single("SELECT user_id FROM miners_data WHERE user_id = ? AND tcp_host = ?", data["user_id"], data["host"]).Int64() if err != nil { utils.Sleep(1) continue BEGIN } if ok == 0 { err = d.ExecSql("DELETE FROM nodes_connection WHERE host = ? OR user_id = ?", data["host"], data["user_id"]) if err != nil { utils.Sleep(1) continue BEGIN } }*/ // если нода забанена недавно if utils.StrToInt64(data["ban_start"]) > utils.Time()-consts.NODE_BAN_TIME { delMiners = append(delMiners, data["miner_id"]) err = d.ExecSql("DELETE FROM nodes_connection WHERE host = ? OR user_id = ?", data["host"], data["user_id"]) if err != nil { if d.dPrintSleep(utils.ErrInfo(err), d.sleepTime) { break BEGIN } continue BEGIN } continue } hosts = append(hosts, map[string]string{"host": data["host"], "user_id": data["user_id"]}) nodesInc[data["host"]] = data["user_id"] nodeCount++ } log.Debug("hosts: %v", hosts) /* ch := make(chan *answerType) for _, host := range hosts { userId := utils.StrToInt64(host["user_id"]) go func(userId int64, host string) { ch_ := make(chan *answerType, 1) go func() { log.Debug("host: %v / userId: %v", host, userId) ch_ <- check(host, userId) }() select { case reachable := <-ch_: ch <- reachable case <-time.After(consts.WAIT_CONFIRMED_NODES * time.Second): ch <- &answerType{userId: userId, answer: 0} } }(userId, host["host"]) } log.Debug("%v", "hosts", hosts) var newHosts []map[string]string var countOk int // если нода не отвечает, то удалем её из таблы nodes_connection for i := 0; i < len(hosts); i++ { result := <-ch if result.answer == 0 { log.Info("delete %v", result.userId) err = d.ExecSql("DELETE FROM nodes_connection WHERE user_id = ?", result.userId) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } } for _, data := range hosts { if utils.StrToInt64(data["user_id"]) != result.userId { newHosts = append(newHosts, data) } } } else { countOk++ } log.Info("answer: %v", result) } */ var countOk int hosts = checkHosts(hosts, &countOk) log.Debug("countOk: %d / hosts: %v", countOk, hosts) // проверим, не нужно нам выйти, т.к. обновилась версия софта if CheckDaemonsRestart(chBreaker, chAnswer, GoroutineName) { break BEGIN } // добьем недостающие хосты до $max_hosts var newHostsForCheck []map[string]string if len(hosts) < maxHosts { need := maxHosts - len(hosts) max, err := d.Single("SELECT max(miner_id) FROM miners").Int() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } i0 := 0 for { rand := 1 if max > 1 { rand = utils.RandInt(1, max+1) } idArray[rand] = 1 i0++ if i0 > 30 || len(idArray) >= need || len(idArray) >= max { break } } log.Info("%v", "idArray", idArray) // удалим себя for _, id := range myMinersIds { delete(idArray, int(id)) } // Удалим забаннные хосты for _, id := range delMiners { delete(idArray, utils.StrToInt(id)) } log.Info("%v", "idArray", idArray) ids := "" if len(idArray) > 0 { for id, _ := range idArray { ids += utils.IntToStr(id) + "," } ids = ids[:len(ids)-1] minersHosts, err := d.GetMap(` SELECT tcp_host, user_id FROM miners_data WHERE miner_id IN (`+ids+`)`, "tcp_host", "user_id") if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } for host, userId := range minersHosts { if len(nodesBan[host]) > 0 { if utils.StrToInt64(nodesBan[host]) > utils.Time()-consts.NODE_BAN_TIME { continue } } //hosts = append(hosts, map[string]string{"host": host, "user_id": userId}) /*err = d.ExecSql("DELETE FROM nodes_connection WHERE host = ?", host) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } log.Debug(host)*/ newHostsForCheck = append(newHostsForCheck, map[string]string{"user_id": userId, "host": host}) /*err = d.ExecSql("INSERT INTO nodes_connection ( host, user_id ) VALUES ( ?, ? )", host, userId) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN }*/ } } } hosts = checkHosts(newHostsForCheck, &countOk) log.Debug("countOk: %d / hosts: %v", countOk, hosts) // проверим, не нужно нам выйти, т.к. обновилась версия софта if CheckDaemonsRestart(chBreaker, chAnswer, GoroutineName) { break BEGIN } log.Debug("%v", "hosts", hosts) // если хосты не набрались из miner_data, то берем из файла if len(hosts) < 10 { hostsData_, err := ioutil.ReadFile(*utils.Dir + "/nodes.inc") if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } hostsData := strings.Split(string(hostsData_), "\n") log.Debug("%v", "hostsData_", hostsData_) log.Debug("%v", "hostsData", hostsData) max := 0 log.Debug("maxHosts: %v", maxHosts) if len(hosts) > maxHosts-1 { max = maxHosts } else { max = len(hostsData) } log.Debug("max: %v", max) for i := 0; i < max; i++ { r := utils.RandInt(0, max) if len(hostsData) <= r { continue } hostUserId := strings.Split(hostsData[r], ";") if len(hostUserId) == 1 { continue } host, userId := hostUserId[0], hostUserId[1] if utils.InSliceInt64(utils.StrToInt64(userId), collective) { continue } if len(nodesBan[host]) > 0 { if utils.StrToInt64(nodesBan[host]) > utils.Time()-consts.NODE_BAN_TIME { continue } } /* err = d.ExecSql("DELETE FROM nodes_connection WHERE host = ?", host) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } log.Debug(host) /*err = d.ExecSql("INSERT INTO nodes_connection ( host, user_id ) VALUES ( ?, ? )", host, userId) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN }*/ newHostsForCheck = append(newHostsForCheck, map[string]string{"user_id": userId, "host": host}) nodesInc[host] = userId } } hosts = checkHosts(newHostsForCheck, &countOk) log.Debug("countOk: %d / hosts: %v", countOk, hosts) // проверим, не нужно нам выйти, т.к. обновилась версия софта if CheckDaemonsRestart(chBreaker, chAnswer, GoroutineName) { break BEGIN } for _, host := range hosts { err = d.ExecSql("DELETE FROM nodes_connection WHERE host = ?", host["host"]) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } err = d.ExecSql("INSERT INTO nodes_connection ( host, user_id ) VALUES ( ?, ? )", host["host"], host["user_id"]) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } } if nodeCount > 5 { nodesFile := "" for k, v := range nodesInc { nodesFile += k + ";" + v + "\n" } nodesFile = nodesFile[:len(nodesFile)-1] err := ioutil.WriteFile(*utils.Dir+"/nodes.inc", []byte(nodesFile), 0644) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } } var sleepTime int if countOk < 2 { sleepTime = 5 } else { sleepTime = d.sleepTime } if d.dSleep(sleepTime) { break BEGIN } } log.Debug("break BEGIN %v", GoroutineName) }
/* * просто шлем всем, кто есть в nodes_connection хэши блока и тр-ий * если мы не майнер, то шлем всю тр-ию целиком, блоки слать не можем * если майнер - то шлем только хэши, т.к. у нас есть хост, откуда всё можно скачать * */ func Disseminator(chBreaker chan bool, chAnswer chan string) { defer func() { if r := recover(); r != nil { log.Error("daemon Recovered", r) panic(r) } }() const GoroutineName = "Disseminator" 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 = 300 } else { d.sleepTime = 1 } if !d.CheckInstall(chBreaker, chAnswer, GoroutineName) { return } d.DCDB = DbConnect(chBreaker, chAnswer, GoroutineName) if d.DCDB == nil { return } BEGIN: for { log.Info(GoroutineName) MonitorDaemonCh <- []string{GoroutineName, utils.Int64ToStr(utils.Time())} // проверим, не нужно ли нам выйти из цикла if CheckDaemonsRestart(chBreaker, chAnswer, GoroutineName) { break BEGIN } var hosts []map[string]string var nodeData map[string]string nodeConfig, err := d.GetNodeConfig() if len(nodeConfig["local_gate_ip"]) == 0 { // обычный режим hosts, err = d.GetAll(` SELECT miners_data.user_id, miners_data.tcp_host as host, node_public_key FROM nodes_connection LEFT JOIN miners_data ON nodes_connection.user_id = miners_data.user_id `, -1) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue } if len(hosts) == 0 { if d.dSleep(d.sleepTime) { break BEGIN } log.Debug("len(hosts) == 0") continue } } else { // защищенный режим nodeData, err = d.OneRow("SELECT node_public_key, tcp_host FROM miners_data WHERE user_id = ?", nodeConfig["static_node_user_id"]).String() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue } hosts = append(hosts, map[string]string{"host": nodeConfig["local_gate_ip"], "node_public_key": nodeData["node_public_key"], "user_id": nodeConfig["static_node_user_id"]}) } myUsersIds, err := d.GetMyUsersIds(false, false) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue } myMinersIds, err := d.GetMyMinersIds(myUsersIds) if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue } log.Debug("%v", myUsersIds) log.Debug("%v", myMinersIds) // если среди тр-ий есть смена нодовского ключа, то слать через отправку хэшей с последющей отдачей данных может не получиться // т.к. при некорректном нодовском ключе придет зашифрованый запрос на отдачу данных, а мы его не сможем расшифровать т.к. ключ у нас неверный var changeNodeKey int64 if len(myUsersIds) > 0 { changeNodeKey, err = d.Single(` SELECT count(*) FROM transactions WHERE type = ? AND user_id IN (`+strings.Join(utils.SliceInt64ToString(myUsersIds), ",")+`) `, utils.TypeInt("ChangeNodeKey")).Int64() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } } var dataType int64 // это тип для того, чтобы принимающая сторона могла понять, как именно надо обрабатывать присланные данные // если я майнер и работаю в обычном режиме, то должен слать хэши if len(myMinersIds) > 0 && len(nodeConfig["local_gate_ip"]) == 0 && changeNodeKey == 0 { log.Debug("0") dataType = 1 // определим, от кого будем слать r := utils.RandInt(0, len(myMinersIds)) myMinerId := myMinersIds[r] myUserId, err := d.Single("SELECT user_id FROM miners_data WHERE miner_id = ?", myMinerId).Int64() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } // возьмем хэш текущего блока и номер блока // для теста ролбеков отключим на время data, err := d.OneRow("SELECT block_id, hash, head_hash FROM info_block WHERE sent = 0").Bytes() if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } err = d.ExecSql("UPDATE info_block SET sent = 1") if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } /* * Составляем данные на отправку * */ // 5 байт = наш user_id. Но они будут не первые, т.к. m_curl допишет вперед user_id получателя (нужно для пулов) toBeSent := utils.DecToBin(myUserId, 5) if len(data) > 0 { // блок // если 5-й байт = 0, то на приемнике будем читать блок, если = 1 , то сразу хэши тр-ий toBeSent = append(toBeSent, utils.DecToBin(0, 1)...) toBeSent = append(toBeSent, utils.DecToBin(utils.BytesToInt64(data["block_id"]), 3)...) toBeSent = append(toBeSent, data["hash"]...) toBeSent = append(toBeSent, data["head_hash"]...) err = d.ExecSql("UPDATE info_block SET sent = 1") if err != nil { if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } } else { // тр-ии без блока toBeSent = append(toBeSent, utils.DecToBin(1, 1)...) } // возьмем хэши тр-ий //utils.WriteSelectiveLog("SELECT hash, high_rate FROM transactions WHERE sent = 0 AND for_self_use = 0") transactions, err := d.GetAll("SELECT hash, high_rate FROM transactions WHERE sent = 0 AND for_self_use = 0", -1) if err != nil { utils.WriteSelectiveLog(err) if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } // нет ни транзакций, ни блока для отправки... if len(transactions) == 0 && len(toBeSent) < 10 { //utils.WriteSelectiveLog("len(transactions) == 0") //log.Debug("len(transactions) == 0") if d.dSleep(d.sleepTime) { break BEGIN } log.Debug("len(transactions) == 0 && len(toBeSent) == 0") continue BEGIN } for _, data := range transactions { hexHash := utils.BinToHex([]byte(data["hash"])) toBeSent = append(toBeSent, utils.DecToBin(utils.StrToInt64(data["high_rate"]), 1)...) toBeSent = append(toBeSent, []byte(data["hash"])...) utils.WriteSelectiveLog("UPDATE transactions SET sent = 1 WHERE hex(hash) = " + string(hexHash)) affect, err := d.ExecSqlGetAffect("UPDATE transactions SET sent = 1 WHERE hex(hash) = ?", hexHash) if err != nil { utils.WriteSelectiveLog(err) if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } utils.WriteSelectiveLog("affect: " + utils.Int64ToStr(affect)) } // отправляем блок и хэши тр-ий, если есть что отправлять if len(toBeSent) > 0 { for _, host := range hosts { go d.DisseminatorType1(host["host"], utils.StrToInt64(host["user_id"]), host["node_public_key"], toBeSent, dataType) } } } else { log.Debug("1") var remoteNodeHost string // если просто юзер или работаю в защищенном режиме, то шлю тр-ии целиком. слать блоки не имею права. if len(nodeConfig["local_gate_ip"]) > 0 { dataType = 3 remoteNodeHost = nodeData["host"] } else { dataType = 2 remoteNodeHost = "" } log.Debug("dataType: %d", dataType) var toBeSent []byte // сюда пишем все тр-ии, которые будем слать другим нодам // возьмем хэши и сами тр-ии utils.WriteSelectiveLog("SELECT hash, data FROM transactions WHERE sent = 0") rows, err := d.Query("SELECT hash, data FROM transactions WHERE sent = 0") if err != nil { utils.WriteSelectiveLog(err) if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } for rows.Next() { var hash, data []byte err = rows.Scan(&hash, &data) if err != nil { rows.Close() if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } log.Debug("hash %x", hash) hashHex := utils.BinToHex(hash) utils.WriteSelectiveLog("UPDATE transactions SET sent = 1 WHERE hex(hash) = " + string(hashHex)) affect, err := d.ExecSqlGetAffect("UPDATE transactions SET sent = 1 WHERE hex(hash) = ?", hashHex) if err != nil { utils.WriteSelectiveLog(err) rows.Close() if d.dPrintSleep(err, d.sleepTime) { break BEGIN } continue BEGIN } utils.WriteSelectiveLog("affect: " + utils.Int64ToStr(affect)) toBeSent = append(toBeSent, data...) } rows.Close() // шлем тр-ии if len(toBeSent) > 0 { for _, host := range hosts { userId := utils.StrToInt64(host["user_id"]) go func(host string, userId int64, node_public_key string) { log.Debug("host %v / userId %v", host, userId) conn, err := utils.TcpConn(host) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } defer conn.Close() randTestblockHash, err := d.Single("SELECT head_hash FROM queue_testblock").String() if err != nil { log.Error("%v", utils.ErrInfo(err)) return } // получаем IV + ключ + зашифрованный текст encryptedData, _, _, err := utils.EncryptData(toBeSent, []byte(node_public_key), randTestblockHash) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } // вначале шлем тип данных, чтобы принимающая сторона могла понять, как именно надо обрабатывать присланные данные _, err = conn.Write(utils.DecToBin(dataType, 1)) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } // т.к. на приеме может быть пул, то нужно дописать в начало user_id, чьим нодовским ключем шифруем /*_, err = conn.Write(utils.DecToBin(userId, 5)) if err != nil { log.Error("%v", utils.ErrInfo(err)) return }*/ encryptedData = append(utils.DecToBin(userId, 5), encryptedData...) // это может быть защищенное локальное соедниение (dataType = 3) и принимающему ноду нужно знать, куда дальше слать данные и чьим они зашифрованы ключем if len(remoteNodeHost) > 0 { /* _, err = conn.Write([]byte(remoteNodeHost)) if err != nil { log.Error("%v", utils.ErrInfo(err)) return }*/ encryptedData = append([]byte(remoteNodeHost), encryptedData...) } log.Debug("encryptedData %x", encryptedData) // в 4-х байтах пишем размер данных, которые пошлем далее size := utils.DecToBin(len(encryptedData), 4) _, err = conn.Write(size) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } // далее шлем сами данные _, err = conn.Write(encryptedData) if err != nil { log.Error("%v", utils.ErrInfo(err)) return } }(host["host"], userId, host["node_public_key"]) } } } d.dbUnlock() if d.dSleep(d.sleepTime) { break BEGIN } } log.Debug("break BEGIN %v", GoroutineName) }
func makeTemplate(html, name string, tData interface{}) (string, error) { defer func() { if r := recover(); r != nil { log.Error("makeTemplate Recovered", r) fmt.Println(r) } }() data, err := static.Asset("static/templates/" + html + ".html") if err != nil { return "", utils.ErrInfo(err) } signatures, err := static.Asset("static/templates/signatures.html") if err != nil { return "", utils.ErrInfo(err) } alert_success, err := static.Asset("static/templates/alert_success.html") if err != nil { return "", utils.ErrInfo(err) } funcMap := template.FuncMap{ "makeCurrencyName": func(currencyId int64) string { if currencyId >= 1000 { return "" } else { return "d" } }, "div": func(a, b interface{}) float64 { return utils.InterfaceToFloat64(a) / utils.InterfaceToFloat64(b) }, "mult": func(a, b interface{}) float64 { return utils.InterfaceToFloat64(a) * utils.InterfaceToFloat64(b) }, "round": func(a interface{}, num int) float64 { return utils.Round(utils.InterfaceToFloat64(a), num) }, "len": func(s []map[string]string) int { return len(s) }, "lenMap": func(s map[string]string) int { return len(s) }, "sum": func(a, b interface{}) float64 { return utils.InterfaceToFloat64(a) + utils.InterfaceToFloat64(b) }, "minus": func(a, b interface{}) float64 { return utils.InterfaceToFloat64(a) - utils.InterfaceToFloat64(b) }, "noescape": func(s string) template.HTML { return template.HTML(s) }, "js": func(s string) template.JS { return template.JS(s) }, "join": func(s []string, sep string) string { return strings.Join(s, sep) }, "strToInt64": func(text string) int64 { return utils.StrToInt64(text) }, "strToInt": func(text string) int { return utils.StrToInt(text) }, "bin2hex": func(text string) string { return string(utils.BinToHex([]byte(text))) }, "int64ToStr": func(text int64) string { return utils.Int64ToStr(text) }, "rand": func() int { return utils.RandInt(0, 99999999) }, "append": func(args ...interface{}) string { var result string for _, value := range args { switch value.(type) { case int64: result += utils.Int64ToStr(value.(int64)) case float64: result += utils.Float64ToStr(value.(float64)) case string: result += value.(string) } } return result }, "replaceCurrency": func(text, name string) string { return strings.Replace(text, "[currency]", name, -1) }, "replaceCurrencyName": func(text, name string) string { return strings.Replace(text, "[currency]", "D"+name, -1) }, "cfCategoryLang": func(lang map[string]string, name string) string { return lang["cf_category_"+name] }, "progressBarLang": func(lang map[string]string, name string) string { return lang["progress_bar_pct_"+name] }, "checkProjectPs": func(ProjectPs map[string]string, id string) bool { if len(ProjectPs["ps"+id]) > 0 { return true } else { return false } }, "cfPageTypeLang": func(lang map[string]string, name string) string { return lang["cf_"+name] }, "notificationsLang": func(lang map[string]string, name string) string { return lang["notifications_"+name] }, } t := template.Must(template.New("template").Funcs(funcMap).Parse(string(data))) t = template.Must(t.Parse(string(alert_success))) t = template.Must(t.Parse(string(signatures))) b := new(bytes.Buffer) err = t.ExecuteTemplate(b, name, tData) if err != nil { return "", utils.ErrInfo(err) } return b.String(), nil }
func (c *Controller) Voting() (string, error) { txType := "VotesComplex" txTypeId := utils.TypeInt(txType) timeNow := utils.Time() waitVoting := make(map[int64]string) promisedAmountCurrencyList := make(map[int64]map[string]string) // голосовать майнер может только после того, как пройдет miner_newbie_time сек regTime, err := c.Single("SELECT reg_time FROM miners_data WHERE user_id = ?", c.SessUserId).Int64() if err != nil { return "", utils.ErrInfo(err) } minerNewbie := "" if regTime > utils.Time()-c.Variables.Int64["miner_newbie_time"] && c.SessUserId != 1 { minerNewbie = strings.Replace(c.Lang["hold_time_wait2"], "[sec]", utils.TimeLeft(c.Variables.Int64["miner_newbie_time"]-(utils.Time()-regTime), c.Lang), -1) } else { // валюты rows, err := c.Query(c.FormatQuery(` SELECT currency_id, name, full_name, start_time FROM promised_amount LEFT JOIN currency ON currency.id = promised_amount.currency_id WHERE user_id = ? AND status IN ('mining', 'repaid') AND start_time > 0 AND del_block_id = 0 GROUP BY currency_id `), c.SessUserId) if err != nil { return "", utils.ErrInfo(err) } defer rows.Close() for rows.Next() { var currency_id, start_time int64 var name, full_name string err = rows.Scan(¤cy_id, &name, &full_name, &start_time) if err != nil { return "", utils.ErrInfo(err) } // после добавления обещанной суммы должно пройти не менее min_hold_time_promise_amount сек, чтобы за неё можно было голосовать if start_time > utils.Time()-c.Variables.Int64["min_hold_time_promise_amount"] { waitVoting[currency_id] = strings.Replace(c.Lang["hold_time_wait"], "[sec]", utils.TimeLeft(c.Variables.Int64["min_hold_time_promise_amount"]-(utils.Time()-start_time), c.Lang), -1) continue } // если по данной валюте еще не набралось >1000 майнеров, то за неё голосовать нельзя. countMiners, err := c.Single(` SELECT count(user_id) FROM promised_amount WHERE start_time < ? AND del_block_id = 0 AND status IN ('mining', 'repaid') AND currency_id = ? AND del_block_id = 0 GROUP BY user_id `, utils.Time()-c.Variables.Int64["min_hold_time_promise_amount"], currency_id).Int64() if err != nil { return "", utils.ErrInfo(err) } if countMiners < c.Variables.Int64["min_miners_of_voting"] { waitVoting[currency_id] = strings.Replace(c.Lang["min_miners_count"], "[miners_count]", utils.Int64ToStr(c.Variables.Int64["min_miners_of_voting"]), -1) waitVoting[currency_id] = strings.Replace(waitVoting[currency_id], "[remaining]", utils.Int64ToStr(c.Variables.Int64["min_miners_of_voting"]-countMiners), -1) continue } // голосовать можно не чаще 1 раза в 2 недели voteTime, err := c.Single("SELECT time FROM log_time_votes_complex WHERE user_id = ? AND time > ?", c.SessUserId, utils.Time()-c.Variables.Int64["limit_votes_complex_period"]).Int64() if err != nil { return "", utils.ErrInfo(err) } if voteTime > 0 { waitVoting[currency_id] = strings.Replace(c.Lang["wait_voting"], "[sec]", utils.TimeLeft(c.Variables.Int64["limit_votes_complex_period"]-(utils.Time()-voteTime), c.Lang), -1) continue } // получим наши предыдущие голоса votesUserPct, err := c.Single("SELECT pct FROM votes_user_pct WHERE user_id = ? AND currency_id = ?", c.SessUserId, currency_id).Int64() if err != nil { return "", utils.ErrInfo(err) } votesMinerPct, err := c.Single("SELECT pct FROM votes_miner_pct WHERE user_id = ? AND currency_id = ?", c.SessUserId, currency_id).Int64() if err != nil { return "", utils.ErrInfo(err) } votesMaxOtherCurrencies, err := c.Single("SELECT count FROM votes_max_other_currencies WHERE user_id = ? AND currency_id = ?", c.SessUserId, currency_id).Int64() if err != nil { return "", utils.ErrInfo(err) } votesMaxPromisedAmount, err := c.Single("SELECT amount FROM votes_max_promised_amount WHERE user_id = ? AND currency_id = ?", c.SessUserId, currency_id).Int64() if err != nil { return "", utils.ErrInfo(err) } promisedAmountCurrencyList[currency_id] = make(map[string]string) promisedAmountCurrencyList[currency_id]["votes_user_pct"] = utils.Int64ToStr(votesUserPct) promisedAmountCurrencyList[currency_id]["votes_miner_pct"] = utils.Int64ToStr(votesMinerPct) promisedAmountCurrencyList[currency_id]["votes_max_other_currencies"] = utils.Int64ToStr(votesMaxOtherCurrencies) promisedAmountCurrencyList[currency_id]["votes_max_promised_amount"] = utils.Int64ToStr(votesMaxPromisedAmount) promisedAmountCurrencyList[currency_id]["name"] = name } } referral, err := c.OneRow("SELECT first, second, third FROM votes_referral WHERE user_id = ?", c.SessUserId).Int64() if err != nil { return "", utils.ErrInfo(err) } if len(referral) == 0 { referral["first"] = int64(utils.RandInt(0, 30)) referral["second"] = int64(utils.RandInt(0, 30)) referral["third"] = int64(utils.RandInt(0, 30)) } maxCurrencyId, err := c.Single("SELECT max(id) FROM currency").Int64() if err != nil { return "", utils.ErrInfo(err) } allMaxPromisedAmount := []int64{1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000, 1000000, 2000000, 5000000, 10000000, 20000000, 50000000, 100000000, 200000000, 500000000, 1000000000} allPct := utils.GetPctArray() pctArray := utils.GetPctArray() jsPct := "{" for year, sec := range pctArray { jsPct += fmt.Sprintf(`%v: '%v',`, year, sec) } jsPct = jsPct[:len(jsPct)-1] + "}" lastTx, err := c.GetLastTx(c.SessUserId, utils.TypesToIds([]string{"VotesComplex"}), 1, c.TimeFormat) lastTxFormatted := "" if len(lastTx) > 0 { lastTxFormatted, _ = utils.MakeLastTx(lastTx, c.Lang) } refs := []string{"first", "second", "third"} refsNums := []int{0, 5, 10, 15, 20, 25, 30} TemplateStr, err := makeTemplate("voting", "voting", &VotingPage{ Alert: c.Alert, Lang: c.Lang, CountSignArr: c.CountSignArr, ShowSignData: c.ShowSignData, UserId: c.SessUserId, TimeNow: timeNow, TxType: txType, TxTypeId: txTypeId, SignData: "", PromisedAmountCurrencyList: promisedAmountCurrencyList, MaxOtherCurrenciesCount: []int{0, 1, 2, 3, 4}, RefsNums: refsNums, Referral: referral, MinerNewbie: minerNewbie, MaxCurrencyId: maxCurrencyId, AllMaxPromisedAmount: allMaxPromisedAmount, AllPct: allPct, LastTxFormatted: lastTxFormatted, WaitVoting: waitVoting, CurrencyList: c.CurrencyList, JsPct: jsPct, Refs: refs}) 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) Upgrade3() (string, error) { log.Debug("Upgrade3") userProfile := *utils.Dir + "/public/" + utils.Int64ToStr(c.SessUserId) + "_user_profile.jpg" userFace := *utils.Dir + "/public/" + utils.Int64ToStr(c.SessUserId) + "_user_face.jpg" if _, err := os.Stat(userProfile); os.IsNotExist(err) { userProfile = "" } else { userProfile = "public/" + utils.Int64ToStr(c.SessUserId) + "_user_profile.jpg?r=" + utils.IntToStr(utils.RandInt(0, 99999)) } if _, err := os.Stat(userFace); os.IsNotExist(err) { userFace = "" } else { userFace = "public/" + utils.Int64ToStr(c.SessUserId) + "_user_face.jpg?r=" + utils.IntToStr(utils.RandInt(0, 99999)) } log.Debug("userProfile: %s", userProfile) log.Debug("userFace: %s", userFace) // текущий набор точек для шаблонов examplePoints, err := c.GetPoints(c.Lang) if err != nil { return "", utils.ErrInfo(err) } // точки, которые юзер уже отмечал data, err := c.OneRow("SELECT face_coords, profile_coords FROM " + c.MyPrefix + "my_table").String() if err != nil { return "", utils.ErrInfo(err) } faceCoords := "" profileCoords := "" if len(data["face_coords"]) > 0 { faceCoords = data["face_coords"] profileCoords = data["profile_coords"] } saveAndGotoStep := strings.Replace(c.Lang["save_and_goto_step"], "[num]", "5", -1) upgradeMenu := utils.MakeUpgradeMenu(3) TemplateStr, err := makeTemplate("upgrade_3", "upgrade3", &upgrade3Page{ Alert: c.Alert, Lang: c.Lang, CountSignArr: c.CountSignArr, ShowSignData: c.ShowSignData, SaveAndGotoStep: saveAndGotoStep, UpgradeMenu: upgradeMenu, UserId: c.SessUserId, FaceCoords: faceCoords, ProfileCoords: profileCoords, UserProfile: userProfile, UserFace: userFace, ExamplePoints: examplePoints, IOS: utils.IOS(), Mobile: utils.Mobile()}) if err != nil { return "", utils.ErrInfo(err) } return TemplateStr, nil }