Refactoring for upcoming GUI app

This commit is contained in:
JustArchi
2016-08-02 06:04:44 +02:00
parent 9918861c66
commit 7025659151
13 changed files with 311 additions and 274 deletions

213
ArchiSteamFarm/ASF.cs Normal file
View File

@@ -0,0 +1,213 @@
/*
_ _ _ ____ _ _____
/ \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
/ _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
/ ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
/_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
Copyright 2015-2016 Łukasz "JustArchi" Domeradzki
Contact: JustArchi@JustArchi.net
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using ArchiSteamFarm.JSON;
using Newtonsoft.Json;
namespace ArchiSteamFarm {
internal static class ASF {
private static Timer AutoUpdatesTimer;
internal static async Task CheckForUpdate(bool updateOverride = false) {
string exeFile = Assembly.GetEntryAssembly().Location;
string oldExeFile = exeFile + ".old";
// We booted successfully so we can now remove old exe file
if (File.Exists(oldExeFile)) {
// It's entirely possible that old process is still running, allow at least a second before trying to remove the file
await Task.Delay(1000).ConfigureAwait(false);
try {
File.Delete(oldExeFile);
} catch (Exception e) {
Logging.LogGenericException(e);
Logging.LogGenericError("Could not remove old ASF binary, please remove " + oldExeFile + " manually in order for update function to work!");
}
}
if (Program.GlobalConfig.UpdateChannel == GlobalConfig.EUpdateChannel.Unknown) {
return;
}
if ((AutoUpdatesTimer == null) && Program.GlobalConfig.AutoUpdates) {
AutoUpdatesTimer = new Timer(
async e => await CheckForUpdate().ConfigureAwait(false),
null,
TimeSpan.FromDays(1), // Delay
TimeSpan.FromDays(1) // Period
);
Logging.LogGenericInfo("ASF will automatically check for new versions every 24 hours");
}
string releaseURL = SharedInfo.GithubReleaseURL;
if (Program.GlobalConfig.UpdateChannel == GlobalConfig.EUpdateChannel.Stable) {
releaseURL += "/latest";
}
Logging.LogGenericInfo("Checking new version...");
string response = await Program.WebBrowser.UrlGetToContentRetry(releaseURL).ConfigureAwait(false);
if (string.IsNullOrEmpty(response)) {
Logging.LogGenericWarning("Could not check latest version!");
return;
}
GitHub.ReleaseResponse releaseResponse;
if (Program.GlobalConfig.UpdateChannel == GlobalConfig.EUpdateChannel.Stable) {
try {
releaseResponse = JsonConvert.DeserializeObject<GitHub.ReleaseResponse>(response);
} catch (JsonException e) {
Logging.LogGenericException(e);
return;
}
} else {
List<GitHub.ReleaseResponse> releases;
try {
releases = JsonConvert.DeserializeObject<List<GitHub.ReleaseResponse>>(response);
} catch (JsonException e) {
Logging.LogGenericException(e);
return;
}
if ((releases == null) || (releases.Count == 0)) {
Logging.LogGenericWarning("Could not check latest version!");
return;
}
releaseResponse = releases[0];
}
if (string.IsNullOrEmpty(releaseResponse.Tag)) {
Logging.LogGenericWarning("Could not check latest version!");
return;
}
Version newVersion = new Version(releaseResponse.Tag);
Logging.LogGenericInfo("Local version: " + SharedInfo.Version + " | Remote version: " + newVersion);
if (SharedInfo.Version.CompareTo(newVersion) >= 0) { // If local version is the same or newer than remote version
return;
}
if (!updateOverride && !Program.GlobalConfig.AutoUpdates) {
Logging.LogGenericInfo("New version is available!");
Logging.LogGenericInfo("Consider updating yourself!");
await Task.Delay(5000).ConfigureAwait(false);
return;
}
if (File.Exists(oldExeFile)) {
Logging.LogGenericWarning("Refusing to proceed with auto update as old " + oldExeFile + " binary could not be removed, please remove it manually");
return;
}
// Auto update logic starts here
if (releaseResponse.Assets == null) {
Logging.LogGenericWarning("Could not proceed with update because that version doesn't include assets!");
return;
}
string exeFileName = Path.GetFileName(exeFile);
GitHub.ReleaseResponse.Asset binaryAsset = releaseResponse.Assets.FirstOrDefault(asset => !string.IsNullOrEmpty(asset.Name) && asset.Name.Equals(exeFileName, StringComparison.OrdinalIgnoreCase));
if (binaryAsset == null) {
Logging.LogGenericWarning("Could not proceed with update because there is no asset that relates to currently running binary!");
return;
}
if (string.IsNullOrEmpty(binaryAsset.DownloadURL)) {
Logging.LogGenericWarning("Could not proceed with update because download URL is empty!");
return;
}
Logging.LogGenericInfo("Downloading new version...");
Logging.LogGenericInfo("While waiting, consider donating if you appreciate the work being done :)");
byte[] result = await Program.WebBrowser.UrlGetToBytesRetry(binaryAsset.DownloadURL).ConfigureAwait(false);
if (result == null) {
return;
}
string newExeFile = exeFile + ".new";
// Firstly we create new exec
try {
File.WriteAllBytes(newExeFile, result);
} catch (Exception e) {
Logging.LogGenericException(e);
return;
}
// Now we move current -> old
try {
File.Move(exeFile, oldExeFile);
} catch (Exception e) {
Logging.LogGenericException(e);
try {
// Cleanup
File.Delete(newExeFile);
} catch {
// Ignored
}
return;
}
// Now we move new -> current
try {
File.Move(newExeFile, exeFile);
} catch (Exception e) {
Logging.LogGenericException(e);
try {
// Cleanup
File.Move(oldExeFile, exeFile);
File.Delete(newExeFile);
} catch {
// Ignored
}
return;
}
Logging.LogGenericInfo("Update process finished!");
if (Program.GlobalConfig.AutoRestart) {
Logging.LogGenericInfo("Restarting...");
await Task.Delay(5000).ConfigureAwait(false);
Program.Restart();
} else {
Logging.LogGenericInfo("Exiting...");
await Task.Delay(5000).ConfigureAwait(false);
Program.Exit();
}
}
}
}

View File

@@ -115,6 +115,7 @@
<Compile Include="ArchiServiceInstaller.cs"> <Compile Include="ArchiServiceInstaller.cs">
<SubType>Component</SubType> <SubType>Component</SubType>
</Compile> </Compile>
<Compile Include="ASF.cs" />
<Compile Include="Bot.cs" /> <Compile Include="Bot.cs" />
<Compile Include="BotConfig.cs" /> <Compile Include="BotConfig.cs" />
<Compile Include="ConcurrentEnumerator.cs" /> <Compile Include="ConcurrentEnumerator.cs" />

View File

@@ -145,7 +145,7 @@ namespace ArchiSteamFarm {
throw new Exception("That bot is already defined!"); throw new Exception("That bot is already defined!");
} }
string botPath = Path.Combine(Program.ConfigDirectory, botName); string botPath = Path.Combine(SharedInfo.ConfigDirectory, botName);
BotName = botName; BotName = botName;
SentryFile = botPath + ".bin"; SentryFile = botPath + ".bin";
@@ -184,10 +184,10 @@ namespace ArchiSteamFarm {
// Initialize // Initialize
SteamClient = new SteamClient(Program.GlobalConfig.SteamProtocol); SteamClient = new SteamClient(Program.GlobalConfig.SteamProtocol);
if (Program.GlobalConfig.Debug && !Debugging.NetHookAlreadyInitialized && Directory.Exists(Program.DebugDirectory)) { if (Program.GlobalConfig.Debug && !Debugging.NetHookAlreadyInitialized && Directory.Exists(SharedInfo.DebugDirectory)) {
try { try {
Debugging.NetHookAlreadyInitialized = true; Debugging.NetHookAlreadyInitialized = true;
SteamClient.DebugNetworkListener = new NetHookNetworkListener(Program.DebugDirectory); SteamClient.DebugNetworkListener = new NetHookNetworkListener(SharedInfo.DebugDirectory);
} catch (Exception e) { } catch (Exception e) {
Logging.LogGenericException(e, botName); Logging.LogGenericException(e, botName);
} }
@@ -533,7 +533,7 @@ namespace ArchiSteamFarm {
if (!BotDatabase.MobileAuthenticator.HasCorrectDeviceID) { if (!BotDatabase.MobileAuthenticator.HasCorrectDeviceID) {
Logging.LogGenericWarning("Your DeviceID is incorrect or doesn't exist", BotName); Logging.LogGenericWarning("Your DeviceID is incorrect or doesn't exist", BotName);
string deviceID = Program.GetUserInput(Program.EUserInputType.DeviceID, BotName); string deviceID = Program.GetUserInput(SharedInfo.EUserInputType.DeviceID, BotName);
if (string.IsNullOrEmpty(deviceID)) { if (string.IsNullOrEmpty(deviceID)) {
BotDatabase.MobileAuthenticator = null; BotDatabase.MobileAuthenticator = null;
return; return;
@@ -1383,7 +1383,7 @@ namespace ArchiSteamFarm {
return null; return null;
} }
await Program.CheckForUpdate(true).ConfigureAwait(false); await ASF.CheckForUpdate(true).ConfigureAwait(false);
return "Done!"; return "Done!";
} }
@@ -1397,7 +1397,7 @@ namespace ArchiSteamFarm {
return null; return null;
} }
return "ASF V" + Program.Version; return "ASF V" + SharedInfo.Version;
} }
private void HandleCallbacks() { private void HandleCallbacks() {
@@ -1480,7 +1480,7 @@ namespace ArchiSteamFarm {
private bool InitializeLoginAndPassword(bool requiresPassword) { private bool InitializeLoginAndPassword(bool requiresPassword) {
if (string.IsNullOrEmpty(BotConfig.SteamLogin)) { if (string.IsNullOrEmpty(BotConfig.SteamLogin)) {
BotConfig.SteamLogin = Program.GetUserInput(Program.EUserInputType.Login, BotName); BotConfig.SteamLogin = Program.GetUserInput(SharedInfo.EUserInputType.Login, BotName);
if (string.IsNullOrEmpty(BotConfig.SteamLogin)) { if (string.IsNullOrEmpty(BotConfig.SteamLogin)) {
return false; return false;
} }
@@ -1490,7 +1490,7 @@ namespace ArchiSteamFarm {
return true; return true;
} }
BotConfig.SteamPassword = Program.GetUserInput(Program.EUserInputType.Password, BotName); BotConfig.SteamPassword = Program.GetUserInput(SharedInfo.EUserInputType.Password, BotName);
return !string.IsNullOrEmpty(BotConfig.SteamPassword); return !string.IsNullOrEmpty(BotConfig.SteamPassword);
} }
@@ -1810,7 +1810,7 @@ namespace ArchiSteamFarm {
switch (callback.Result) { switch (callback.Result) {
case EResult.AccountLogonDenied: case EResult.AccountLogonDenied:
AuthCode = Program.GetUserInput(Program.EUserInputType.SteamGuard, BotName); AuthCode = Program.GetUserInput(SharedInfo.EUserInputType.SteamGuard, BotName);
if (string.IsNullOrEmpty(AuthCode)) { if (string.IsNullOrEmpty(AuthCode)) {
Stop(); Stop();
} }
@@ -1818,7 +1818,7 @@ namespace ArchiSteamFarm {
break; break;
case EResult.AccountLoginDeniedNeedTwoFactor: case EResult.AccountLoginDeniedNeedTwoFactor:
if (BotDatabase.MobileAuthenticator == null) { if (BotDatabase.MobileAuthenticator == null) {
TwoFactorCode = Program.GetUserInput(Program.EUserInputType.TwoFactorAuthentication, BotName); TwoFactorCode = Program.GetUserInput(SharedInfo.EUserInputType.TwoFactorAuthentication, BotName);
if (string.IsNullOrEmpty(TwoFactorCode)) { if (string.IsNullOrEmpty(TwoFactorCode)) {
Stop(); Stop();
} }
@@ -1842,14 +1842,14 @@ namespace ArchiSteamFarm {
if (BotDatabase.MobileAuthenticator == null) { if (BotDatabase.MobileAuthenticator == null) {
// Support and convert SDA files // Support and convert SDA files
string maFilePath = Path.Combine(Program.ConfigDirectory, callback.ClientSteamID.ConvertToUInt64() + ".maFile"); string maFilePath = Path.Combine(SharedInfo.ConfigDirectory, callback.ClientSteamID.ConvertToUInt64() + ".maFile");
if (File.Exists(maFilePath)) { if (File.Exists(maFilePath)) {
ImportAuthenticator(maFilePath); ImportAuthenticator(maFilePath);
} }
} }
if (string.IsNullOrEmpty(BotConfig.SteamParentalPIN)) { if (string.IsNullOrEmpty(BotConfig.SteamParentalPIN)) {
BotConfig.SteamParentalPIN = Program.GetUserInput(Program.EUserInputType.SteamParentalPIN, BotName); BotConfig.SteamParentalPIN = Program.GetUserInput(SharedInfo.EUserInputType.SteamParentalPIN, BotName);
if (string.IsNullOrEmpty(BotConfig.SteamParentalPIN)) { if (string.IsNullOrEmpty(BotConfig.SteamParentalPIN)) {
Stop(); Stop();
return; return;

View File

@@ -82,7 +82,7 @@ namespace ArchiSteamFarm {
} else { } else {
FileTarget fileTarget = new FileTarget("File") { FileTarget fileTarget = new FileTarget("File") {
DeleteOldFileOnStartup = true, DeleteOldFileOnStartup = true,
FileName = Program.LogFile, FileName = SharedInfo.LogFile,
Layout = GeneralLayout Layout = GeneralLayout
}; };
@@ -122,7 +122,7 @@ namespace ArchiSteamFarm {
LogManager.ReconfigExistingLoggers(); LogManager.ReconfigExistingLoggers();
} }
internal static void LogGenericError(string message, string botName = Program.ASF, [CallerMemberName] string previousMethodName = null) { internal static void LogGenericError(string message, string botName = SharedInfo.ASF, [CallerMemberName] string previousMethodName = null) {
if (string.IsNullOrEmpty(message)) { if (string.IsNullOrEmpty(message)) {
LogNullError(nameof(message), botName); LogNullError(nameof(message), botName);
return; return;
@@ -131,7 +131,7 @@ namespace ArchiSteamFarm {
Logger.Error($"{botName}|{previousMethodName}() {message}"); Logger.Error($"{botName}|{previousMethodName}() {message}");
} }
internal static void LogGenericException(Exception exception, string botName = Program.ASF, [CallerMemberName] string previousMethodName = null) { internal static void LogGenericException(Exception exception, string botName = SharedInfo.ASF, [CallerMemberName] string previousMethodName = null) {
if (exception == null) { if (exception == null) {
LogNullError(nameof(exception), botName); LogNullError(nameof(exception), botName);
return; return;
@@ -140,7 +140,7 @@ namespace ArchiSteamFarm {
Logger.Error(exception, $"{botName}|{previousMethodName}()"); Logger.Error(exception, $"{botName}|{previousMethodName}()");
} }
internal static void LogFatalException(Exception exception, string botName = Program.ASF, [CallerMemberName] string previousMethodName = null) { internal static void LogFatalException(Exception exception, string botName = SharedInfo.ASF, [CallerMemberName] string previousMethodName = null) {
if (exception == null) { if (exception == null) {
LogNullError(nameof(exception), botName); LogNullError(nameof(exception), botName);
return; return;
@@ -154,10 +154,10 @@ namespace ArchiSteamFarm {
} }
// Otherwise, if we run into fatal exception before logging module is even initialized, write exception to classic log file // Otherwise, if we run into fatal exception before logging module is even initialized, write exception to classic log file
File.WriteAllText(Program.LogFile, DateTime.Now + " ASF V" + Program.Version + " has run into fatal exception before core logging module was even able to initialize!" + Environment.NewLine); File.WriteAllText(SharedInfo.LogFile, DateTime.Now + " ASF V" + SharedInfo.Version + " has run into fatal exception before core logging module was even able to initialize!" + Environment.NewLine);
while (true) { while (true) {
File.AppendAllText(Program.LogFile, "[!] EXCEPTION: " + previousMethodName + "() " + exception.Message + Environment.NewLine + "StackTrace:" + Environment.NewLine + exception.StackTrace); File.AppendAllText(SharedInfo.LogFile, "[!] EXCEPTION: " + previousMethodName + "() " + exception.Message + Environment.NewLine + "StackTrace:" + Environment.NewLine + exception.StackTrace);
if (exception.InnerException != null) { if (exception.InnerException != null) {
exception = exception.InnerException; exception = exception.InnerException;
continue; continue;
@@ -167,7 +167,7 @@ namespace ArchiSteamFarm {
} }
} }
internal static void LogGenericWarning(string message, string botName = Program.ASF, [CallerMemberName] string previousMethodName = null) { internal static void LogGenericWarning(string message, string botName = SharedInfo.ASF, [CallerMemberName] string previousMethodName = null) {
if (string.IsNullOrEmpty(message)) { if (string.IsNullOrEmpty(message)) {
LogNullError(nameof(message), botName); LogNullError(nameof(message), botName);
return; return;
@@ -176,7 +176,7 @@ namespace ArchiSteamFarm {
Logger.Warn($"{botName}|{previousMethodName}() {message}"); Logger.Warn($"{botName}|{previousMethodName}() {message}");
} }
internal static void LogGenericInfo(string message, string botName = Program.ASF, [CallerMemberName] string previousMethodName = null) { internal static void LogGenericInfo(string message, string botName = SharedInfo.ASF, [CallerMemberName] string previousMethodName = null) {
if (string.IsNullOrEmpty(message)) { if (string.IsNullOrEmpty(message)) {
LogNullError(nameof(message), botName); LogNullError(nameof(message), botName);
return; return;
@@ -186,7 +186,7 @@ namespace ArchiSteamFarm {
} }
[SuppressMessage("ReSharper", "ExplicitCallerInfoArgument")] [SuppressMessage("ReSharper", "ExplicitCallerInfoArgument")]
internal static void LogNullError(string nullObjectName, string botName = Program.ASF, [CallerMemberName] string previousMethodName = null) { internal static void LogNullError(string nullObjectName, string botName = SharedInfo.ASF, [CallerMemberName] string previousMethodName = null) {
if (string.IsNullOrEmpty(nullObjectName)) { if (string.IsNullOrEmpty(nullObjectName)) {
return; return;
} }
@@ -196,7 +196,7 @@ namespace ArchiSteamFarm {
[Conditional("DEBUG")] [Conditional("DEBUG")]
[SuppressMessage("ReSharper", "UnusedMember.Global")] [SuppressMessage("ReSharper", "UnusedMember.Global")]
internal static void LogGenericDebug(string message, string botName = Program.ASF, [CallerMemberName] string previousMethodName = null) { internal static void LogGenericDebug(string message, string botName = SharedInfo.ASF, [CallerMemberName] string previousMethodName = null) {
if (string.IsNullOrEmpty(message)) { if (string.IsNullOrEmpty(message)) {
LogNullError(nameof(message), botName); LogNullError(nameof(message), botName);
return; return;

View File

@@ -22,7 +22,6 @@
*/ */
using Newtonsoft.Json;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
@@ -33,24 +32,9 @@ using System.Reflection;
using System.ServiceProcess; using System.ServiceProcess;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using ArchiSteamFarm.JSON;
namespace ArchiSteamFarm { namespace ArchiSteamFarm {
internal static class Program { internal static class Program {
internal enum EUserInputType : byte {
Unknown,
DeviceID,
Login,
Password,
PhoneNumber,
SMS,
SteamGuard,
SteamParentalPIN,
RevocationCode,
TwoFactorAuthentication,
WCFHostname
}
private enum EMode : byte { private enum EMode : byte {
[SuppressMessage("ReSharper", "UnusedMember.Local")] [SuppressMessage("ReSharper", "UnusedMember.Local")]
Unknown, Unknown,
@@ -59,17 +43,6 @@ namespace ArchiSteamFarm {
Server // Normal + WCF server Server // Normal + WCF server
} }
internal const string ASF = "ASF";
internal const string ConfigDirectory = "config";
internal const string DebugDirectory = "debug";
internal const string LogFile = "log.txt";
private const string GithubReleaseURL = "https://api.github.com/repos/" + SharedInfo.GithubRepo + "/releases"; // GitHub API is HTTPS only
private const string GlobalConfigFileName = ASF + ".json";
private const string GlobalDatabaseFileName = ASF + ".db";
internal static readonly Version Version = Assembly.GetEntryAssembly().GetName().Version;
private static readonly object ConsoleLock = new object(); private static readonly object ConsoleLock = new object();
private static readonly ManualResetEventSlim ShutdownResetEvent = new ManualResetEventSlim(false); private static readonly ManualResetEventSlim ShutdownResetEvent = new ManualResetEventSlim(false);
private static readonly WCF WCF = new WCF(); private static readonly WCF WCF = new WCF();
@@ -77,185 +50,10 @@ namespace ArchiSteamFarm {
internal static bool IsRunningAsService { get; private set; } internal static bool IsRunningAsService { get; private set; }
internal static GlobalConfig GlobalConfig { get; private set; } internal static GlobalConfig GlobalConfig { get; private set; }
internal static GlobalDatabase GlobalDatabase { get; private set; } internal static GlobalDatabase GlobalDatabase { get; private set; }
internal static WebBrowser WebBrowser { get; private set; }
private static bool ShutdownSequenceInitialized; private static bool ShutdownSequenceInitialized;
private static Timer AutoUpdatesTimer;
private static EMode Mode = EMode.Normal; private static EMode Mode = EMode.Normal;
private static WebBrowser WebBrowser;
internal static async Task CheckForUpdate(bool updateOverride = false) {
string exeFile = Assembly.GetEntryAssembly().Location;
string oldExeFile = exeFile + ".old";
// We booted successfully so we can now remove old exe file
if (File.Exists(oldExeFile)) {
// It's entirely possible that old process is still running, allow at least a second before trying to remove the file
await Task.Delay(1000).ConfigureAwait(false);
try {
File.Delete(oldExeFile);
} catch (Exception e) {
Logging.LogGenericException(e);
Logging.LogGenericError("Could not remove old ASF binary, please remove " + oldExeFile + " manually in order for update function to work!");
}
}
if (GlobalConfig.UpdateChannel == GlobalConfig.EUpdateChannel.Unknown) {
return;
}
if ((AutoUpdatesTimer == null) && GlobalConfig.AutoUpdates) {
AutoUpdatesTimer = new Timer(
async e => await CheckForUpdate().ConfigureAwait(false),
null,
TimeSpan.FromDays(1), // Delay
TimeSpan.FromDays(1) // Period
);
Logging.LogGenericInfo("ASF will automatically check for new versions every 24 hours");
}
string releaseURL = GithubReleaseURL;
if (GlobalConfig.UpdateChannel == GlobalConfig.EUpdateChannel.Stable) {
releaseURL += "/latest";
}
Logging.LogGenericInfo("Checking new version...");
string response = await WebBrowser.UrlGetToContentRetry(releaseURL).ConfigureAwait(false);
if (string.IsNullOrEmpty(response)) {
Logging.LogGenericWarning("Could not check latest version!");
return;
}
GitHub.ReleaseResponse releaseResponse;
if (GlobalConfig.UpdateChannel == GlobalConfig.EUpdateChannel.Stable) {
try {
releaseResponse = JsonConvert.DeserializeObject<GitHub.ReleaseResponse>(response);
} catch (JsonException e) {
Logging.LogGenericException(e);
return;
}
} else {
List<GitHub.ReleaseResponse> releases;
try {
releases = JsonConvert.DeserializeObject<List<GitHub.ReleaseResponse>>(response);
} catch (JsonException e) {
Logging.LogGenericException(e);
return;
}
if ((releases == null) || (releases.Count == 0)) {
Logging.LogGenericWarning("Could not check latest version!");
return;
}
releaseResponse = releases[0];
}
if (string.IsNullOrEmpty(releaseResponse.Tag)) {
Logging.LogGenericWarning("Could not check latest version!");
return;
}
Version newVersion = new Version(releaseResponse.Tag);
Logging.LogGenericInfo("Local version: " + Version + " | Remote version: " + newVersion);
if (Version.CompareTo(newVersion) >= 0) { // If local version is the same or newer than remote version
return;
}
if (!updateOverride && !GlobalConfig.AutoUpdates) {
Logging.LogGenericInfo("New version is available!");
Logging.LogGenericInfo("Consider updating yourself!");
await Task.Delay(5000).ConfigureAwait(false);
return;
}
if (File.Exists(oldExeFile)) {
Logging.LogGenericWarning("Refusing to proceed with auto update as old " + oldExeFile + " binary could not be removed, please remove it manually");
return;
}
// Auto update logic starts here
if (releaseResponse.Assets == null) {
Logging.LogGenericWarning("Could not proceed with update because that version doesn't include assets!");
return;
}
string exeFileName = Path.GetFileName(exeFile);
GitHub.ReleaseResponse.Asset binaryAsset = releaseResponse.Assets.FirstOrDefault(asset => !string.IsNullOrEmpty(asset.Name) && asset.Name.Equals(exeFileName, StringComparison.OrdinalIgnoreCase));
if (binaryAsset == null) {
Logging.LogGenericWarning("Could not proceed with update because there is no asset that relates to currently running binary!");
return;
}
if (string.IsNullOrEmpty(binaryAsset.DownloadURL)) {
Logging.LogGenericWarning("Could not proceed with update because download URL is empty!");
return;
}
Logging.LogGenericInfo("Downloading new version...");
Logging.LogGenericInfo("While waiting, consider donating if you appreciate the work being done :)");
byte[] result = await WebBrowser.UrlGetToBytesRetry(binaryAsset.DownloadURL).ConfigureAwait(false);
if (result == null) {
return;
}
string newExeFile = exeFile + ".new";
// Firstly we create new exec
try {
File.WriteAllBytes(newExeFile, result);
} catch (Exception e) {
Logging.LogGenericException(e);
return;
}
// Now we move current -> old
try {
File.Move(exeFile, oldExeFile);
} catch (Exception e) {
Logging.LogGenericException(e);
try {
// Cleanup
File.Delete(newExeFile);
} catch {
// Ignored
}
return;
}
// Now we move new -> current
try {
File.Move(newExeFile, exeFile);
} catch (Exception e) {
Logging.LogGenericException(e);
try {
// Cleanup
File.Move(oldExeFile, exeFile);
File.Delete(newExeFile);
} catch {
// Ignored
}
return;
}
Logging.LogGenericInfo("Update process finished!");
if (GlobalConfig.AutoRestart) {
Logging.LogGenericInfo("Restarting...");
await Task.Delay(5000).ConfigureAwait(false);
Restart();
} else {
Logging.LogGenericInfo("Exiting...");
await Task.Delay(5000).ConfigureAwait(false);
Exit();
}
}
internal static void Exit(byte exitCode = 0) { internal static void Exit(byte exitCode = 0) {
Shutdown(); Shutdown();
@@ -274,8 +72,8 @@ namespace ArchiSteamFarm {
Environment.Exit(0); Environment.Exit(0);
} }
internal static string GetUserInput(EUserInputType userInputType, string botName = ASF, string extraInformation = null) { internal static string GetUserInput(SharedInfo.EUserInputType userInputType, string botName = SharedInfo.ASF, string extraInformation = null) {
if (userInputType == EUserInputType.Unknown) { if (userInputType == SharedInfo.EUserInputType.Unknown) {
return null; return null;
} }
@@ -288,35 +86,35 @@ namespace ArchiSteamFarm {
lock (ConsoleLock) { lock (ConsoleLock) {
Logging.OnUserInputStart(); Logging.OnUserInputStart();
switch (userInputType) { switch (userInputType) {
case EUserInputType.DeviceID: case SharedInfo.EUserInputType.DeviceID:
Console.Write("<" + botName + "> Please enter your Device ID (including \"android:\"): "); Console.Write("<" + botName + "> Please enter your Device ID (including \"android:\"): ");
break; break;
case EUserInputType.Login: case SharedInfo.EUserInputType.Login:
Console.Write("<" + botName + "> Please enter your login: "); Console.Write("<" + botName + "> Please enter your login: ");
break; break;
case EUserInputType.Password: case SharedInfo.EUserInputType.Password:
Console.Write("<" + botName + "> Please enter your password: "); Console.Write("<" + botName + "> Please enter your password: ");
break; break;
case EUserInputType.PhoneNumber: case SharedInfo.EUserInputType.PhoneNumber:
Console.Write("<" + botName + "> Please enter your full phone number (e.g. +1234567890): "); Console.Write("<" + botName + "> Please enter your full phone number (e.g. +1234567890): ");
break; break;
case EUserInputType.SMS: case SharedInfo.EUserInputType.SMS:
Console.Write("<" + botName + "> Please enter SMS code sent on your mobile: "); Console.Write("<" + botName + "> Please enter SMS code sent on your mobile: ");
break; break;
case EUserInputType.SteamGuard: case SharedInfo.EUserInputType.SteamGuard:
Console.Write("<" + botName + "> Please enter the auth code sent to your email: "); Console.Write("<" + botName + "> Please enter the auth code sent to your email: ");
break; break;
case EUserInputType.SteamParentalPIN: case SharedInfo.EUserInputType.SteamParentalPIN:
Console.Write("<" + botName + "> Please enter steam parental PIN: "); Console.Write("<" + botName + "> Please enter steam parental PIN: ");
break; break;
case EUserInputType.RevocationCode: case SharedInfo.EUserInputType.RevocationCode:
Console.WriteLine("<" + botName + "> PLEASE WRITE DOWN YOUR REVOCATION CODE: " + extraInformation); Console.WriteLine("<" + botName + "> PLEASE WRITE DOWN YOUR REVOCATION CODE: " + extraInformation);
Console.Write("<" + botName + "> Hit enter once ready..."); Console.Write("<" + botName + "> Hit enter once ready...");
break; break;
case EUserInputType.TwoFactorAuthentication: case SharedInfo.EUserInputType.TwoFactorAuthentication:
Console.Write("<" + botName + "> Please enter your 2 factor auth code from your authenticator app: "); Console.Write("<" + botName + "> Please enter your 2 factor auth code from your authenticator app: ");
break; break;
case EUserInputType.WCFHostname: case SharedInfo.EUserInputType.WCFHostname:
Console.Write("<" + botName + "> Please enter your WCF hostname: "); Console.Write("<" + botName + "> Please enter your WCF hostname: ");
break; break;
default: default:
@@ -378,7 +176,7 @@ namespace ArchiSteamFarm {
} }
private static void InitServices() { private static void InitServices() {
string globalConfigFile = Path.Combine(ConfigDirectory, GlobalConfigFileName); string globalConfigFile = Path.Combine(SharedInfo.ConfigDirectory, SharedInfo.GlobalConfigFileName);
GlobalConfig = GlobalConfig.Load(globalConfigFile); GlobalConfig = GlobalConfig.Load(globalConfigFile);
if (GlobalConfig == null) { if (GlobalConfig == null) {
@@ -387,7 +185,7 @@ namespace ArchiSteamFarm {
Exit(1); Exit(1);
} }
string globalDatabaseFile = Path.Combine(ConfigDirectory, GlobalDatabaseFileName); string globalDatabaseFile = Path.Combine(SharedInfo.ConfigDirectory, SharedInfo.GlobalDatabaseFileName);
GlobalDatabase = GlobalDatabase.Load(globalDatabaseFile); GlobalDatabase = GlobalDatabase.Load(globalDatabaseFile);
if (GlobalDatabase == null) { if (GlobalDatabase == null) {
@@ -400,7 +198,7 @@ namespace ArchiSteamFarm {
WebBrowser.Init(); WebBrowser.Init();
WCF.Init(); WCF.Init();
WebBrowser = new WebBrowser(ASF); WebBrowser = new WebBrowser(SharedInfo.ASF);
} }
private static void ParsePreInitArgs(IEnumerable<string> args) { private static void ParsePreInitArgs(IEnumerable<string> args) {
@@ -486,7 +284,7 @@ namespace ArchiSteamFarm {
TaskScheduler.UnobservedTaskException += UnobservedTaskExceptionHandler; TaskScheduler.UnobservedTaskException += UnobservedTaskExceptionHandler;
Logging.InitCoreLoggers(); Logging.InitCoreLoggers();
Logging.LogGenericInfo("ASF V" + Version); Logging.LogGenericInfo("ASF V" + SharedInfo.Version);
if (!Runtime.IsRuntimeSupported()) { if (!Runtime.IsRuntimeSupported()) {
Logging.LogGenericError("ASF detected unsupported runtime version, program might NOT run correctly in current environment. You're running it at your own risk!"); Logging.LogGenericError("ASF detected unsupported runtime version, program might NOT run correctly in current environment. You're running it at your own risk!");
@@ -503,13 +301,13 @@ namespace ArchiSteamFarm {
// Common structure is bin/(x64/)Debug/ArchiSteamFarm.exe, so we allow up to 4 directories up // Common structure is bin/(x64/)Debug/ArchiSteamFarm.exe, so we allow up to 4 directories up
for (byte i = 0; i < 4; i++) { for (byte i = 0; i < 4; i++) {
Directory.SetCurrentDirectory(".."); Directory.SetCurrentDirectory("..");
if (Directory.Exists(ConfigDirectory)) { if (Directory.Exists(SharedInfo.ConfigDirectory)) {
break; break;
} }
} }
// If config directory doesn't exist after our adjustment, abort all of that // If config directory doesn't exist after our adjustment, abort all of that
if (!Directory.Exists(ConfigDirectory)) { if (!Directory.Exists(SharedInfo.ConfigDirectory)) {
Directory.SetCurrentDirectory(homeDirectory); Directory.SetCurrentDirectory(homeDirectory);
} }
} }
@@ -524,13 +322,13 @@ namespace ArchiSteamFarm {
// If debugging is on, we prepare debug directory prior to running // If debugging is on, we prepare debug directory prior to running
if (GlobalConfig.Debug) { if (GlobalConfig.Debug) {
if (Directory.Exists(DebugDirectory)) { if (Directory.Exists(SharedInfo.DebugDirectory)) {
Directory.Delete(DebugDirectory, true); Directory.Delete(SharedInfo.DebugDirectory, true);
Thread.Sleep(1000); // Dirty workaround giving Windows some time to sync Thread.Sleep(1000); // Dirty workaround giving Windows some time to sync
} }
Directory.CreateDirectory(DebugDirectory); Directory.CreateDirectory(SharedInfo.DebugDirectory);
SteamKit2.DebugLog.AddListener(new Debugging.DebugListener(Path.Combine(DebugDirectory, "debug.txt"))); SteamKit2.DebugLog.AddListener(new Debugging.DebugListener(Path.Combine(SharedInfo.DebugDirectory, "debug.txt")));
SteamKit2.DebugLog.Enabled = true; SteamKit2.DebugLog.Enabled = true;
} }
@@ -547,22 +345,22 @@ namespace ArchiSteamFarm {
// From now on it's server mode // From now on it's server mode
Logging.InitEnhancedLoggers(); Logging.InitEnhancedLoggers();
if (!Directory.Exists(ConfigDirectory)) { if (!Directory.Exists(SharedInfo.ConfigDirectory)) {
Logging.LogGenericError("Config directory doesn't exist!"); Logging.LogGenericError("Config directory doesn't exist!");
Thread.Sleep(5000); Thread.Sleep(5000);
Exit(1); Exit(1);
} }
CheckForUpdate().Wait(); ASF.CheckForUpdate().Wait();
// Before attempting to connect, initialize our list of CMs // Before attempting to connect, initialize our list of CMs
Bot.InitializeCMs(GlobalDatabase.CellID, GlobalDatabase.ServerListProvider); Bot.InitializeCMs(GlobalDatabase.CellID, GlobalDatabase.ServerListProvider);
bool isRunning = false; bool isRunning = false;
foreach (string botName in Directory.EnumerateFiles(ConfigDirectory, "*.json").Select(Path.GetFileNameWithoutExtension)) { foreach (string botName in Directory.EnumerateFiles(SharedInfo.ConfigDirectory, "*.json").Select(Path.GetFileNameWithoutExtension)) {
switch (botName) { switch (botName) {
case ASF: case SharedInfo.ASF:
case "example": case "example":
case "minimal": case "minimal":
continue; continue;

View File

@@ -32,5 +32,5 @@ using ArchiSteamFarm;
// You can specify all the values or you can default the Build and Revision Numbers // You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion(SharedInfo.Version)] [assembly: AssemblyVersion(SharedInfo.VersionNumber)]
[assembly: AssemblyFileVersion(SharedInfo.Version)] [assembly: AssemblyFileVersion(SharedInfo.VersionNumber)]

View File

@@ -22,9 +22,26 @@
*/ */
using System;
using System.Reflection;
namespace ArchiSteamFarm { namespace ArchiSteamFarm {
internal static class SharedInfo { internal static class SharedInfo {
internal const string Version = "2.1.3.8"; internal enum EUserInputType : byte {
Unknown,
DeviceID,
Login,
Password,
PhoneNumber,
SMS,
SteamGuard,
SteamParentalPIN,
RevocationCode,
TwoFactorAuthentication,
WCFHostname
}
internal const string VersionNumber = "2.1.3.8";
internal const string Copyright = "Copyright © ArchiSteamFarm 2015-2016"; internal const string Copyright = "Copyright © ArchiSteamFarm 2015-2016";
internal const string GithubRepo = "JustArchi/ArchiSteamFarm"; internal const string GithubRepo = "JustArchi/ArchiSteamFarm";
@@ -34,5 +51,16 @@ namespace ArchiSteamFarm {
internal const string EventLog = ServiceName; internal const string EventLog = ServiceName;
internal const string EventLogSource = EventLog + "Logger"; internal const string EventLogSource = EventLog + "Logger";
internal const string ASF = "ASF";
internal const string ConfigDirectory = "config";
internal const string DebugDirectory = "debug";
internal const string LogFile = "log.txt";
internal const string GithubReleaseURL = "https://api.github.com/repos/" + GithubRepo + "/releases"; // GitHub API is HTTPS only
internal const string GlobalConfigFileName = ASF + ".json";
internal const string GlobalDatabaseFileName = ASF + ".db";
internal static readonly Version Version = Assembly.GetEntryAssembly().GetName().Version;
} }
} }

View File

@@ -47,7 +47,7 @@ namespace ArchiSteamFarm {
internal static void Init() { internal static void Init() {
if (string.IsNullOrEmpty(Program.GlobalConfig.WCFHostname)) { if (string.IsNullOrEmpty(Program.GlobalConfig.WCFHostname)) {
Program.GlobalConfig.WCFHostname = Program.GetUserInput(Program.EUserInputType.WCFHostname); Program.GlobalConfig.WCFHostname = Program.GetUserInput(SharedInfo.EUserInputType.WCFHostname);
if (string.IsNullOrEmpty(Program.GlobalConfig.WCFHostname)) { if (string.IsNullOrEmpty(Program.GlobalConfig.WCFHostname)) {
return; return;
} }

View File

@@ -87,7 +87,7 @@ namespace ArchiSteamFarm {
}; };
// Most web services expect that UserAgent is set, so we declare it globally // Most web services expect that UserAgent is set, so we declare it globally
HttpClient.DefaultRequestHeaders.UserAgent.ParseAdd("ArchiSteamFarm/" + Program.Version); HttpClient.DefaultRequestHeaders.UserAgent.ParseAdd("ArchiSteamFarm/" + SharedInfo.Version);
} }
internal async Task<bool> UrlHeadRetry(string request, string referer = null) { internal async Task<bool> UrlHeadRetry(string request, string referer = null) {

View File

@@ -26,6 +26,7 @@ using Newtonsoft.Json;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using ArchiSteamFarm;
namespace ConfigGenerator { namespace ConfigGenerator {
internal abstract class ASFConfig { internal abstract class ASFConfig {
@@ -60,7 +61,7 @@ namespace ConfigGenerator {
internal void Remove() { internal void Remove() {
string queryPath = Path.GetFileNameWithoutExtension(FilePath); string queryPath = Path.GetFileNameWithoutExtension(FilePath);
lock (FileLock) { lock (FileLock) {
foreach (string botFile in Directory.EnumerateFiles(Program.ConfigDirectory, queryPath + ".*")) { foreach (string botFile in Directory.EnumerateFiles(SharedInfo.ConfigDirectory, queryPath + ".*")) {
try { try {
File.Delete(botFile); File.Delete(botFile);
} catch (Exception e) { } catch (Exception e) {
@@ -80,15 +81,15 @@ namespace ConfigGenerator {
string queryPath = Path.GetFileNameWithoutExtension(FilePath); string queryPath = Path.GetFileNameWithoutExtension(FilePath);
lock (FileLock) { lock (FileLock) {
foreach (string botFile in Directory.EnumerateFiles(Program.ConfigDirectory, queryPath + ".*")) { foreach (string botFile in Directory.EnumerateFiles(SharedInfo.ConfigDirectory, queryPath + ".*")) {
try { try {
File.Move(botFile, Path.Combine(Program.ConfigDirectory, botName + Path.GetExtension(botFile))); File.Move(botFile, Path.Combine(SharedInfo.ConfigDirectory, botName + Path.GetExtension(botFile)));
} catch (Exception e) { } catch (Exception e) {
Logging.LogGenericException(e); Logging.LogGenericException(e);
} }
} }
FilePath = Path.Combine(Program.ConfigDirectory, botName + ".json"); FilePath = Path.Combine(SharedInfo.ConfigDirectory, botName + ".json");
} }
} }
} }

View File

@@ -52,14 +52,14 @@ namespace ConfigGenerator {
return; return;
} }
ASFTab = new ConfigPage(GlobalConfig.Load(Path.Combine(Program.ConfigDirectory, Program.GlobalConfigFile))); ASFTab = new ConfigPage(GlobalConfig.Load(Path.Combine(SharedInfo.ConfigDirectory, SharedInfo.GlobalConfigFileName)));
MainTab.TabPages.Add(ASFTab); MainTab.TabPages.Add(ASFTab);
foreach (string configFile in Directory.EnumerateFiles(Program.ConfigDirectory, "*.json")) { foreach (string configFile in Directory.EnumerateFiles(SharedInfo.ConfigDirectory, "*.json")) {
string botName = Path.GetFileNameWithoutExtension(configFile); string botName = Path.GetFileNameWithoutExtension(configFile);
switch (botName) { switch (botName) {
case Program.ASF: case SharedInfo.ASF:
case "example": case "example":
case "minimal": case "minimal":
continue; continue;
@@ -161,7 +161,7 @@ namespace ConfigGenerator {
} }
switch (input) { switch (input) {
case Program.ASF: case SharedInfo.ASF:
case "example": case "example":
case "minimal": case "minimal":
Logging.LogGenericErrorWithoutStacktrace("This name is reserved!"); Logging.LogGenericErrorWithoutStacktrace("This name is reserved!");
@@ -173,7 +173,7 @@ namespace ConfigGenerator {
return; return;
} }
input = Path.Combine(Program.ConfigDirectory, input + ".json"); input = Path.Combine(SharedInfo.ConfigDirectory, input + ".json");
ConfigPage newConfigPage = new ConfigPage(BotConfig.Load(input)); ConfigPage newConfigPage = new ConfigPage(BotConfig.Load(input));
MainTab.TabPages.Insert(MainTab.TabPages.Count - ReservedTabs, newConfigPage); MainTab.TabPages.Insert(MainTab.TabPages.Count - ReservedTabs, newConfigPage);

View File

@@ -32,12 +32,8 @@ using ArchiSteamFarm;
namespace ConfigGenerator { namespace ConfigGenerator {
internal static class Program { internal static class Program {
internal const string ASF = "ASF";
internal const string ConfigDirectory = "config";
internal const string GlobalConfigFile = ASF + ".json";
private const string ASFDirectory = "ArchiSteamFarm"; private const string ASFDirectory = "ArchiSteamFarm";
private const string ASFExecutableFile = ASF + ".exe"; private const string ASFExecutableFile = SharedInfo.ASF + ".exe";
/// <summary> /// <summary>
/// The main entry point for the application. /// The main entry point for the application.
@@ -73,13 +69,13 @@ namespace ConfigGenerator {
} }
// If config directory doesn't exist after our adjustment, abort all of that // If config directory doesn't exist after our adjustment, abort all of that
if (!Directory.Exists(ConfigDirectory)) { if (!Directory.Exists(SharedInfo.ConfigDirectory)) {
Directory.SetCurrentDirectory(homeDirectory); Directory.SetCurrentDirectory(homeDirectory);
} }
} }
} }
if (!Directory.Exists(ConfigDirectory)) { if (!Directory.Exists(SharedInfo.ConfigDirectory)) {
Logging.LogGenericErrorWithoutStacktrace("Config directory could not be found!"); Logging.LogGenericErrorWithoutStacktrace("Config directory could not be found!");
Environment.Exit(1); Environment.Exit(1);
} }

View File

@@ -32,5 +32,5 @@ using ArchiSteamFarm;
// You can specify all the values or you can default the Build and Revision Numbers // You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion(SharedInfo.Version)] [assembly: AssemblyVersion(SharedInfo.VersionNumber)]
[assembly: AssemblyFileVersion(SharedInfo.Version)] [assembly: AssemblyFileVersion(SharedInfo.VersionNumber)]