mirror of
https://github.com/JustArchiNET/ArchiSteamFarm.git
synced 2026-01-01 22:20:52 +00:00
Add support for creating new files
Now it's complete, bug-hunting begins
This commit is contained in:
@@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -33,7 +34,18 @@ using ArchiSteamFarm.JSON;
|
||||
|
||||
namespace ArchiSteamFarm {
|
||||
internal static class ASF {
|
||||
internal sealed class BotConfigEventArgs : EventArgs {
|
||||
internal readonly BotConfig BotConfig;
|
||||
|
||||
internal BotConfigEventArgs(BotConfig botConfig = null) {
|
||||
BotConfig = botConfig;
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly ConcurrentDictionary<Bot, DateTime> LastWriteTimes = new ConcurrentDictionary<Bot, DateTime>();
|
||||
|
||||
private static Timer AutoUpdatesTimer;
|
||||
private static FileSystemWatcher FileSystemWatcher;
|
||||
|
||||
internal static async Task CheckForUpdate(bool updateOverride = false) {
|
||||
string exeFile = Assembly.GetEntryAssembly().Location;
|
||||
@@ -200,5 +212,154 @@ namespace ArchiSteamFarm {
|
||||
Program.Exit();
|
||||
}
|
||||
}
|
||||
|
||||
internal static void InitFileWatcher() {
|
||||
if (FileSystemWatcher != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
FileSystemWatcher = new FileSystemWatcher(SharedInfo.ConfigDirectory, "*json") {
|
||||
NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite
|
||||
};
|
||||
|
||||
FileSystemWatcher.Changed += OnChanged;
|
||||
FileSystemWatcher.Created += OnCreated;
|
||||
FileSystemWatcher.Deleted += OnDeleted;
|
||||
FileSystemWatcher.Renamed += OnRenamed;
|
||||
|
||||
FileSystemWatcher.EnableRaisingEvents = true;
|
||||
}
|
||||
|
||||
private static string GetBotNameFromConfigFileName(string fileName) {
|
||||
if (string.IsNullOrEmpty(fileName)) {
|
||||
Logging.LogNullError(nameof(fileName));
|
||||
return null;
|
||||
}
|
||||
|
||||
string botName = Path.GetFileNameWithoutExtension(fileName);
|
||||
if (!string.IsNullOrEmpty(botName)) {
|
||||
return !botName.Equals(SharedInfo.ASF) ? botName : null;
|
||||
}
|
||||
|
||||
Logging.LogNullError(nameof(botName));
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Bot GetBotFromConfigFileName(string fileName) {
|
||||
if (string.IsNullOrEmpty(fileName)) {
|
||||
Logging.LogNullError(nameof(fileName));
|
||||
return null;
|
||||
}
|
||||
|
||||
string botName = GetBotNameFromConfigFileName(fileName);
|
||||
if (string.IsNullOrEmpty(botName)) {
|
||||
Logging.LogNullError(nameof(botName));
|
||||
return null;
|
||||
}
|
||||
|
||||
Bot bot;
|
||||
return Bot.Bots.TryGetValue(botName, out bot) ? bot : null;
|
||||
}
|
||||
|
||||
private static async Task CreateBot(string botName) {
|
||||
if (string.IsNullOrEmpty(botName)) {
|
||||
Logging.LogNullError(nameof(botName));
|
||||
return;
|
||||
}
|
||||
|
||||
if (Bot.Bots.ContainsKey(botName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// It's entirely possible that some process is still accessing our file, allow at least a second before trying to read it
|
||||
await Task.Delay(1000).ConfigureAwait(false);
|
||||
|
||||
if (Bot.Bots.ContainsKey(botName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
new Bot(botName).Forget();
|
||||
}
|
||||
|
||||
private static async void OnChanged(object sender, FileSystemEventArgs e) {
|
||||
if ((sender == null) || (e == null)) {
|
||||
Logging.LogNullError(nameof(sender) + " || " + nameof(e));
|
||||
return;
|
||||
}
|
||||
|
||||
string botName = GetBotNameFromConfigFileName(e.Name);
|
||||
if (string.IsNullOrEmpty(botName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Bot bot;
|
||||
if (!Bot.Bots.TryGetValue(botName, out bot)) {
|
||||
CreateBot(botName).Forget();
|
||||
return;
|
||||
}
|
||||
|
||||
DateTime lastWriteTime = File.GetLastWriteTime(e.FullPath);
|
||||
|
||||
DateTime savedLastWriteTime;
|
||||
if (LastWriteTimes.TryGetValue(bot, out savedLastWriteTime)) {
|
||||
if (savedLastWriteTime >= lastWriteTime) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
LastWriteTimes[bot] = lastWriteTime;
|
||||
|
||||
// It's entirely possible that some process is still accessing our file, allow at least a second before trying to read it
|
||||
await Task.Delay(1000).ConfigureAwait(false);
|
||||
|
||||
// It's also possible that we got some other event in the meantime
|
||||
if (LastWriteTimes.TryGetValue(bot, out savedLastWriteTime)) {
|
||||
if (lastWriteTime != savedLastWriteTime) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (LastWriteTimes.TryRemove(bot, out savedLastWriteTime)) {
|
||||
if (lastWriteTime != savedLastWriteTime) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bot.OnNewConfigLoaded(new BotConfigEventArgs(BotConfig.Load(e.FullPath))).Forget();
|
||||
}
|
||||
|
||||
private static void OnCreated(object sender, FileSystemEventArgs e) {
|
||||
if ((sender == null) || (e == null)) {
|
||||
Logging.LogNullError(nameof(sender) + " || " + nameof(e));
|
||||
return;
|
||||
}
|
||||
|
||||
string botName = GetBotNameFromConfigFileName(e.Name);
|
||||
if (string.IsNullOrEmpty(botName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
CreateBot(botName).Forget();
|
||||
}
|
||||
|
||||
private static void OnDeleted(object sender, FileSystemEventArgs e) {
|
||||
if ((sender == null) || (e == null)) {
|
||||
Logging.LogNullError(nameof(sender) + " || " + nameof(e));
|
||||
return;
|
||||
}
|
||||
|
||||
Bot bot = GetBotFromConfigFileName(e.Name);
|
||||
bot?.OnNewConfigLoaded(new BotConfigEventArgs()).Forget();
|
||||
}
|
||||
|
||||
private static void OnRenamed(object sender, RenamedEventArgs e) {
|
||||
if ((sender == null) || (e == null)) {
|
||||
Logging.LogNullError(nameof(sender) + " || " + nameof(e));
|
||||
return;
|
||||
}
|
||||
|
||||
Bot bot = GetBotFromConfigFileName(e.OldName);
|
||||
bot?.OnNewConfigLoaded(new BotConfigEventArgs()).Forget();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,22 +256,9 @@ namespace ArchiSteamFarm {
|
||||
Initialize().Forget();
|
||||
}
|
||||
|
||||
private async Task Initialize() {
|
||||
BotConfig.NewConfigLoaded += OnNewConfigLoaded;
|
||||
BotConfig.InitializeWatcher();
|
||||
|
||||
if (!BotConfig.Enabled) {
|
||||
Logging.LogGenericInfo("Not starting this instance because it's disabled in config file", BotName);
|
||||
return;
|
||||
}
|
||||
|
||||
// Start
|
||||
await Start().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async void OnNewConfigLoaded(object sender, BotConfig.BotConfigEventArgs args) {
|
||||
if ((sender == null) || (args == null)) {
|
||||
Logging.LogNullError(nameof(sender) + " || " + nameof(args), BotName);
|
||||
internal async Task OnNewConfigLoaded(ASF.BotConfigEventArgs args) {
|
||||
if (args == null) {
|
||||
Logging.LogNullError(nameof(args), BotName);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -284,15 +271,12 @@ namespace ArchiSteamFarm {
|
||||
return;
|
||||
}
|
||||
|
||||
await InitializationSemaphore.WaitAsync().ConfigureAwait(false);
|
||||
|
||||
try {
|
||||
if (args.BotConfig == BotConfig) {
|
||||
return;
|
||||
}
|
||||
|
||||
Stop();
|
||||
BotConfig.NewConfigLoaded -= OnNewConfigLoaded;
|
||||
BotConfig = args.BotConfig;
|
||||
|
||||
CardsFarmer.Paused = BotConfig.Paused;
|
||||
@@ -341,11 +325,19 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
}
|
||||
|
||||
private async Task Initialize() {
|
||||
if (!BotConfig.Enabled) {
|
||||
Logging.LogGenericInfo("Not starting this instance because it's disabled in config file", BotName);
|
||||
return;
|
||||
}
|
||||
|
||||
// Start
|
||||
await Start().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
// Those are objects that are always being created if constructor doesn't throw exception
|
||||
ArchiWebHandler.Dispose();
|
||||
BotConfig.NewConfigLoaded -= OnNewConfigLoaded;
|
||||
BotConfig.Dispose();
|
||||
CardsFarmer.Dispose();
|
||||
HeartBeatTimer.Dispose();
|
||||
HandledGifts.Dispose();
|
||||
@@ -2178,6 +2170,7 @@ namespace ArchiSteamFarm {
|
||||
case EResult.ServiceUnavailable:
|
||||
case EResult.Timeout:
|
||||
case EResult.TryAnotherCM:
|
||||
case EResult.TwoFactorCodeMismatch:
|
||||
Logging.LogGenericWarning("Unable to login to Steam: " + callback.Result + " / " + callback.ExtendedResult, BotName);
|
||||
break;
|
||||
default: // Unexpected result, shutdown immediately
|
||||
|
||||
@@ -28,22 +28,13 @@ using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ArchiSteamFarm {
|
||||
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
|
||||
[SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")]
|
||||
[SuppressMessage("ReSharper", "ConvertToConstant.Local")]
|
||||
[SuppressMessage("ReSharper", "ConvertToConstant.Global")]
|
||||
internal sealed class BotConfig : IDisposable {
|
||||
internal sealed class BotConfigEventArgs : EventArgs {
|
||||
internal readonly BotConfig BotConfig;
|
||||
|
||||
internal BotConfigEventArgs(BotConfig botConfig = null) {
|
||||
BotConfig = botConfig;
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class BotConfig {
|
||||
internal enum EFarmingOrder : byte {
|
||||
Unordered,
|
||||
AppIDsAscending,
|
||||
@@ -137,12 +128,6 @@ namespace ArchiSteamFarm {
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
private readonly CryptoHelper.ECryptoMethod PasswordFormat = CryptoHelper.ECryptoMethod.PlainText;
|
||||
|
||||
internal event EventHandler<BotConfigEventArgs> NewConfigLoaded;
|
||||
|
||||
private string FilePath;
|
||||
private FileSystemWatcher FileSystemWatcher;
|
||||
private DateTime LastWriteTime = DateTime.MinValue;
|
||||
|
||||
internal static BotConfig Load(string filePath) {
|
||||
if (string.IsNullOrEmpty(filePath)) {
|
||||
Logging.LogNullError(nameof(filePath));
|
||||
@@ -167,8 +152,6 @@ namespace ArchiSteamFarm {
|
||||
return null;
|
||||
}
|
||||
|
||||
botConfig.FilePath = filePath;
|
||||
|
||||
// Support encrypted passwords
|
||||
if ((botConfig.PasswordFormat != CryptoHelper.ECryptoMethod.PlainText) && !string.IsNullOrEmpty(botConfig.SteamPassword)) {
|
||||
// In worst case password will result in null, which will have to be corrected by user during runtime
|
||||
@@ -192,78 +175,5 @@ namespace ArchiSteamFarm {
|
||||
|
||||
// This constructor is used only by deserializer
|
||||
private BotConfig() { }
|
||||
|
||||
internal void InitializeWatcher() {
|
||||
if (FileSystemWatcher != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(FilePath)) {
|
||||
Logging.LogNullError(nameof(FilePath));
|
||||
return;
|
||||
}
|
||||
|
||||
string fileDirectory = Path.GetDirectoryName(FilePath);
|
||||
if (string.IsNullOrEmpty(fileDirectory)) {
|
||||
Logging.LogNullError(nameof(fileDirectory));
|
||||
return;
|
||||
}
|
||||
|
||||
string fileName = Path.GetFileName(FilePath);
|
||||
if (string.IsNullOrEmpty(fileName)) {
|
||||
Logging.LogNullError(nameof(fileName));
|
||||
return;
|
||||
}
|
||||
|
||||
FileSystemWatcher = new FileSystemWatcher(fileDirectory, fileName) {
|
||||
NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite
|
||||
};
|
||||
|
||||
FileSystemWatcher.Changed += OnChanged;
|
||||
FileSystemWatcher.Deleted += OnDeleted;
|
||||
FileSystemWatcher.Renamed += OnRenamed;
|
||||
|
||||
FileSystemWatcher.EnableRaisingEvents = true;
|
||||
}
|
||||
|
||||
private async void OnChanged(object sender, FileSystemEventArgs e) {
|
||||
if (NewConfigLoaded == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
DateTime lastWriteTime;
|
||||
|
||||
lock (FileSystemWatcher) {
|
||||
lastWriteTime = File.GetLastWriteTime(FilePath);
|
||||
if (LastWriteTime == lastWriteTime) {
|
||||
return;
|
||||
}
|
||||
|
||||
LastWriteTime = lastWriteTime;
|
||||
}
|
||||
|
||||
// It's entirely possible that some process is still accessing our file, allow at least a second before trying to read it
|
||||
await Task.Delay(1000).ConfigureAwait(false);
|
||||
|
||||
// It's also possible that we got some other event in the meantime
|
||||
if (lastWriteTime != LastWriteTime) {
|
||||
return;
|
||||
}
|
||||
|
||||
NewConfigLoaded?.Invoke(this, new BotConfigEventArgs(Load(FilePath)));
|
||||
}
|
||||
private void OnDeleted(object sender, FileSystemEventArgs e) => NewConfigLoaded?.Invoke(this, new BotConfigEventArgs());
|
||||
private void OnRenamed(object sender, RenamedEventArgs e) => NewConfigLoaded?.Invoke(this, new BotConfigEventArgs());
|
||||
|
||||
public void Dispose() {
|
||||
if (FileSystemWatcher == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
FileSystemWatcher.Changed -= OnChanged;
|
||||
FileSystemWatcher.Deleted -= OnDeleted;
|
||||
FileSystemWatcher.Renamed -= OnRenamed;
|
||||
FileSystemWatcher.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -350,6 +350,8 @@ namespace ArchiSteamFarm {
|
||||
|
||||
new Bot(botName).Forget();
|
||||
}
|
||||
|
||||
ASF.InitFileWatcher();
|
||||
}
|
||||
|
||||
private static void Main(string[] args) {
|
||||
|
||||
Reference in New Issue
Block a user