コード例 #1
0
ファイル: WhatToMine.cs プロジェクト: xeddmc/MiningStation
        public static void GetProfit(ProfitTable profitTable, Shortcut currentlyMinedCoin, out ProfitTableRow maxCoinRow, out decimal maxProfit, out decimal currentProfit, out bool nothingChecked)
        {
            maxProfit      = 0;
            maxCoinRow     = null;
            nothingChecked = true;
            ProfitTableRow currentCoinRow = null;
            var            coinName       = currentlyMinedCoin?.GetName();

            foreach (var row in profitTable.ProfitList)
            {
                if (currentlyMinedCoin != null &&
                    row.Name == coinName &&
                    row.Path == currentlyMinedCoin?.Path &&
                    row.Arguments == currentlyMinedCoin?.Arguments)
                {
                    currentCoinRow = row;
                }
                if (row.Switchable)
                {
                    nothingChecked = false;
                }
                if (row.Switchable && row.ProfitDay > maxProfit)
                {
                    maxCoinRow = row;
                    maxProfit  = row.ProfitDay;
                }
            }
            currentProfit = 0;
            if (currentlyMinedCoin != null && currentCoinRow != null)
            {
                currentProfit = currentCoinRow.ProfitDay;
            }
        }
コード例 #2
0
        public async Task <SwitchResult> SwitchStandalone()
        {
            var streamServerAddress = BuildServerAddress(WtmSettings.ServerName, Constants.StreamServer);

            using (var logFile = new StreamWriter(Constants.SwitchLog, true))
            {
                if (new FileInfo(Constants.SwitchLog).Length > 0)
                {
                    logFile.WriteLine(string.Empty);
                }
                logFile.WriteLine(DateTime.Now);

                // Respect the DelayNextSwitchTime setting
                if (WtmSettings.DelayNextSwitchTime != 0)
                {
                    var    lastTime    = new DateTime();
                    var    lastTimeObj = GetRegistryKeyValue(Constants.SwitchRegistryKey, "LastSuccess");
                    string lastTimeStr = lastTimeObj as string;
                    if (lastTimeStr != null && lastTimeStr != string.Empty)
                    {
                        lastTime = Convert.ToDateTime(lastTimeStr, DateTimeFormatInfo.InvariantInfo).ToUniversalTime();
                        var now = DateTime.UtcNow;
                        var lastTimePlusDelay = lastTime.AddHours(WtmSettings.DelayNextSwitchTime);
                        if (now < lastTimePlusDelay)
                        {
                            logFile.WriteLine($"Because of the Delay option checked Auto Switch can proceed only after {lastTimePlusDelay.ToLocalTime()}.");
                            return(SwitchResult.DelayIsNotOver);
                        }
                    }
                }

                // Update Workers from server
                if (WtmSettings.ApplicationMode == "Client" && WtmSettings.UpdateWorkersFromServer)
                {
                    await UpdateWorkersFromServer(logFile);
                }

                //Find localhost name in Workers list (used in Standalone and Client modes )
                var    thisPcName = Environment.MachineName;
                Worker thisWorker = GetWorkerByPCName(thisPcName);
                if (thisWorker == null && WtmSettings.ApplicationMode != "Server")
                {
                    string msg = $"{thisPcName} was not found in any worker.";
                    logFile.WriteLine(msg);
                    return(SwitchResult.ThisPcIsNotListed);
                }

                // Get coin names from worker description
                var    coinList      = new List <string>();
                var    allCoinList   = new List <string>();
                var    workersList   = new List <Worker>();
                string noCoinChecked = string.Empty;
                if (thisWorker != null)
                {
                    noCoinChecked = $"No coin is checked as switchable in {thisWorker.Name}.";
                }
                else
                {
                    noCoinChecked = "No coin is checked as switchable.";
                }
                if (WtmSettings.ApplicationMode != "Server") // Standalone or Client mode - just the worker that contains localhost name
                {
                    workersList = new List <Worker> {
                        thisWorker
                    };
                }
                else // Server mode - all workers, all coins
                {
                    foreach (var w in Workers.WorkerList)
                    {
                        workersList.Add(w.Clone());
                    }
                    allCoinList = Workers.GetCoins(workersList, false, false);
                    if (allCoinList == null || allCoinList.Count == 0)
                    {
                        logFile.WriteLine(noCoinChecked);
                        return(SwitchResult.NothingToDo);
                    }
                    if (!allCoinList.Contains("Bitcoin"))
                    {
                        allCoinList.Add("Bitcoin");
                    }
                }
                coinList = Workers.GetCoins(workersList, false, true); // Only coins with Switch checked
                if (coinList == null || coinList.Count == 0)
                {
                    logFile.WriteLine(noCoinChecked);
                    return(SwitchResult.NothingToDo);
                }
                if (!coinList.Contains("Bitcoin"))
                {
                    coinList.Add("Bitcoin");
                }


                // Get WTM coins JSON data
                Dictionary <string, WtmData> wtmDataDict = new Dictionary <string, WtmData>();
                // Attempt to download data from local server
                HistoricalData localDataCopy = null;
                if (WtmSettings.ApplicationMode == "Client")
                {
                    var channel = Service.NewStreamChannel(streamServerAddress, TimeSpan.FromSeconds(60));
                    try
                    {
                        var response = await channel.GetWtmLocalDataAsync();

                        if (response != null)
                        {
                            var memoryStream = new MemoryStream();
                            await response.Stream.CopyToAsync(memoryStream);

                            localDataCopy = NetHelper.DeserializeFromStream <HistoricalData>(memoryStream);
                        }

                        if (localDataCopy == null)
                        {
                            throw new NullReferenceException("Local data from server are null.");
                        }
                    }
                    catch (Exception ex)
                    {
                        logFile.WriteLine($"Failed to download proxy data from local server {WtmSettings.ServerName}. " + ex.Message);
                        if (!WtmSettings.QueryWtmOnLocalServerFail)
                        {
                            return(SwitchResult.NoWtmData);
                        }
                    }
                    finally
                    {
                        NetHelper.CloseChannel(channel);
                    }

                    // Check if the received data are up to date
                    if (localDataCopy != null)
                    {
                        bool dataTimestampGood = EvaluateWtmDataTimeRange(localDataCopy.Date);
                        if (!dataTimestampGood && !WtmSettings.QueryWtmOnLocalServerFail)
                        {
                            logFile.WriteLine("The server cache data is expired."
                                              + " Make sure that AutoSwitch on the client launches later than on the server."
                                              + " For example, if AutoSwitch runs on a daily basis schedule AutoSwitch on the server to run at 9:00 and on the client machines at anyting between 10:00-23:59."
                                              + " This way the cache data obtained in the morning is valid for the rest of the day.");
                            return(SwitchResult.Terminate);
                        }
                        if (dataTimestampGood)
                        {
                            // Filter out coins downloded from server that are not checked for AutoSwitch locally
                            wtmDataDict = localDataCopy.PriceData.Where(x => coinList.Contains(x.Key)).ToDictionary(x => x.Key, x => x.Value);
                        }
                    }
                }
                // Download data from WhatToMine (Standalone or Server)
                if (wtmDataDict.Count == 0)
                {
                    StatusBarText = "Downloading coin definitions from whattomine.com...";
                    (Dictionary <string, WtmData> data, WhatToMine.GetWtmCoinDataResult result)wtmDataResult = (null, WhatToMine.GetWtmCoinDataResult.OK);
                    if (WtmSettings.ApplicationMode == "Server")
                    {
                        var allCoinHashList = GetHashrates(allCoinList);
                        wtmDataResult = await WhatToMine.GetWtmCoinData(allCoinHashList, false, logFile).ConfigureAwait(false);
                    }
                    else
                    {
                        var coinHashList = GetHashrates(coinList);
                        wtmDataResult = await WhatToMine.GetWtmCoinData(coinHashList, false, logFile).ConfigureAwait(false);
                    }
                    if (wtmDataResult.result == WhatToMine.GetWtmCoinDataResult.CoinNotFound)
                    {
                        return(SwitchResult.CoinNotFound);
                    }
                    wtmDataDict = wtmDataResult.data;
                    if (wtmDataDict == null)
                    {
                        return(SwitchResult.CoinNotFound);
                    }
                }

                // Update WTM coin data with historical averages from local database if opted to
                var  historicalDataList     = new List <HistoricalData>();
                bool historicalDataUpToDate = false;
                if (WtmSettings.UseHistoricalAverage)
                {
                    if (WtmSettings.ApplicationMode == "Client")
                    {
                        //Needs longer timeout for the server might be downloading all coins from whattomine.com
                        var channel = Service.NewStreamChannel(streamServerAddress, TimeSpan.FromSeconds(180));

                        try
                        {
                            var response = await channel.GetPriceHistoryAsync(new StreamDownloadRequest { Period = WtmSettings.HistoricalAveragePeriod }).ConfigureAwait(false);

                            if (response != null)
                            {
                                var memoryStream = new MemoryStream();
                                await response.Stream.CopyToAsync(memoryStream);

                                historicalDataList     = NetHelper.DeserializeFromStream <List <HistoricalData> >(memoryStream);
                                historicalDataUpToDate = true;
                            }
                        }
                        catch (Exception ex)
                        {
                            logFile.WriteLine($"Failed to obtain historical prices from local server {WtmSettings.ServerName}. " + ex.Message);
                            return(SwitchResult.Error);
                        }
                        finally
                        {
                            NetHelper.CloseChannel(channel);
                        }
                    }
                    else
                    {
                        var result = await UpdatePriceHistory();

                        if (result == UpdatePriceHistoryResult.Success || result == UpdatePriceHistoryResult.AlreadyUpToDate)
                        {
                            historicalDataList     = ReadHistoricalData(WtmSettings.HistoricalAveragePeriod);
                            historicalDataUpToDate = true;
                        }
                    }
                    // Calculate historical prices for wtmDataList
                    if (historicalDataUpToDate)
                    {
                        GetHistoricalAverages(wtmDataDict, historicalDataList);
                    }
                }

                // Update WtmLocalData if in server mode
                if (WtmSettings.ApplicationMode == "Server")
                {
                    if (wtmDataDict != null && wtmDataDict.Count != 0)
                    {
                        using (var db = new LiteDatabase(Constants.DataBase))
                        {
                            var collection = db.GetCollection <HistoricalData>(Constants.LightDB_WtmCacheCollection);
                            collection.Delete(LiteDB.Query.All());
                            collection.Insert(new HistoricalData(DateTime.Now, wtmDataDict));
                        }
                    }
                }

                // Abandon if in server mode and DontSwitchServer is checked
                if (WtmSettings.ApplicationMode == "Server" && WtmSettings.DontSwitchServer)
                {
                    return(SwitchResult.NoNeedToSwitch);
                }
                if (WtmSettings.ApplicationMode == "Server" && !WtmSettings.DontSwitchServer && thisWorker == null)
                {
                    logFile.WriteLine("The server cannot switch because it is not listed in any worker table.");
                    return(SwitchResult.ThisPcIsNotListed);
                }

                // Calculate profit table for this PC and analize it
                var            profitTables = WhatToMine.CreateProfitTables(wtmDataDict, workersList, (decimal)Workers.PowerCost, WtmSettings, true);
                var            profitTable = profitTables.First();
                var            currentCoinShortcut = Shortcut.GetCurrentCoin(); // Get current coin from Startup folder .lnk
                ProfitTableRow maxCoinRow = null; decimal maxProfit = 0; decimal currentProfit = 0;
                bool           nothingChecked = false;
                WhatToMine.GetProfit(profitTable, currentCoinShortcut, out maxCoinRow, out maxProfit, out currentProfit, out nothingChecked);
                if (nothingChecked)
                {
                    string msg = "Nothing to do. Make sure there are actual switchable coins defined in worker.";
                    logFile.WriteLine(msg);
                    return(SwitchResult.NothingToDo);
                }
                if (maxProfit == 0)
                {
                    string msg = $"There is no coin with profit above 0 for {thisPcName}.";
                    logFile.WriteLine(msg);
                    return(SwitchResult.NothingToDo);
                }

                //Check profitability and price margin
                bool currentCoinMatch             = currentCoinShortcut?.GetName() == maxCoinRow.Name;
                bool currentCoinPathMatch         = currentCoinShortcut?.Path == maxCoinRow.Path;
                bool currentPforitIsHigherOrEqual = maxProfit <= currentProfit;
                bool currentProfitIsWithinMargin  = false;
                if (WtmSettings.PriceMargin > 0)
                {
                    currentProfitIsWithinMargin = maxProfit <= (currentProfit + (currentProfit * WtmSettings.PriceMargin / 100));
                }

                if (currentPforitIsHigherOrEqual)
                {
                    string msg;
                    msg = $"No need to switch. {thisPcName} is already set to mine the most profitable coin {currentCoinShortcut?.GetNameAndSymbol()}.";
                    logFile.WriteLine(msg);
                    return(SwitchResult.NoNeedToSwitch);
                }
                if (currentProfitIsWithinMargin)
                {
                    string msg;
                    if (currentCoinMatch && !currentCoinPathMatch)
                    {
                        msg = $"No need to switch. {thisPcName} is set to mine {currentCoinShortcut?.GetNameAndSymbol()} started by \"{currentCoinShortcut?.Path}\". It is less profitable than {maxCoinRow.NameAndSymbol} started by \"{maxCoinRow.Path}\" but the difference is within price margin.";
                    }
                    else
                    {
                        msg = $"No need to switch. {thisPcName} is set to mine {currentCoinShortcut?.GetNameAndSymbol()}. It is less profitable than {maxCoinRow.NameAndSymbol} but the difference is within price margin.";
                    }
                    logFile.WriteLine(msg);
                    return(SwitchResult.NoNeedToSwitch);
                }

                // Check if executable path exists
                if (!File.Exists(maxCoinRow.Path))
                {
                    logFile.WriteLine($"{maxCoinRow.Path} - file does not exist on {thisPcName}.");
                    return(SwitchResult.CoinNotFound);
                }

                bool startOk = false; // Start miner process flag
                try
                {
                    Shortcut.CreateCoinShortcut(maxCoinRow.Name, maxCoinRow.Symbol, maxCoinRow.Algorithm, maxCoinRow.Path, maxCoinRow.Arguments);
                    if (WtmSettings.RestartComputer)
                    {
                        RestartComputerPending = true;
                    }
                    if (WtmSettings.RestartMiner)
                    {
                        // Kill processes from KillList
                        var killResponse = KillProcesses(WtmSettings.KillList);
                        if (!killResponse.success && killResponse.failList != null)
                        {
                            string errorMessage = $"Startup shortcut to mine {maxCoinRow.NameAndSymbol} has been created but some processes could not be killed:";
                            logFile.WriteLine(errorMessage);
                            foreach (var entry in killResponse.failList)
                            {
                                if (entry != string.Empty)
                                {
                                    logFile.WriteLine(entry);
                                }
                            }
                            logFile.WriteLine($"{Environment.MachineName} will restart.");
                            RestartComputerPending = true;
                            SetRegistryKeyValue(Constants.SwitchRegistryKey, "LastSuccess", DateTime.UtcNow.ToString("o"));
                            return(SwitchResult.SwitchedSuccessfully);
                        }

                        if (!System.IO.File.Exists(maxCoinRow.Path))
                        {
                            logFile.WriteLine($"ERROR: File not found. {maxCoinRow.Path}");
                            return(SwitchResult.Error);
                        }

                        // Start miner process
                        var     startInfo = new ProcessStartInfo(maxCoinRow.Path, maxCoinRow.Arguments);
                        Process process   = new Process();
                        process.StartInfo = startInfo;
                        startOk           = process.Start();
                        if (!startOk)
                        {
                            throw new Exception($"\"{Path.GetFileName(maxCoinRow.Path)}\" failed to start.");
                        }
                    }
                    SetRegistryKeyValue(Constants.SwitchRegistryKey, "LastSuccess", DateTime.UtcNow.ToString("o"));
                    logFile.WriteLine($"Switched to {maxCoinRow.NameAndSymbol} successfully.");
                    return(SwitchResult.SwitchedSuccessfully);
                }
                catch (Exception ex)
                {
                    logFile.WriteLine($"Failed to switch to {maxCoinRow.NameAndSymbol}: {ex.Message}");
                    if (WtmSettings.RestartMiner && !startOk)
                    {
                        RestartComputerPending = true;
                        logFile.WriteLine($"{Environment.MachineName} will restart.");
                    }
                    return(SwitchResult.Error);
                }
            }
        }
コード例 #3
0
ファイル: WhatToMine.cs プロジェクト: xeddmc/MiningStation
        public static List <ProfitTable> CreateProfitTables(Dictionary <string, WtmData> wtmDataDict, List <Worker> workerList, decimal powerCost, WtmSettingsObject settings, bool switchableOnly = false)
        {
            var btc          = wtmDataDict["Bitcoin"];
            var profitList   = new List <ProfitTableRow>();
            var profitTables = new List <ProfitTable>();

            int j = 1; var workerCount = workerList.Count;

            foreach (var worker in workerList)
            {
                foreach (var entry in worker.CoinList)
                {
                    if (switchableOnly && !entry.Switch)
                    {
                        continue;
                    }
                    var     profitResult    = CalculateProfit(entry, wtmDataDict, btc, settings, powerCost);
                    decimal profit24        = profitResult.profit24;
                    decimal revenueAllCoins = profitResult.revenue;
                    bool    multicell       = (entry.Coins.Count > 1);
                    var     newRow          = new ProfitTableRow
                    {
                        Name        = entry.FullName,
                        Symbol      = entry.FullSymbol,
                        Algorithm   = entry.FullAlgorithm,
                        Hashrate    = entry.FullHashrate,
                        Multicell   = multicell,
                        Switchable  = entry.Switch,
                        Revenue     = revenueAllCoins,
                        ProfitDay   = profit24,
                        ProfitWeek  = profit24 * 7,
                        ProfitMonth = profit24 * 30,
                        ProfitYear  = profit24 * 365,
                        Path        = entry.Path ?? string.Empty,
                        Arguments   = entry.Arguments ?? string.Empty,
                        Notes       = entry.Notes,
                    };
                    profitList.Add(newRow);

                    newRow = null;
                }
                var newProfitTable = new ProfitTable
                {
                    Name      = worker.Name,
                    Index     = j,
                    ThisPC    = Helpers.ListContainsThisPC(worker.Computers),
                    Computers = new ObservableCollection <Computer>(worker?.Computers.Select(computer => new Computer {
                        Name = computer
                    })),
                    Description = worker.Description,
                    ProfitList  = profitList.OrderByDescending(p => p.ProfitDay).ToList()
                };

                var firstCoin = newProfitTable.ProfitList.FirstOrDefault();
                if (firstCoin != null)
                {
                    firstCoin.ManualSwitch = true;
                }

                //Show the topmost coin as the new coin in Computers list
                newProfitTable.HookPropertyChanched();
                newProfitTable.Row_PropertyChanged(newProfitTable.ProfitList.FirstOrDefault(), new PropertyChangedEventArgs("ManualSwitch"));

                profitTables.Add(newProfitTable);
                profitList.Clear();
                j++;
            }
            return(profitTables);
        }