Skip to content

Commit

Permalink
feat(repeater): adopt repeater self-deploying
Browse files Browse the repository at this point in the history
closes #174
  • Loading branch information
ostridm committed Jun 13, 2024
1 parent 2450016 commit 515d8ed
Show file tree
Hide file tree
Showing 29 changed files with 72 additions and 409 deletions.
22 changes: 0 additions & 22 deletions src/SecTester.Repeater/Api/CreateRepeaterRequest.cs

This file was deleted.

34 changes: 0 additions & 34 deletions src/SecTester.Repeater/Api/DefaultRepeaters.cs

This file was deleted.

13 changes: 0 additions & 13 deletions src/SecTester.Repeater/Api/DeleteRepeaterRequest.cs

This file was deleted.

10 changes: 0 additions & 10 deletions src/SecTester.Repeater/Api/IRepeaters.cs

This file was deleted.

8 changes: 0 additions & 8 deletions src/SecTester.Repeater/Api/RepeaterIdentity.cs

This file was deleted.

4 changes: 2 additions & 2 deletions src/SecTester.Repeater/Bus/DefaultRepeaterBusFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public DefaultRepeaterBusFactory(Configuration config, ILoggerFactory loggerFact
_scopeFactory = scopeFactory ?? throw new ArgumentNullException(nameof(scopeFactory));
}

public IRepeaterBus Create(string repeaterId)
public IRepeaterBus Create(string? hostname = default)
{
if (_config.Credentials is null)
{
Expand All @@ -39,7 +39,7 @@ public IRepeaterBus Create(string repeaterId)
ReconnectionDelayMax = options.ReconnectionDelayMax,
ConnectionTimeout = options.ConnectionTimeout,
Transport = TransportProtocol.WebSocket,
Auth = new { token = _config.Credentials.Token, domain = repeaterId }
Auth = new { token = _config.Credentials.Token, domain = hostname ?? System.Net.Dns.GetHostName() }
})
{
Serializer = new SocketIOMessagePackSerializer()
Expand Down
2 changes: 1 addition & 1 deletion src/SecTester.Repeater/Bus/IRepeaterBus.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ public interface IRepeaterBus : IAsyncDisposable
event Action<Version> UpgradeAvailable;

Task Connect();
Task Deploy(string repeaterId, CancellationToken? cancellationToken = null);
Task<string> Deploy(string? repeaterId, CancellationToken? cancellationToken = null);
}
2 changes: 1 addition & 1 deletion src/SecTester.Repeater/Bus/IRepeaterBusFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ namespace SecTester.Repeater.Bus;

public interface IRepeaterBusFactory
{
IRepeaterBus Create(string repeaterId);
IRepeaterBus Create(string? hostname = default);
}
5 changes: 3 additions & 2 deletions src/SecTester.Repeater/Bus/RepeaterInfo.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
using System;
using MessagePack;

namespace SecTester.Repeater.Bus;

[MessagePackObject]
public sealed record RepeaterInfo
public sealed record RepeaterInfo(string RepeaterId)
{
[Key("repeaterId")]
public string RepeaterId { get; set; } = null!;
public string RepeaterId { get; init; } = RepeaterId ?? throw new ArgumentNullException(nameof(RepeaterId));
}
31 changes: 16 additions & 15 deletions src/SecTester.Repeater/Bus/SocketIoRepeaterBus.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ internal sealed class SocketIoRepeaterBus : IRepeaterBus
private readonly ILogger<IRepeaterBus> _logger;
private readonly SocketIoRepeaterBusOptions _options;

internal SocketIoRepeaterBus(SocketIoRepeaterBusOptions options, ISocketIoConnection connection, ITimerProvider heartbeat, ILogger<IRepeaterBus> logger)
internal SocketIoRepeaterBus(SocketIoRepeaterBusOptions options, ISocketIoConnection connection, ITimerProvider heartbeat,
ILogger<IRepeaterBus> logger)
{
_options = options ?? throw new ArgumentNullException(nameof(options));
_connection = connection ?? throw new ArgumentNullException(nameof(connection));
Expand Down Expand Up @@ -48,13 +49,13 @@ private void DelegateEvents()
_connection.On("error", response =>
{
var err = response.GetValue<RepeaterError>();
ErrorOccurred?.Invoke(new(err.Message));
ErrorOccurred?.Invoke(new Exception(err.Message));

Check warning on line 52 in src/SecTester.Repeater/Bus/SocketIoRepeaterBus.cs

View workflow job for this annotation

GitHub Actions / windows-2019

Exception type System.Exception is not sufficiently specific
});

_connection.On("update-available", response =>
{
var version = response.GetValue<RepeaterVersion>();
UpgradeAvailable?.Invoke(new(version.Version));
UpgradeAvailable?.Invoke(new Version(version.Version));
});

_connection.On("request", async response =>
Expand Down Expand Up @@ -90,21 +91,27 @@ public async ValueTask DisposeAsync()
GC.SuppressFinalize(this);
}

public async Task Deploy(string repeaterId, CancellationToken? cancellationToken = null)
public async Task<string> Deploy(string? repeaterId, CancellationToken? cancellationToken = default)
{
try
{
var tcs = new TaskCompletionSource<RepeaterInfo>();

_connection.On("deployed", response => tcs.TrySetResult(response.GetValue<RepeaterInfo>()));

await _connection.EmitAsync("deploy", new RepeaterInfo { RepeaterId = repeaterId }).ConfigureAwait(false);
var args = repeaterId == null ? Array.Empty<object>() : new object[] { new RepeaterInfo(repeaterId) };

await _connection
.EmitAsync("deploy", args)
.ConfigureAwait(false);

using var _ = cancellationToken?.Register(() => tcs.TrySetCanceled());

var result = await tcs.Task.ConfigureAwait(false);
var result = (await tcs.Task.ConfigureAwait(false))!;

_logger.LogDebug("Repeater ({RepeaterId}) deployed", result.RepeaterId);

_logger.LogDebug("Repeater ({RepeaterId}) deployed", result?.RepeaterId);
return result.RepeaterId;
}
finally
{
Expand All @@ -120,13 +127,7 @@ private async Task SchedulePing()
_heartbeat.Start();
}

private async void Ping(object sender, ElapsedEventArgs args)
{
await Ping().ConfigureAwait(false);
}
private async void Ping(object sender, ElapsedEventArgs args) => await Ping().ConfigureAwait(false);

private async Task Ping()
{
await _connection.EmitAsync("ping").ConfigureAwait(false);
}
private async Task Ping() => await _connection.EmitAsync("ping").ConfigureAwait(false);
}
15 changes: 4 additions & 11 deletions src/SecTester.Repeater/DefaultRepeaterFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using Microsoft.Extensions.Logging;
using SecTester.Core;
using SecTester.Core.Logger;
using SecTester.Repeater.Api;
using SecTester.Repeater.Bus;

namespace SecTester.Repeater;
Expand All @@ -12,30 +11,24 @@ public class DefaultRepeaterFactory : IRepeaterFactory
{
private readonly Configuration _configuration;
private readonly IRepeaterBusFactory _busFactory;
private readonly IRepeaters _repeaters;
private readonly ILoggerFactory _loggerFactory;
private readonly IAnsiCodeColorizer _ansiCodeColorizer;
private readonly RequestRunnerResolver _requestRunnerResolver;

public DefaultRepeaterFactory(IRepeaters repeaters, IRepeaterBusFactory busFactory, Configuration configuration, ILoggerFactory loggerFactory, IAnsiCodeColorizer ansiCodeColorizer, RequestRunnerResolver requestRunnerResolver)
public DefaultRepeaterFactory(IRepeaterBusFactory busFactory, Configuration configuration, ILoggerFactory loggerFactory, IAnsiCodeColorizer ansiCodeColorizer, RequestRunnerResolver requestRunnerResolver)
{
_repeaters = repeaters ?? throw new ArgumentNullException(nameof(repeaters));
_loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
_busFactory = busFactory ?? throw new ArgumentNullException(nameof(busFactory));
_configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
_ansiCodeColorizer = ansiCodeColorizer ?? throw new ArgumentNullException(nameof(ansiCodeColorizer));
_requestRunnerResolver = requestRunnerResolver ?? throw new ArgumentNullException(nameof(requestRunnerResolver));
}

public async Task<IRepeater> CreateRepeater(RepeaterOptions? options = default)
public async Task<IRepeater> CreateRepeater()

Check warning on line 27 in src/SecTester.Repeater/DefaultRepeaterFactory.cs

View workflow job for this annotation

GitHub Actions / windows-2019

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
{
options ??= new RepeaterOptions();

var repeaterId = await _repeaters.CreateRepeater($"{options.NamePrefix}-{Guid.NewGuid()}", options.Description).ConfigureAwait(false);

var bus = _busFactory.Create(repeaterId);
var bus = _busFactory.Create();
var version = new Version(_configuration.RepeaterVersion);

return new Repeater(repeaterId, bus, version, _loggerFactory.CreateLogger<Repeater>(), _ansiCodeColorizer, _requestRunnerResolver);
return new Repeater(bus, version, _loggerFactory.CreateLogger<Repeater>(), _ansiCodeColorizer, _requestRunnerResolver);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
using SecTester.Core;
using SecTester.Core.Bus;
using SecTester.Core.Utils;
using SecTester.Repeater.Api;
using SecTester.Repeater.Bus;
using SecTester.Repeater.Dispatchers;
using SecTester.Repeater.RetryStrategies;
Expand All @@ -28,7 +27,6 @@ public static IServiceCollection AddSecTesterRepeater(this IServiceCollection co
.AddSingleton<IRetryStrategy, ExponentialBackoffIRetryStrategy>()
.AddSingleton<IRepeaterBusFactory, DefaultRepeaterBusFactory>()
.AddScoped<IRepeaterFactory, DefaultRepeaterFactory>()
.AddScoped<IRepeaters, DefaultRepeaters>()
.AddScoped<ITimerProvider, SystemTimerProvider>()
.AddScoped<IRequestRunner, HttpRequestRunner>()
.AddScoped<RequestRunnerResolver>(sp =>
Expand Down
2 changes: 1 addition & 1 deletion src/SecTester.Repeater/IRepeater.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace SecTester.Repeater;

public interface IRepeater : IAsyncDisposable
{
string RepeaterId { get; }
string? RepeaterId { get; }
Task Start(CancellationToken cancellationToken = default);
Task Stop(CancellationToken cancellationToken = default);
}
2 changes: 1 addition & 1 deletion src/SecTester.Repeater/IRepeaterFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ namespace SecTester.Repeater;

public interface IRepeaterFactory
{
Task<IRepeater> CreateRepeater(RepeaterOptions? options = default);
Task<IRepeater> CreateRepeater();
}
45 changes: 0 additions & 45 deletions src/SecTester.Repeater/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,51 +30,6 @@ The factory exposes the `CreateRepeater` method that returns a new `Repeater` in
await using var repeater = await repeaterFactory.CreateRepeater();
```

You can customize some properties, e.g. name prefix or description, passing options as follows:

```csharp
await using var repeater = await repeaterFactory.CreateRepeater(new RepeaterOptions {
NamePrefix = 'my-repeater',
Description = 'My repeater'
});
```

The `CreateRepeater` method accepts the options described below:

| Option | Description |
| :--------------------- | ----------------------------------------------------------------------------------------------------- |
| `namePrefix` | Enter a name prefix that will be used as a constant part of the unique name. By default, `sectester`. |
| `description` | Set a short description of the Repeater. |
| `requestRunnerOptions` | Custom the request runner settings that will be used to execute requests to your application. |

The default `requestRunnerOptions` is as follows:

```json
{
"timeout": 30000,
"maxContentLength": 100,
"reuseConnection": false,
"allowedMimes": [
"text/html",
"text/plain",
"text/css",
"text/javascript",
"text/markdown",
"text/xml",
"application/javascript",
"application/x-javascript",
"application/json",
"application/xml",
"application/x-www-form-urlencoded",
"application/msgpack",
"application/ld+json",
"application/graphql"
]
}
```

The `RequestRunnerOptions` exposes the following options that can used to customize the request runner's behavior: [RequestRunnerOptions.cs](https://github.com/NeuraLegion/sectester-net/blob/master/src/SecTester.Repeater/Runners/RequestRunnerOptions.cs)

The `Repeater` instance provides the `Start` method. This method is required to establish a connection with the Bright cloud engine and interact with other services.

```csharp
Expand Down
7 changes: 3 additions & 4 deletions src/SecTester.Repeater/Repeater.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,9 @@ public class Repeater : IRepeater
private readonly IAnsiCodeColorizer _ansiCodeColorizer;
private readonly RequestRunnerResolver _requestRunnersAccessor;

public Repeater(string repeaterId, IRepeaterBus bus, Version version, ILogger<Repeater> logger,
public Repeater(IRepeaterBus bus, Version version, ILogger<Repeater> logger,
IAnsiCodeColorizer ansiCodeColorizer, RequestRunnerResolver requestRunnersAccessor)
{
RepeaterId = repeaterId ?? throw new ArgumentNullException(nameof(repeaterId));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_version = version ?? throw new ArgumentNullException(nameof(version));
_bus = bus ?? throw new ArgumentNullException(nameof(bus));
Expand All @@ -33,7 +32,7 @@ public Repeater(string repeaterId, IRepeaterBus bus, Version version, ILogger<Re
}

public RunningStatus Status { get; private set; } = RunningStatus.Off;
public string RepeaterId { get; }
public string? RepeaterId { get; private set; }

public async ValueTask DisposeAsync()
{
Expand All @@ -60,7 +59,7 @@ public async Task Start(CancellationToken cancellationToken = default)
SubscribeToEvents();

await _bus.Connect().ConfigureAwait(false);
await _bus.Deploy(RepeaterId, cancellationToken).ConfigureAwait(false);
RepeaterId = await _bus.Deploy(RepeaterId, cancellationToken).ConfigureAwait(false);

Status = RunningStatus.Running;
}
Expand Down
24 changes: 0 additions & 24 deletions src/SecTester.Repeater/RepeaterOptions.cs

This file was deleted.

Loading

0 comments on commit 515d8ed

Please sign in to comment.