Skip to content

Commit a3b74c3

Browse files
authored
Add timeout parameter (#1006)
1 parent d757712 commit a3b74c3

File tree

8 files changed

+63
-2
lines changed

8 files changed

+63
-2
lines changed

dev-proxy-abstractions/IProxyConfiguration.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,5 @@ public interface IProxyConfiguration
2121
IEnumerable<int> WatchPids { get; }
2222
IEnumerable<string> WatchProcessNames { get; }
2323
bool ShowTimestamps { get; }
24+
long? TimeoutSeconds { get; }
2425
}

dev-proxy/CommandHandlers/ProxyCommandHandler.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,11 @@ private void ParseOptions(InvocationContext context)
135135
{
136136
Configuration.InstallCert = installCert.Value;
137137
}
138+
var timeout = context.ParseResult.GetValueForOption<long?>(ProxyHost.TimeoutOptionName, _options);
139+
if (timeout is not null)
140+
{
141+
Configuration.TimeoutSeconds = timeout.Value;
142+
}
138143
}
139144

140145
private async Task CheckForNewVersionAsync()

dev-proxy/InactivityTimer.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
namespace DevProxy;
6+
7+
internal class InactivityTimer(long timeoutSeconds, Action timeoutAction)
8+
{
9+
private readonly TimeSpan _timeout = TimeSpan.FromSeconds(timeoutSeconds);
10+
private readonly Timer _timer = new(_ => timeoutAction.Invoke(), null, TimeSpan.FromSeconds(timeoutSeconds), Timeout.InfiniteTimeSpan);
11+
public void Reset() => _timer.Change(_timeout, Timeout.InfiniteTimeSpan);
12+
public void Stop() => _timer.Dispose();
13+
}

dev-proxy/Properties/launchSettings.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@
4545
"Jwt create": {
4646
"commandName": "Project",
4747
"commandLineArgs": "jwt create"
48+
},
49+
"Timeout": {
50+
"commandName": "Project",
51+
"commandLineArgs": "--timeout 30"
4852
}
4953
}
5054
}

dev-proxy/ProxyConfiguration.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,5 @@ public class ProxyConfiguration : IProxyConfiguration
3939
public int ApiPort { get; set; } = 8897;
4040
public bool ShowSkipMessages { get; set; } = true;
4141
public bool ShowTimestamps { get; set; } = true;
42+
public long? TimeoutSeconds { get; set; }
4243
}

dev-proxy/ProxyEngine.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ public class ProxyEngine(IProxyConfiguration config, ISet<UrlToWatch> urlsToWatc
3838
// Dictionary for plugins to store data between requests
3939
// the key is HashObject of the SessionEventArgs object
4040
private readonly Dictionary<int, Dictionary<string, object>> _pluginData = [];
41+
private InactivityTimer? _inactivityTimer;
4142

4243
public static X509Certificate2? Certificate => _proxyServer?.CertificateManager.RootCertificate;
4344

@@ -160,7 +161,12 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
160161
StartRecording();
161162
}
162163
_pluginEvents.AfterRequestLog += AfterRequestLogAsync;
163-
164+
165+
if (config.TimeoutSeconds.HasValue)
166+
{
167+
_inactivityTimer = new InactivityTimer(config.TimeoutSeconds.Value, _proxyState.StopProxy);
168+
}
169+
164170
if (!isInteractive)
165171
{
166172
return;
@@ -343,6 +349,8 @@ private void StopProxy()
343349
}
344350
}
345351

352+
_inactivityTimer?.Stop();
353+
346354
if (RunTime.IsMac && _config.AsSystemProxy)
347355
{
348356
ToggleSystemProxy(ToggleSystemProxyAction.Off);
@@ -453,6 +461,7 @@ private bool IsProxiedProcess(TunnelConnectSessionEventArgs e)
453461

454462
async Task OnRequestAsync(object sender, SessionEventArgs e)
455463
{
464+
_inactivityTimer?.Reset();
456465
if (IsProxiedHost(e.HttpClient.Request.RequestUri.Host) &&
457466
IsIncludedByHeaders(e.HttpClient.Request.Headers))
458467
{

dev-proxy/ProxyHost.cs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ internal class ProxyHost
3535
private readonly Option<bool?> _installCertOption;
3636
internal static readonly string UrlsToWatchOptionName = "--urls-to-watch";
3737
private static Option<IEnumerable<string>?>? _urlsToWatchOption;
38+
internal static readonly string TimeoutOptionName = "--timeout";
39+
private readonly Option<long?> _timeoutOption;
3840

3941
private static bool _configFileResolved = false;
4042
private static string _configFile = "devproxyrc.json";
@@ -268,6 +270,26 @@ public ProxyHost()
268270
Arity = ArgumentArity.ZeroOrMore
269271
};
270272
_urlsToWatchOption.AddAlias("-u");
273+
274+
_timeoutOption = new Option<long?>(TimeoutOptionName, "Time in seconds after which Dev Proxy exits. Resets when Dev Proxy intercepts a request.")
275+
{
276+
ArgumentHelpName = "timeout",
277+
};
278+
_timeoutOption.AddValidator(input =>
279+
{
280+
try
281+
{
282+
if (!long.TryParse(input.Tokens[0].Value, out long timeoutInput) || timeoutInput < 1)
283+
{
284+
input.ErrorMessage = $"{input.Tokens[0].Value} is not valid as a timeout value";
285+
}
286+
}
287+
catch (InvalidOperationException ex)
288+
{
289+
input.ErrorMessage = ex.Message;
290+
}
291+
});
292+
_timeoutOption.AddAlias("-t");
271293

272294
ProxyCommandHandler.Configuration.ConfigFile = ConfigFile;
273295
}
@@ -291,7 +313,8 @@ public RootCommand GetRootCommand(ILogger logger)
291313
_installCertOption,
292314
// _urlsToWatchOption is set while initialize the Program
293315
// As such, it's always set here
294-
_urlsToWatchOption!
316+
_urlsToWatchOption!,
317+
_timeoutOption
295318
};
296319
command.Description = "Dev Proxy is a command line tool for testing Microsoft Graph, SharePoint Online and any other HTTP APIs.";
297320

@@ -457,6 +480,7 @@ public RootCommand GetRootCommand(ILogger logger)
457480
_noFirstRunOption,
458481
_asSystemProxyOption,
459482
_installCertOption,
483+
_timeoutOption,
460484
.. optionsFromPlugins,
461485
],
462486
urlsToWatch,

schemas/v0.25.0/rc.schema.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,10 @@
134134
},
135135
"showTimestamps": {
136136
"type": "boolean"
137+
},
138+
"timeout": {
139+
"type": "number",
140+
"minimum": 1
137141
}
138142
},
139143
"required": [

0 commit comments

Comments
 (0)