44// Created : 02-23-2021
55//
66// Last Modified By : Nathan Pipes
7- // Last Modified On : 02-27 -2021
7+ // Last Modified On : 09-08 -2021
88// ***********************************************************************
99// <copyright file="Helpers.cs" company="NPipes">
1010// Copyright (c) NPipes. All rights reserved.
1111// </copyright>
1212// <summary></summary>
1313// ***********************************************************************
14+
1415using System ;
1516using System . Net ;
1617using System . Net . Sockets ;
18+ using System . Text ;
19+ using System . Text . Json ;
1720using System . Threading ;
1821using System . Threading . Tasks ;
22+ using SupportBot . Checks . Modal ;
1923
2024namespace SupportBot . Checks
2125{
@@ -24,6 +28,64 @@ namespace SupportBot.Checks
2428 /// </summary>
2529 public class Helpers
2630 {
31+ /// <summary>
32+ /// Checks using the Steam Public API what is currently running on the specified server
33+ /// </summary>
34+ /// <param name="address">The hostname or IP of the server to check</param>
35+ /// <returns>List of servers running, or an error message</returns>
36+ public static async Task < string > CheckSteam ( string address )
37+ {
38+ try
39+ {
40+ var sb = new StringBuilder ( ) ;
41+
42+ if ( ! Helpers . CheckIpValid ( address ) )
43+ {
44+ var entries = await Dns . GetHostAddressesAsync ( address ) ;
45+ if ( entries . Length > 1 )
46+ {
47+ sb . Append (
48+ "Multiple addresses found for this host, only the first is checked, please specify the IP you want to check next time.\n " ) ;
49+ }
50+
51+ //Set the address to the resolved IP.
52+ address = entries [ 0 ] . ToString ( ) ;
53+ }
54+
55+ using var webClient = new WebClient ( ) ;
56+ //We are not using Async here as this will cause the method to hang the entire Task.
57+ var result = JsonSerializer . Deserialize < SteamApiResponse > (
58+ webClient . DownloadString (
59+ $ "https://api.steampowered.com/ISteamApps/GetServersAtAddress/v0001?addr={ address } ") ) ;
60+
61+ if ( result == null || ! result . response . success )
62+ {
63+ return await Task . FromResult ( "Steam API resulted in a failure. Try again later." ) ;
64+ }
65+
66+ var totalServers = result . response . servers . Length ;
67+
68+ sb . Append ( "Steam can see the following:\n " ) ;
69+
70+ foreach ( var item in result . response . servers )
71+ {
72+ sb . Append (
73+ $ "**{ item . gamedir } **\n App ID: { item . appid } \n Is Secure: { item . secure } \n Is Lan:{ item . lan } \n Game Port:{ item . gameport } \n Spec Port:{ item . specport } \n ") ;
74+ }
75+
76+ sb . Append ( $ "Total Servers: { totalServers } ") ;
77+
78+ var response = sb . ToString ( ) ;
79+ return await Task . FromResult ( response ) ;
80+ }
81+ catch ( Exception )
82+ {
83+ // ignored
84+ }
85+
86+ return await Task . FromResult ( "Unable to check with steam, sorry about that." ) ;
87+ }
88+
2789 /// <summary>
2890 /// Tries to open a network connection to a specific port retrieving the result.
2991 /// </summary>
@@ -55,7 +117,8 @@ public static PortState GetPortState(string host, int port, int timeoutSeconds =
55117 var waitHandle = asyncResult . AsyncWaitHandle ;
56118 try
57119 {
58- if ( asyncResult . AsyncWaitHandle . WaitOne ( TimeSpan . FromSeconds ( timeoutSeconds ) , false ) )
120+ if ( asyncResult . AsyncWaitHandle . WaitOne ( TimeSpan . FromSeconds ( timeoutSeconds ) ,
121+ false ) )
59122 {
60123 // The result was positive
61124 if ( ! asyncResult . IsCompleted )
@@ -67,6 +130,7 @@ public static PortState GetPortState(string host, int port, int timeoutSeconds =
67130 result = client . Connected ? PortState . Open : PortState . Closed ;
68131 }
69132 }
133+
70134 // ensure the ending-call
71135 client . EndConnect ( asyncResult ) ;
72136 }
@@ -79,15 +143,12 @@ public static PortState GetPortState(string host, int port, int timeoutSeconds =
79143 catch ( SocketException sockEx )
80144 {
81145 // see https://msdn.microsoft.com/en-us/library/ms740668.aspx for a list of all states
82- switch ( sockEx . NativeErrorCode )
146+ result = sockEx . NativeErrorCode switch
83147 {
84- case 10060 :
85- result = PortState . TimedOut ;
86- break ;
87- case 10061 :
88- result = PortState . Refused ;
89- break ;
90- }
148+ 10060 => PortState . TimedOut ,
149+ 10061 => PortState . Refused ,
150+ _ => result
151+ } ;
91152 }
92153 catch ( Exception )
93154 {
@@ -107,15 +168,14 @@ public static PortState GetPortState(string host, int port, int timeoutSeconds =
107168 {
108169 client . Connect ( host , port ) ;
109170 var asyncResult = client . BeginReceive (
110- _ =>
111- {
112- } ,
171+ _ => { } ,
113172 null ) ;
114173 asyncResult . AsyncWaitHandle . WaitOne ( TimeSpan . FromSeconds ( timeoutSeconds ) , false ) ;
115174 if ( ! asyncResult . IsCompleted )
116175 {
117176 return PortState . TimedOut ;
118177 }
178+
119179 result = PortState . Open ;
120180 }
121181 catch ( SocketException sockEx )
@@ -138,6 +198,7 @@ public static PortState GetPortState(string host, int port, int timeoutSeconds =
138198 client . Close ( ) ;
139199 }
140200 }
201+
141202 return result ;
142203 } ,
143204 token ) . ContinueWith (
@@ -147,6 +208,7 @@ public static PortState GetPortState(string host, int port, int timeoutSeconds =
147208 {
148209 return PortState . TimedOut ;
149210 }
211+
150212 return t . Result ;
151213 } ,
152214 token ) . Result ;
@@ -163,7 +225,7 @@ public static PortState GetPortState(string host, int port, int timeoutSeconds =
163225 {
164226 // empty catch
165227 }
166-
228+
167229 return outerResult ;
168230 }
169231
@@ -208,6 +270,4 @@ public enum PortState
208270 /// </summary>
209271 Refused = 4
210272 }
211-
212-
213273}
0 commit comments