diff --git a/SteamKit2/SteamKit2/Steam/CMClient.cs b/SteamKit2/SteamKit2/Steam/CMClient.cs index d4c9e633f..afdb5bf73 100644 --- a/SteamKit2/SteamKit2/Steam/CMClient.cs +++ b/SteamKit2/SteamKit2/Steam/CMClient.cs @@ -142,10 +142,12 @@ public CMClient( SteamConfiguration configuration, string identifier ) ID = identifier; - heartBeatFunc = new ScheduledFunction( () => - { - Send( new ClientMsgProtobuf( EMsg.ClientHeartBeat ) ); - } ); + heartBeatFunc = new ScheduledFunction( + configuration.TimeProvider, + () => + { + Send( new ClientMsgProtobuf( EMsg.ClientHeartBeat ) ); + } ); } /// diff --git a/SteamKit2/SteamKit2/Steam/SteamClient/AsyncJobManager.cs b/SteamKit2/SteamKit2/Steam/SteamClient/AsyncJobManager.cs index 714ace6e5..74f27421d 100644 --- a/SteamKit2/SteamKit2/Steam/SteamClient/AsyncJobManager.cs +++ b/SteamKit2/SteamKit2/Steam/SteamClient/AsyncJobManager.cs @@ -8,11 +8,11 @@ class AsyncJobManager internal ConcurrentDictionary asyncJobs; internal ScheduledFunction jobTimeoutFunc; - public AsyncJobManager() + public AsyncJobManager( TimeProvider timeProvider ) { asyncJobs = new ConcurrentDictionary(); - jobTimeoutFunc = new ScheduledFunction( CancelTimedoutJobs, TimeSpan.FromSeconds( 1 ) ); + jobTimeoutFunc = new ScheduledFunction( timeProvider, CancelTimedoutJobs, TimeSpan.FromSeconds( 1 ) ); } diff --git a/SteamKit2/SteamKit2/Steam/SteamClient/Configuration/ISteamConfigurationBuilder.cs b/SteamKit2/SteamKit2/Steam/SteamClient/Configuration/ISteamConfigurationBuilder.cs index 25023cbfe..737191874 100644 --- a/SteamKit2/SteamKit2/Steam/SteamClient/Configuration/ISteamConfigurationBuilder.cs +++ b/SteamKit2/SteamKit2/Steam/SteamClient/Configuration/ISteamConfigurationBuilder.cs @@ -72,6 +72,14 @@ public interface ISteamConfigurationBuilder /// A builder with modified configuration. ISteamConfigurationBuilder WithServerListProvider(IServerListProvider provider); + /// + /// Configures the for this . + /// This can be changed for testing and diagnostic purposes. + /// + /// The time provider to use. + /// A builder with modified configuration. + ISteamConfigurationBuilder WithTimeProvider(TimeProvider timeProvider); + /// /// Configures the Universe that this belongs to. /// diff --git a/SteamKit2/SteamKit2/Steam/SteamClient/Configuration/SteamConfiguration.cs b/SteamKit2/SteamKit2/Steam/SteamClient/Configuration/SteamConfiguration.cs index e16b61a22..1e3be4a82 100644 --- a/SteamKit2/SteamKit2/Steam/SteamClient/Configuration/SteamConfiguration.cs +++ b/SteamKit2/SteamKit2/Steam/SteamClient/Configuration/SteamConfiguration.cs @@ -93,6 +93,12 @@ internal static SteamConfiguration CreateDefault() /// public IServerListProvider ServerListProvider => state.ServerListProvider; + /// + /// The used to control the flow of time. + /// This can be changed for testing and diagnostic purposes. + /// + public TimeProvider TimeProvider => state.TimeProvider; + /// /// The Universe to connect to. This should always be unless /// you work at Valve and are using this internally. If this is you, hello there. @@ -106,7 +112,7 @@ internal static SteamConfiguration CreateDefault() public Uri WebAPIBaseAddress => state.WebAPIBaseAddress; /// - /// An API key to be used for authorized requests. + /// An API key to be used for authorized requests. /// Keys can be obtained from https://steamcommunity.com/dev or the Steamworks Partner site. /// public string WebAPIKey => state.WebAPIKey; diff --git a/SteamKit2/SteamKit2/Steam/SteamClient/Configuration/SteamConfigurationBuilder.cs b/SteamKit2/SteamKit2/Steam/SteamClient/Configuration/SteamConfigurationBuilder.cs index eb23cc202..34252f35c 100644 --- a/SteamKit2/SteamKit2/Steam/SteamClient/Configuration/SteamConfigurationBuilder.cs +++ b/SteamKit2/SteamKit2/Steam/SteamClient/Configuration/SteamConfigurationBuilder.cs @@ -39,6 +39,8 @@ public static SteamConfigurationState CreateDefaultState() ServerListProvider = new MemoryServerListProvider(), + TimeProvider = TimeProvider.System, + Universe = EUniverse.Public, WebAPIBaseAddress = WebAPI.DefaultBaseAddress @@ -98,6 +100,13 @@ public ISteamConfigurationBuilder WithServerListProvider(IServerListProvider pro return this; } + public ISteamConfigurationBuilder WithTimeProvider(TimeProvider timeProvider) + { + ArgumentNullException.ThrowIfNull(timeProvider); + state.TimeProvider = timeProvider; + return this; + } + public ISteamConfigurationBuilder WithUniverse(EUniverse universe) { state.Universe = universe; diff --git a/SteamKit2/SteamKit2/Steam/SteamClient/Configuration/SteamConfigurationState.cs b/SteamKit2/SteamKit2/Steam/SteamClient/Configuration/SteamConfigurationState.cs index da60c2e5f..4ba946d19 100644 --- a/SteamKit2/SteamKit2/Steam/SteamClient/Configuration/SteamConfigurationState.cs +++ b/SteamKit2/SteamKit2/Steam/SteamClient/Configuration/SteamConfigurationState.cs @@ -19,6 +19,7 @@ struct SteamConfigurationState public IMachineInfoProvider MachineInfoProvider; public ProtocolTypes ProtocolTypes; public IServerListProvider ServerListProvider; + public TimeProvider TimeProvider; public EUniverse Universe; public Uri WebAPIBaseAddress; public string WebAPIKey; diff --git a/SteamKit2/SteamKit2/Steam/SteamClient/SteamClient.cs b/SteamKit2/SteamKit2/Steam/SteamClient/SteamClient.cs index 49faf017e..1b2009c32 100644 --- a/SteamKit2/SteamKit2/Steam/SteamClient/SteamClient.cs +++ b/SteamKit2/SteamKit2/Steam/SteamClient/SteamClient.cs @@ -106,7 +106,7 @@ public SteamClient( SteamConfiguration configuration, string identifier ) this.processStartTime = process.StartTime; } - jobManager = new AsyncJobManager(); + jobManager = new AsyncJobManager( configuration.TimeProvider ); } diff --git a/SteamKit2/SteamKit2/Util/ScheduledFunction.cs b/SteamKit2/SteamKit2/Util/ScheduledFunction.cs index 72369ec9b..ea79615ec 100644 --- a/SteamKit2/SteamKit2/Util/ScheduledFunction.cs +++ b/SteamKit2/SteamKit2/Util/ScheduledFunction.cs @@ -17,19 +17,19 @@ class ScheduledFunction Action func; bool bStarted; - Timer timer; + ITimer timer; - public ScheduledFunction( Action func ) - : this( func, TimeSpan.FromMilliseconds( -1 ) ) + public ScheduledFunction( TimeProvider timeProvider, Action func ) + : this( timeProvider, func, TimeSpan.FromMilliseconds( -1 ) ) { } - public ScheduledFunction( Action func, TimeSpan delay ) + public ScheduledFunction( TimeProvider timeProvider, Action func, TimeSpan delay ) { this.func = func; this.Delay = delay; - timer = new Timer( Tick, null, TimeSpan.FromMilliseconds( -1 ), delay ); + timer = timeProvider.CreateTimer( Tick, null, TimeSpan.FromMilliseconds( -1 ), delay ); } ~ScheduledFunction() { diff --git a/SteamKit2/Tests/SteamConfigurationFacts.cs b/SteamKit2/Tests/SteamConfigurationFacts.cs index 9a6c08d7d..d9668fa1c 100644 --- a/SteamKit2/Tests/SteamConfigurationFacts.cs +++ b/SteamKit2/Tests/SteamConfigurationFacts.cs @@ -88,6 +88,12 @@ public void PublicUniverse() Assert.Equal(EUniverse.Public, configuration.Universe); } + [Fact] + public void TimeProviderIsSystemTime() + { + Assert.Equal(TimeProvider.System, configuration.TimeProvider); + } + [Fact] public void WebAPIAddress() { @@ -114,6 +120,7 @@ public SteamConfigurationConfiguredObjectFacts() .WithMachineInfoProvider(new CustomMachineInfoProvider()) .WithProtocolTypes(ProtocolTypes.WebSocket | ProtocolTypes.Udp) .WithServerListProvider(new CustomServerListProvider()) + .WithTimeProvider(new CustomTimeProvider()) .WithUniverse(EUniverse.Internal) .WithWebAPIBaseAddress(new Uri("http://foo.bar.com/api/")) .WithWebAPIKey("T0PS3kR1t")); @@ -177,6 +184,12 @@ public void ProtocolsAreConfigured() Assert.Equal(ProtocolTypes.WebSocket | ProtocolTypes.Udp, configuration.ProtocolTypes); } + [Fact] + public void TimeProviderIsConfigured() + { + Assert.IsType(configuration.TimeProvider); + } + [Fact] public void UniverseIsConfigured() { @@ -213,5 +226,9 @@ Task> IServerListProvider.FetchServerListAsync() Task IServerListProvider.UpdateServerListAsync(IEnumerable endpoints) => throw new NotImplementedException(); } + + class CustomTimeProvider : TimeProvider + { + } } }