diff --git a/CS2Interface/CSClient/Client.cs b/CS2Interface/CSClient/Client.cs index dd9409c..1568a23 100644 --- a/CS2Interface/CSClient/Client.cs +++ b/CS2Interface/CSClient/Client.cs @@ -602,9 +602,10 @@ internal async Task RemoveItemFromCasket(ulong casket_id, ulong item_id) { } [Flags] - internal enum EClientStatus : byte { + public enum EClientStatus : byte { None = 0, Connected = 1, - Ready = 2 + Ready = 2, + BotOffline = 4 } } \ No newline at end of file diff --git a/CS2Interface/Handlers/ClientHandler.cs b/CS2Interface/Handlers/ClientHandler.cs index 59305ce..f321573 100644 --- a/CS2Interface/Handlers/ClientHandler.cs +++ b/CS2Interface/Handlers/ClientHandler.cs @@ -104,12 +104,12 @@ internal void ForceStop() { internal (EClientStatus ClientStatus, string Message) Status() { if (!Bot.IsConnectedAndLoggedOn) { - return (EClientStatus.None, ArchiSteamFarm.Localization.Strings.BotNotConnected); + return (EClientStatus.BotOffline, ArchiSteamFarm.Localization.Strings.BotNotConnected); } EClientStatus status = Client.Status(); - bool connected = ((status & EClientStatus.Connected) == EClientStatus.Connected); - bool ready = ((status & EClientStatus.Ready) == EClientStatus.Ready); + bool connected = (status & EClientStatus.Connected) == EClientStatus.Connected; + bool ready = (status & EClientStatus.Ready) == EClientStatus.Ready; if (!connected) { if (!ready) { diff --git a/CS2Interface/IPC/Api/CS2InterfaceController.cs b/CS2Interface/IPC/Api/CS2InterfaceController.cs index 5f32755..d2ff0aa 100644 --- a/CS2Interface/IPC/Api/CS2InterfaceController.cs +++ b/CS2Interface/IPC/Api/CS2InterfaceController.cs @@ -12,7 +12,7 @@ using SteamKit2.GC.CSGO.Internal; using Swashbuckle.AspNetCore.Annotations; -namespace CS2Interface { +namespace CS2Interface.IPC { [Route("Api/CS2Interface")] public sealed class CS2InterfaceController : ArchiController { [HttpGet("{botNames:required}/Start")] @@ -64,6 +64,28 @@ public ActionResult Stop(string botNames) { return Ok(new GenericResponse>(true, results.ToDictionary(static result => result.Bot.BotName, static result => result.Response))); } + [HttpGet("{botNames:required}/Status")] + [SwaggerOperation (Summary = "Get the status of the CS2 Interface")] + [ProducesResponseType(typeof(GenericResponse>), (int) HttpStatusCode.OK)] + [ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.BadRequest)] + public ActionResult Status(string botNames) { + if (string.IsNullOrEmpty(botNames)) { + throw new ArgumentNullException(nameof(botNames)); + } + + HashSet? bots = Bot.GetBots(botNames); + + if ((bots == null) || (bots.Count == 0)) { + return BadRequest(new GenericResponse(false, string.Format(ArchiSteamFarm.Localization.Strings.BotNotFound, botNames))); + } + + IEnumerable<(Bot Bot, ClientStatus Response)> results = bots.Select( + static bot => (bot, new ClientStatus(ClientHandler.ClientHandlers[bot.BotName].Status())) + ); + + return Ok(new GenericResponse>(true, results.ToDictionary(static result => result.Bot.BotName, static result => result.Response))); + } + [HttpGet("{botNames:required}/InspectItem")] [SwaggerOperation (Summary = "Inspect a CS2 Item")] [ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.OK)] diff --git a/CS2Interface/IPC/Documentation/Interface/Status.md b/CS2Interface/IPC/Documentation/Interface/Status.md new file mode 100644 index 0000000..fb4d875 --- /dev/null +++ b/CS2Interface/IPC/Documentation/Interface/Status.md @@ -0,0 +1,45 @@ +# GET /Api/CS2Interface/{botNames}/Status + +## Description + +Gets the CS2 interface status for the given `botNames` + +## Path Parameters + +Name | Required | Description +--- | --- | --- +`botNames` | Yes | One or more ASF [bot names](https://github.com/JustArchiNET/ArchiSteamFarm/wiki/Commands#bots-argument) + +## Query Parameters + +None + +## Response Result + +Property | Type | Description +--- | --- | --- +`botName.Connected` | `bool` | True if the interface is connected for `botName` +`botName.Connecting` | `bool` | True if the interface is attempting to connect for `botName` +`botName.Ready` | `bool` | True if the interface is currently able to handle a new request for `botName` +`botName.Message` | `string` | A description of the status for `botName` + +## Example Response + +``` +http://127.0.0.1:1242/Api/CS2Interface/Bot1/Status +``` + +```json +{ + "Message": "OK", + "Success": true, + "Result": { + "Bot1": { + "Connected": true, + "Connecting": false, + "Ready": true, + "Message": "Ready" + } + } +} +``` diff --git a/CS2Interface/IPC/Documentation/Items/InspectItem.md b/CS2Interface/IPC/Documentation/Items/InspectItem.md index 385356b..ddf5414 100644 --- a/CS2Interface/IPC/Documentation/Items/InspectItem.md +++ b/CS2Interface/IPC/Documentation/Items/InspectItem.md @@ -57,7 +57,7 @@ Property | Type | Description `defs.music_def` | `object` | Related game data found in [items_game.txt](https://raw.githubusercontent.com/SteamDatabase/GameTracking-CS2/master/game/csgo/pak01_dir/scripts/items/items_game.txt) under `music_definitions` `defs.keychain_def` | `object` | Related game data found in [items_game.txt](https://raw.githubusercontent.com/SteamDatabase/GameTracking-CS2/master/game/csgo/pak01_dir/scripts/items/items_game.txt) under `keychain_definitions` -## Example Response +## Example Responses ``` http://127.0.0.1:1242/Api/CS2Interface/asf/InspectItem?url=steam://rungame/730/76561202255233023/+csgo_econ_action_preview%20M625254122282020305A6760346663D30614827701953021 diff --git a/CS2Interface/IPC/Responses/ClientStatus.cs b/CS2Interface/IPC/Responses/ClientStatus.cs new file mode 100644 index 0000000..2e6784d --- /dev/null +++ b/CS2Interface/IPC/Responses/ClientStatus.cs @@ -0,0 +1,31 @@ +using System.Text.Json.Serialization; + +namespace CS2Interface.IPC { + public sealed class ClientStatus { + [JsonInclude] + [JsonPropertyName("Connected")] + public bool Connected; + + [JsonInclude] + [JsonPropertyName("Connecting")] + public bool Connecting; + + [JsonInclude] + [JsonPropertyName("Ready")] + public bool Ready; + + [JsonInclude] + [JsonPropertyName("Message")] + public string Message; + + public ClientStatus((EClientStatus status, string message) @params) : this(@params.status, @params.message) {} + + public ClientStatus(EClientStatus status, string message) { + Connected = (status & EClientStatus.Connected) == EClientStatus.Connected; + Ready = (status & EClientStatus.Ready) == EClientStatus.Ready; + bool botOffline = (status & EClientStatus.BotOffline) == EClientStatus.BotOffline; + Connecting = !Connected && !Ready && !botOffline; + Message = message; + } + } +} diff --git a/README.md b/README.md index a0e293a..b81edc5 100644 --- a/README.md +++ b/README.md @@ -60,21 +60,22 @@ Command | Alias | API | Method | Parameters | Description --- | --- | --- | --- [`/Api/CS2Interface/{botNames}/Start`](CS2Interface/IPC/Documentation/Interface/Start.md)|`GET`| |Starts the CS2 Interface +[`/Api/CS2Interface/{botNames}/Status`](CS2Interface/IPC/Documentation/Interface/Status.md)|`GET`| |Get the CS2 Interface status [`/Api/CS2Interface/{botNames}/Stop`](CS2Interface/IPC/Documentation/Interface/Stop.md)|`GET`| |Stops the CS2 Interface #### Players API | Method | Parameters | Description --- | --- | --- | --- -[`/Api/CS2Interface/{botName}/PlayerProfile/{steamID}`](CS2Interface/IPC/Documentation/Players/PlayerProfile.md)|`GET`| |Get a friend's CS2 player profile +[`/Api/CS2Interface/{botName}/PlayerProfile/{steamID}`](CS2Interface/IPC/Documentation/Players/PlayerProfile.md)|`GET`| |Get a friend's player profile #### Items API | Method | Parameters | Description --- | --- | --- | --- -[`/Api/CS2Interface/{botName}/CraftItem/{recipeID}`](CS2Interface/IPC/Documentation/Items/CraftItem.md)|`GET`|`itemIDs`|Crafts an item using the specified trade up recipe -[`/Api/CS2Interface/{botName}/GetCrateContents/{crateID}`](CS2Interface/IPC/Documentation/Items/GetCrateContents.md)|`GET`|`minimal`, `showDefs`|Get the contents of the given bot's crate -[`/Api/CS2Interface/{botNames}/InspectItem`](CS2Interface/IPC/Documentation/Items/InspectItem.md)|`GET`|`url`, `s`, `a`, `d`, `m`, `minimal`, `showDefs`|Inspect a CS2 Item -[`/Api/CS2Interface/{botName}/Inventory`](CS2Interface/IPC/Documentation/Items/Inventory.md)|`GET`|`minimal`, `showDefs`|Get the given bot's CS2 inventory -[`/Api/CS2Interface/{botName}/RetrieveItem/{crateID}/{itemID}`](CS2Interface/IPC/Documentation/Items/RetrieveItem.md)|`GET`| |Retrieves an item from the specified crate -[`/Api/CS2Interface/{botName}/StoreItem/{crateID}/{itemID}`](CS2Interface/IPC/Documentation/Items/StoreItem.md)|`GET`| |Stores an item into the specified crate +[`/Api/CS2Interface/{botName}/CraftItem/{recipeID}`](CS2Interface/IPC/Documentation/Items/CraftItem.md)|`GET`|`itemIDs`|Craft an item +[`/Api/CS2Interface/{botName}/GetCrateContents/{crateID}`](CS2Interface/IPC/Documentation/Items/GetCrateContents.md)|`GET`|`minimal`, `showDefs`|Get a storage unit's contents +[`/Api/CS2Interface/{botNames}/InspectItem`](CS2Interface/IPC/Documentation/Items/InspectItem.md)|`GET`|`url`, `s`, `a`, `d`, `m`, `minimal`, `showDefs`|Inspect an item +[`/Api/CS2Interface/{botName}/Inventory`](CS2Interface/IPC/Documentation/Items/Inventory.md)|`GET`|`minimal`, `showDefs`|Get a bot's inventory +[`/Api/CS2Interface/{botName}/RetrieveItem/{crateID}/{itemID}`](CS2Interface/IPC/Documentation/Items/RetrieveItem.md)|`GET`| |Take an item out of a storage unit +[`/Api/CS2Interface/{botName}/StoreItem/{crateID}/{itemID}`](CS2Interface/IPC/Documentation/Items/StoreItem.md)|`GET`| |Place an item into a storage unit