public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { bool thisPc = (bool)value; if (thisPc) { string coin = null; try { coin = Shortcut.GetCurrentCoin().GetNameAndSymbol(); if (string.IsNullOrEmpty(coin)) { return(string.Empty); } } catch { return(string.Empty); } List <Inline> inlines = new List <Inline>(); inlines.Add(new Run { Text = ", " }); inlines.Add(new Run { Text = Environment.MachineName, FontWeight = FontWeights.SemiBold, Foreground = Brushes.Blue }); inlines.Add(new Run { Text = $" is mining {coin}" }); return(inlines); } else { return(string.Empty); } }
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); } } }