func Start(dir string, thrustWindowLoder *window.Window) { var err error IosLog("start") defer func() { if r := recover(); r != nil { log.Error("Recovered", r) panic(r) } }() if dir != "" { fmt.Println("dir", dir) *utils.Dir = dir } IosLog("dir:" + dir) fmt.Println("utils.Dir", *utils.Dir) fmt.Println("dcVersion:", consts.VERSION) log.Debug("dcVersion: %v", consts.VERSION) // читаем config.ini configIni := make(map[string]string) configIni_, err := config.NewConfig("ini", *utils.Dir+"/config.ini") if err != nil { IosLog("err:" + fmt.Sprintf("%s", utils.ErrInfo(err))) log.Error("%v", utils.ErrInfo(err)) } else { configIni, err = configIni_.GetSection("default") } // убьем ранее запущенный Dcoin if !utils.Mobile() { fmt.Println("kill dcoin.pid") if _, err := os.Stat(*utils.Dir + "/dcoin.pid"); err == nil { dat, err := ioutil.ReadFile(*utils.Dir + "/dcoin.pid") if err != nil { log.Error("%v", utils.ErrInfo(err)) } var pidMap map[string]string err = json.Unmarshal(dat, &pidMap) if err != nil { log.Error("%v", utils.ErrInfo(err)) } fmt.Println("old PID ("+*utils.Dir+"/dcoin.pid"+"):", pidMap["pid"]) utils.DB, err = utils.NewDbConnect(configIni) err = KillPid(pidMap["pid"]) if nil != err { fmt.Println(err) log.Error("KillPid %v", utils.ErrInfo(err)) } if fmt.Sprintf("%s", err) != "null" { fmt.Println(fmt.Sprintf("%s", err)) // даем 15 сек, чтобы завершиться предыдущему процессу for i := 0; i < 15; i++ { log.Debug("waiting killer %d", i) if _, err := os.Stat(*utils.Dir + "/dcoin.pid"); err == nil { fmt.Println("waiting killer") utils.Sleep(1) } else { // если dcoin.pid нет, значит завершился break } } } } } // сохраним текущий pid и версию if !utils.Mobile() { pid := os.Getpid() PidAndVer, err := json.Marshal(map[string]string{"pid": utils.IntToStr(pid), "version": consts.VERSION}) if err != nil { log.Error("%v", utils.ErrInfo(err)) } err = ioutil.WriteFile(*utils.Dir+"/dcoin.pid", PidAndVer, 0644) if err != nil { log.Error("%v", utils.ErrInfo(err)) panic(err) } } controllers.SessInit() controllers.ConfigInit() daemons.ConfigInit() go func() { utils.DB, err = utils.NewDbConnect(configIni) log.Debug("%v", utils.DB) IosLog("utils.DB:" + fmt.Sprintf("%v", utils.DB)) if err != nil { IosLog("err:" + fmt.Sprintf("%s", utils.ErrInfo(err))) log.Error("%v", utils.ErrInfo(err)) panic(err) os.Exit(1) } }() f, err := os.OpenFile(*utils.Dir+"/dclog.txt", os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0777) if err != nil { IosLog("err:" + fmt.Sprintf("%s", utils.ErrInfo(err))) log.Error("%v", utils.ErrInfo(err)) panic(err) os.Exit(1) } defer f.Close() IosLog("configIni:" + fmt.Sprintf("%v", configIni)) var backend *logging.LogBackend switch configIni["log_output"] { case "file": backend = logging.NewLogBackend(f, "", 0) case "console": backend = logging.NewLogBackend(os.Stderr, "", 0) case "file_console": //backend = logging.NewLogBackend(io.MultiWriter(f, os.Stderr), "", 0) default: backend = logging.NewLogBackend(f, "", 0) } backendFormatter := logging.NewBackendFormatter(backend, format) backendLeveled := logging.AddModuleLevel(backendFormatter) logLevel_ := "DEBUG" if *utils.LogLevel == "" { logLevel_ = configIni["log_level"] } else { logLevel_ = *utils.LogLevel } logLevel, err := logging.LogLevel(logLevel_) if err != nil { log.Error("%v", utils.ErrInfo(err)) } log.Debug("logLevel: %v", logLevel) backendLeveled.SetLevel(logLevel, "") logging.SetBackend(backendLeveled) rand.Seed(time.Now().UTC().UnixNano()) // если есть OldFileName, значит работаем под именем tmp_dc и нужно перезапуститься под нормальным именем log.Error("OldFileName %v", *utils.OldFileName) if *utils.OldFileName != "" { // вначале нужно обновить БД в зависимости от версии dat, err := ioutil.ReadFile(*utils.Dir + "/dcoin.pid") if err != nil { log.Error("%v", utils.ErrInfo(err)) } var pidMap map[string]string err = json.Unmarshal(dat, &pidMap) if err != nil { log.Error("%v", utils.ErrInfo(err)) } log.Debug("OldFileName %v", *utils.OldFileName) err = utils.CopyFileContents(*utils.Dir+`/dc.tmp`, *utils.OldFileName) if err != nil { log.Debug("%v", os.Stderr) log.Debug("%v", utils.ErrInfo(err)) } // ждем подключения к БД for { if utils.DB == nil || utils.DB.DB == nil { utils.Sleep(1) continue } break } if len(pidMap["version"]) > 0 { if utils.VersionOrdinal(pidMap["version"]) < utils.VersionOrdinal("1.0.2b5") { log.Debug("%v", "ALTER TABLE config ADD COLUMN analytics_disabled smallint") err = utils.DB.ExecSql(`ALTER TABLE config ADD COLUMN analytics_disabled smallint`) if err != nil { log.Error("%v", utils.ErrInfo(err)) } } if utils.VersionOrdinal(pidMap["version"]) < utils.VersionOrdinal("2.0.1b2") { log.Debug("%v", "ALTER TABLE config ADD COLUMN sqlite_db_url varchar(255)") err = utils.DB.ExecSql(`ALTER TABLE config ADD COLUMN sqlite_db_url varchar(255)`) if err != nil { log.Error("%v", utils.ErrInfo(err)) } } } err = utils.DB.Close() if err != nil { log.Error("%v", utils.ErrInfo(err)) } fmt.Println("DB Closed") err = os.Remove(*utils.Dir + "/dcoin.pid") if err != nil { log.Error("%v", utils.ErrInfo(err)) } log.Debug("dc.tmp %v", *utils.Dir+`/dc.tmp`) err = exec.Command(*utils.OldFileName, "-dir", *utils.Dir).Start() if err != nil { log.Debug("%v", os.Stderr) log.Debug("%v", utils.ErrInfo(err)) } log.Debug("OldFileName %v", *utils.OldFileName) os.Exit(1) } // откат БД до указанного блока if *utils.RollbackToBlockId > 0 { utils.DB, err = utils.NewDbConnect(configIni) parser := new(dcparser.Parser) parser.DCDB = utils.DB err = parser.RollbackToBlockId(*utils.RollbackToBlockId) if err != nil { fmt.Println(err) panic(err) } fmt.Print("complete") os.Exit(0) } log.Debug("public") IosLog("public") if _, err := os.Stat(*utils.Dir + "/public"); os.IsNotExist(err) { err = os.Mkdir(*utils.Dir+"/public", 0755) if err != nil { log.Error("%v", utils.ErrInfo(err)) panic(err) os.Exit(1) } } log.Debug("daemonsStart") IosLog("daemonsStart") daemons.StartDaemons() IosLog("MonitorDaemons") // мониторинг демонов daemonsTable := make(map[string]string) go func() { for { daemonNameAndTime := <-daemons.MonitorDaemonCh daemonsTable[daemonNameAndTime[0]] = daemonNameAndTime[1] if utils.Time()%10 == 0 { log.Debug("daemonsTable: %v\n", daemonsTable) } } }() // сигналы демонам для выхода IosLog("signals") stopdaemons.Signals() utils.Sleep(1) // мониторим сигнал из БД о том, что демонам надо завершаться go stopdaemons.WaitStopTime() BrowserHttpHost := "http://localhost:8089" HandleHttpHost := "" ListenHttpHost := ":" + *utils.ListenHttpHost go func() { // уже прошли процесс инсталяции, где юзер указал БД и был перезапуск кошелька if len(configIni["db_type"]) > 0 && !utils.Mobile() { for { // ждем, пока произойдет подключение к БД в другой гоурутине if utils.DB == nil || utils.DB.DB == nil { utils.Sleep(1) fmt.Println("wait DB") } else { break } } fmt.Println("GET http host") BrowserHttpHost, HandleHttpHost, ListenHttpHost = GetHttpHost() // для биржы нужен хост или каталог, поэтому нужно подключение к БД exhangeHttpListener(HandleHttpHost) // для ноды тоже нужна БД tcpListener() } IosLog(fmt.Sprintf("BrowserHttpHost: %v, HandleHttpHost: %v, ListenHttpHost: %v", BrowserHttpHost, HandleHttpHost, ListenHttpHost)) fmt.Printf("BrowserHttpHost: %v, HandleHttpHost: %v, ListenHttpHost: %v\n", BrowserHttpHost, HandleHttpHost, ListenHttpHost) // включаем листинг веб-сервером для клиентской части http.HandleFunc(HandleHttpHost+"/", controllers.Index) http.HandleFunc(HandleHttpHost+"/content", controllers.Content) http.HandleFunc(HandleHttpHost+"/ajax", controllers.Ajax) http.HandleFunc(HandleHttpHost+"/tools", controllers.Tools) http.HandleFunc(HandleHttpHost+"/cf/", controllers.IndexCf) http.HandleFunc(HandleHttpHost+"/cf/content", controllers.ContentCf) http.Handle(HandleHttpHost+"/public/", noDirListing(http.FileServer(http.Dir(*utils.Dir)))) http.Handle(HandleHttpHost+"/static/", http.FileServer(&assetfs.AssetFS{Asset: static.Asset, AssetDir: static.AssetDir, Prefix: ""})) log.Debug("ListenHttpHost", ListenHttpHost) IosLog(fmt.Sprintf("ListenHttpHost: %v", ListenHttpHost)) fmt.Println("ListenHttpHost", ListenHttpHost) httpListener(ListenHttpHost, BrowserHttpHost) if *utils.Console == 0 && !utils.Mobile() { utils.Sleep(1) if thrustWindowLoder != nil { thrustWindowLoder.Close() thrustWindow := thrust.NewWindow(thrust.WindowOptions{ RootUrl: BrowserHttpHost, Size: commands.SizeHW{Width: 1024, Height: 600}, }) thrustWindow.HandleEvent("*", func(cr commands.EventResult) { fmt.Println("HandleEvent", cr) }) thrustWindow.HandleRemote(func(er commands.EventResult, this *window.Window) { fmt.Println("RemoteMessage Recieved:", er.Message.Payload) openBrowser(er.Message.Payload) // Keep in mind once we have the message, lets say its json of some new type we made, // We can unmarshal it to that type. // Same goes for the other way around. this.SendRemoteMessage("boop") }) thrustWindow.Show() thrustWindow.Focus() } else { openBrowser(BrowserHttpHost) } } }() // ожидает появления свежих записей в чате, затем ждет появления коннектов // (заносятся из демеона connections и от тех, кто сам подключился к ноде) go utils.ChatOutput(utils.ChatNewTx) log.Debug("ALL RIGHT") IosLog("ALL RIGHT") fmt.Println("ALL RIGHT") utils.Sleep(3600 * 24 * 90) log.Debug("EXIT") }
func (c *Controller) AlertMessage() (string, error) { if c.SessRestricted != 0 { return "", nil } c.r.ParseForm() if ok, _ := regexp.MatchString(`install`, c.r.FormValue("tpl_name")); ok { return "", nil } show := false // проверим, есть ли сообщения от админа data, err := c.OneRow("SELECT * FROM alert_messages WHERE close = 0 ORDER BY id DESC").String() if err != nil { return "", utils.ErrInfo(err) } var message map[string]string var adminMessage string if len(data["message"]) > 0 { err = json.Unmarshal([]byte(data["message"]), &message) if err != nil { return "", utils.ErrInfo(err) } if len(message[utils.Int64ToStr(c.LangInt)]) > 0 { adminMessage = message[utils.Int64ToStr(c.LangInt)] } else { adminMessage = message["gen"] } if data["currency_list"] != "ALL" { // проверим, есть ли у нас обещанные суммы с такой валютой promisedAmount, err := c.Single("SELECT id FROM promised_amount WHERE currency_id IN (" + data["currency_list"] + ")").Int64() if err != nil { return "", utils.ErrInfo(err) } if promisedAmount > 0 { show = true } } else { show = true } } result := "" if show { result += `<script> $('#close_alert').bind('click', function () { $.post( 'ajax?controllerName=closeAlert', { 'id' : '` + data["id"] + `' } ); }); </script> <div class="alert alert-danger alert-dismissable" style='margin-top: 30px'><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button> <h4>Warning!</h4> ` + adminMessage + ` </div>` } // сообщение о новой версии движка myVer, err := c.Single("SELECT current_version FROM info_block").String() if err != nil { return "", utils.ErrInfo(err) } // возможны 2 сценария: // 1. информация о новой версии есть в блоках newVer, err := c.GetList("SELECT version FROM new_version WHERE alert = 1").String() if err != nil { return "", utils.ErrInfo(err) } newMaxVer := "0" for i := 0; i < len(newVer); i++ { if utils.VersionOrdinal(newVer[i]) > utils.VersionOrdinal(myVer) && newMaxVer == "0" { newMaxVer = newVer[i] } if utils.VersionOrdinal(newVer[i]) > utils.VersionOrdinal(newMaxVer) && newMaxVer != "0" { newMaxVer = newVer[i] } } var newVersion string if newMaxVer != "0" { newVersion = strings.Replace(c.Lang["new_version"], "[ver]", newMaxVer, -1) } // для пулов и ограниченных юзеров выводим сообщение без кнопок if (c.Community || c.SessRestricted != 0) && newMaxVer != "0" { newVersion = strings.Replace(c.Lang["new_version_pulls"], "[ver]", newMaxVer, -1) } if newMaxVer != "0" && len(myVer) > 0 { result += `<script> $('#btn_install').bind('click', function () { $('#new_version_text').text('Please wait'); $.post( 'ajax?controllerName=installNewVersion', {}, function(data) { $('#new_version_text').text(data); }); }); $('#btn_upgrade').bind('click', function () { $('#new_version_text').text('Please wait'); $.post( 'ajax?controllerName=upgradeToNewVersion', {}, function(data) { $('#new_version_text').text(data); }); }); </script> <div class="alert alert-danger alert-dismissable" style='margin-top: 30px'><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button> <h4>Warning!</h4> <div id='new_version_text'>` + newVersion + `</div> </div>` } if c.SessRestricted == 0 && (!c.Community || c.PoolAdmin) { myMinerId, err := c.GetMinerId(c.SessUserId) if err != nil { return "", utils.ErrInfo(err) } // если юзер уже майнер, то у него должно быть настроено точное время if myMinerId > 0 { networkTime, err := utils.GetNetworkTime() if err != nil { return "", utils.ErrInfo(err) } diff := int64(math.Abs(float64(utils.Time() - networkTime.Unix()))) if diff > c.Variables.Int64["alert_error_time"] { alertTime := strings.Replace(c.Lang["alert_time"], "[sec]", utils.Int64ToStr(diff), -1) result += `<div class="alert alert-danger alert-dismissable" style='margin-top: 30px'><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button> <h4>Warning!</h4> <div>` + alertTime + `</div> </div>` } } } if c.SessRestricted == 0 { // после обнуления таблиц my_node_key будет пуст // получим время из последнего блока myNodePrivateKey, err := c.GetNodePrivateKey(c.MyPrefix) if err != nil { return "", utils.ErrInfo(err) } minerId, err := c.GetMinerId(c.SessUserId) if err != nil { return "", utils.ErrInfo(err) } // возможно юзер новенький на пуле и у него разные нод-ключи nodePublicKey, err := c.GetNodePublicKey(c.SessUserId) if err != nil { return "", utils.ErrInfo(err) } myNodePublicKey, err := c.GetMyNodePublicKey(c.MyPrefix) if err != nil { return "", utils.ErrInfo(err) } if (len(myNodePrivateKey) == 0 && minerId > 0) || (string(nodePublicKey) != myNodePublicKey && len(nodePublicKey) > 0) { result += `<div class="alert alert-danger alert-dismissable" style='margin-top: 30px'><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button> <h4>Warning!</h4> <div>` + c.Lang["alert_change_node_key"] + `</div> </div>` } } // просто информируем, что в данном разделе у юзера нет прав skipCommunity := []string{"nodeConfig", "nulling", "startStop"} skipRestrictedUsers := []string{"nodeConfig", "changeNodeKey", "nulling", "startStop", "cashRequestIn", "cashRequestOut", "upgrade", "notifications", "interface"} if (!c.NodeAdmin && utils.InSliceString(c.TplName, skipCommunity)) || (c.SessRestricted != 0 && utils.InSliceString(c.TplName, skipRestrictedUsers)) { result += `<div class="alert alert-danger alert-dismissable" style='margin-top: 30px'><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button> <h4>Warning!</h4> <div>` + c.Lang["permission_denied"] + `</div> </div>` } // информируем, что у юзера нет прав и нужно стать майнером minersOnly := []string{"myCfProjects", "newCfProject", "cashRequestIn", "cashRequestOut", "changeNodeKey", "voting", "geolocation", "promisedAmountList", "promisedAmountAdd", "holidaysList", "newHolidays", "points", "tasks", "changeHost", "newUser", "changeCommission"} if utils.InSliceString(c.TplName, minersOnly) { minerId, err := c.Single("SELECT miner_id FROM users LEFT JOIN miners_data ON users.user_id = miners_data.user_id WHERE users.user_id = ?", c.SessUserId).Int64() if err != nil { return "", utils.ErrInfo(err) } if minerId == 0 { result += `<div class="alert alert-danger alert-dismissable" style='margin-top: 30px'><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button> <h4>Warning!</h4> <div>` + c.Lang["only_for_miners"] + `</div> </div>` } } // информируем, что необходимо вначале сменить праймари-ключ logId, err := c.Single("SELECT log_id FROM users WHERE user_id = ?", c.SessUserId).Int64() if err != nil { return "", utils.ErrInfo(err) } if logId == 0 { text := "" // проверим, есть ли запросы на смену в тр-ях lastTx, err := c.GetLastTx(c.SessUserId, utils.TypesToIds([]string{"ChangePrimaryKey"}), 1, c.TimeFormat) if err != nil { return "", utils.ErrInfo(err) } if len(lastTx) == 0 { // юзер еще не начинал смену ключа text = c.Lang["alert_change_primary_key"] } else if len(lastTx[0]["error"]) > 0 || len(lastTx[0]["queue_tx"]) > 0 || len(lastTx[0]["tx"]) > 0 || utils.Time()-utils.StrToInt64(lastTx[0]["time_int"]) > 3600 { text = c.Lang["please_try_again_change_key"] } else { text = c.Lang["please_wait_changing_key"] } result += `<div class="alert alert-danger alert-dismissable" style='margin-top: 30px'><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button> <h4>` + c.Lang["warning"] + `</h4> <div>` + text + `</div> </div>` } return result, nil }