diff --git a/ArchiSteamFarm/ArchiSteamFarm.csproj b/ArchiSteamFarm/ArchiSteamFarm.csproj
index 7663509cb..b55c32ee8 100644
--- a/ArchiSteamFarm/ArchiSteamFarm.csproj
+++ b/ArchiSteamFarm/ArchiSteamFarm.csproj
@@ -79,6 +79,7 @@
+
@@ -100,6 +101,7 @@
+
diff --git a/ArchiSteamFarm/Logging.cs b/ArchiSteamFarm/Logging.cs
index 410094582..f28857c6e 100644
--- a/ArchiSteamFarm/Logging.cs
+++ b/ArchiSteamFarm/Logging.cs
@@ -31,6 +31,8 @@ namespace ArchiSteamFarm {
internal static class Logging {
private static readonly object FileLock = new object();
+ internal static bool LogToFile { get; set; } = false;
+
internal static void Init() {
File.Delete(Program.LogFile);
}
@@ -47,8 +49,10 @@ namespace ArchiSteamFarm {
Console.Write(loggedMessage);
}
- lock (FileLock) {
- File.AppendAllText(Program.LogFile, loggedMessage);
+ if (LogToFile) {
+ lock (FileLock) {
+ File.AppendAllText(Program.LogFile, loggedMessage);
+ }
}
}
diff --git a/ArchiSteamFarm/Program.cs b/ArchiSteamFarm/Program.cs
index c79f40574..88ee49571 100644
--- a/ArchiSteamFarm/Program.cs
+++ b/ArchiSteamFarm/Program.cs
@@ -31,7 +31,7 @@ using System.Threading.Tasks;
namespace ArchiSteamFarm {
internal static class Program {
- internal enum EUserInputType {
+ internal enum EUserInputType : byte {
Login,
Password,
PhoneNumber,
@@ -42,6 +42,12 @@ namespace ArchiSteamFarm {
TwoFactorAuthentication,
}
+ internal enum EMode : byte {
+ Normal, // Standard most common usage
+ Client, // WCF client only
+ Server // Normal + WCF server
+ }
+
private const string LatestGithubReleaseURL = "https://api.github.com/repos/JustArchi/ArchiSteamFarm/releases/latest";
internal const string ConfigDirectory = "config";
internal const string LogFile = "log.txt";
@@ -52,9 +58,12 @@ namespace ArchiSteamFarm {
private static readonly Assembly Assembly = Assembly.GetExecutingAssembly();
private static readonly string ExecutableFile = Assembly.Location;
private static readonly string ExecutableDirectory = Path.GetDirectoryName(ExecutableFile);
+ private static readonly WCF WCF = new WCF();
internal static readonly string Version = Assembly.GetName().Version.ToString();
+ private static EMode Mode;
+
internal static bool ConsoleIsBusy { get; private set; } = false;
private static async Task CheckForUpdate() {
@@ -141,10 +150,9 @@ namespace ArchiSteamFarm {
return result.Trim(); // Get rid of all whitespace characters
}
- internal static async void OnBotShutdown() {
+ internal static void OnBotShutdown() {
if (Bot.GetRunningBotsCount() == 0) {
Logging.LogGenericInfo("Main", "No bots are running, exiting");
- await Utilities.SleepAsync(5000).ConfigureAwait(false); // This might be the only message user gets, consider giving him some time
ShutdownResetEvent.Set();
}
}
@@ -154,7 +162,42 @@ namespace ArchiSteamFarm {
WebBrowser.Init();
}
+ private static void ParseArgs(string[] args) {
+ foreach (string arg in args) {
+ switch (arg) {
+ case "--client":
+ Mode = EMode.Client;
+ Logging.LogToFile = false;
+ break;
+ case "--log":
+ Logging.LogToFile = true;
+ break;
+ case "--no-log":
+ Logging.LogToFile = false;
+ break;
+ case "--server":
+ Mode = EMode.Server;
+ WCF.StartServer();
+ break;
+ default:
+ if (arg.StartsWith("--")) {
+ Logging.LogGenericWarning("Main", "Unrecognized parameter: " + arg);
+ continue;
+ }
+
+ if (Mode != EMode.Client) {
+ Logging.LogGenericWarning("Main", "Ignoring command because --client wasn't specified: " + arg);
+ continue;
+ }
+
+ WCF.SendCommand(arg);
+ break;
+ }
+ }
+ }
+
private static void Main(string[] args) {
+ Logging.LogGenericInfo("Main", "Archi's Steam Farm, version " + Version);
Directory.SetCurrentDirectory(ExecutableDirectory);
InitServices();
@@ -175,7 +218,18 @@ namespace ArchiSteamFarm {
}
}
- Logging.LogGenericInfo("Main", "Archi's Steam Farm, version " + Version);
+ // By default we're operating on normal mode
+ Mode = EMode.Normal;
+ Logging.LogToFile = true;
+
+ // But that can be overriden by arguments
+ ParseArgs(args);
+
+ // If we ran ASF as a client, we're done by now
+ if (Mode == EMode.Client) {
+ return;
+ }
+
Task.Run(async () => await CheckForUpdate().ConfigureAwait(false)).Wait();
if (!Directory.Exists(ConfigDirectory)) {
@@ -196,6 +250,11 @@ namespace ArchiSteamFarm {
OnBotShutdown();
ShutdownResetEvent.WaitOne();
+
+ // We got a signal to shutdown
+ WCF.StopServer();
+
+ Thread.Sleep(5000); // We're shuting down, consider giving user some time to read the message
}
}
}
diff --git a/ArchiSteamFarm/WCF.cs b/ArchiSteamFarm/WCF.cs
new file mode 100644
index 000000000..3afdddc7b
--- /dev/null
+++ b/ArchiSteamFarm/WCF.cs
@@ -0,0 +1,52 @@
+using System;
+using System.ServiceModel;
+
+namespace ArchiSteamFarm {
+ [ServiceContract]
+ internal interface IWCF {
+ [OperationContract]
+ string SendCommand(string command);
+ }
+
+ internal class WCF : IWCF {
+ private const string URL = "http://localhost:1242/ASF"; // 1242 = 1024 + A(65) + S(83) + F(70)
+
+ private ServiceHost ServiceHost;
+
+ internal void StartServer() {
+ if (ServiceHost != null) {
+ return;
+ }
+
+ Logging.LogGenericNotice("WCF", "Starting WCF server...");
+ ServiceHost = new ServiceHost(typeof(WCF));
+ ServiceHost.AddServiceEndpoint(typeof(IWCF), new BasicHttpBinding(), URL);
+
+ try {
+ ServiceHost.Open();
+ } catch (AddressAccessDeniedException) {
+ Logging.LogGenericWarning("WCF", "WCF service could not be started because of AddressAccessDeniedException");
+ Logging.LogGenericWarning("WCF", "If you want to use WCF service provided by ASF, consider starting ASF as administrator, or giving proper permissions");
+ return;
+ } catch (Exception e) {
+ Logging.LogGenericException("WCF", e);
+ return;
+ }
+
+ Logging.LogGenericNotice("WCF", "WCF server ready!");
+ }
+
+ internal void StopServer() {
+ if (ServiceHost == null) {
+ return;
+ }
+
+ ServiceHost.Close();
+ ServiceHost = null;
+ }
+
+ public string SendCommand(string command) {
+ throw new NotImplementedException();
+ }
+ }
+}