From 15106dbfd67c11e1dba1765bb55deb9217ac20f3 Mon Sep 17 00:00:00 2001 From: Peter Kurfer Date: Sat, 20 Feb 2021 15:18:08 +0100 Subject: [PATCH] Add audit API client - cleanup - generate PCAP API --- .../Audit/Client/AuditApiClient.cs | 73 +++++++++++++++++++ src/INetMock.Client/Audit/Details.cs | 21 +++--- src/INetMock.Client/Audit/Event.cs | 9 +-- .../Audit/EventServerStreamReader.cs | 28 ------- src/INetMock.Client/Audit/IAuditApiClient.cs | 14 ++++ src/INetMock.Client/Audit/IEventReader.cs | 4 +- .../Serialization/EventServerStreamReader.cs | 30 ++++++++ .../{ => Serialization}/GenericReader.cs | 5 +- .../Audit/{ => Serialization}/ProtoReader.cs | 8 +- .../Audit/{ => Serialization}/TypedReader.cs | 2 +- src/INetMock.Client/INetMock.Client.csproj | 1 + .../{ => Serialization}/GenericReaderTest.cs | 7 +- .../{ => Serialization}/TypedReaderTest.cs | 7 +- 13 files changed, 151 insertions(+), 58 deletions(-) create mode 100644 src/INetMock.Client/Audit/Client/AuditApiClient.cs delete mode 100644 src/INetMock.Client/Audit/EventServerStreamReader.cs create mode 100644 src/INetMock.Client/Audit/IAuditApiClient.cs create mode 100644 src/INetMock.Client/Audit/Serialization/EventServerStreamReader.cs rename src/INetMock.Client/Audit/{ => Serialization}/GenericReader.cs (89%) rename src/INetMock.Client/Audit/{ => Serialization}/ProtoReader.cs (96%) rename src/INetMock.Client/Audit/{ => Serialization}/TypedReader.cs (98%) rename tests/INetMock.Client.Test/Audit/{ => Serialization}/GenericReaderTest.cs (89%) rename tests/INetMock.Client.Test/Audit/{ => Serialization}/TypedReaderTest.cs (84%) diff --git a/src/INetMock.Client/Audit/Client/AuditApiClient.cs b/src/INetMock.Client/Audit/Client/AuditApiClient.cs new file mode 100644 index 0000000..c29aa53 --- /dev/null +++ b/src/INetMock.Client/Audit/Client/AuditApiClient.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Grpc.Core; +using Grpc.Net.Client; +using INetMock.Client.Audit.Serialization; +using INetMock.Client.Rpc; + +namespace INetMock.Client.Audit.Client +{ + public class AuditApiClient : IAuditApiClient + { + private readonly Rpc.Audit.AuditClient _auditClient; + + public AuditApiClient(string address, GrpcChannelOptions? options = null) : this(new Uri(address), options) + { + } + + public AuditApiClient(Uri address, GrpcChannelOptions? options = null) : this( + GrpcChannel.ForAddress(address, options ?? new GrpcChannelOptions())) + { + } + + public AuditApiClient(ChannelBase channel) + { + _auditClient = new Rpc.Audit.AuditClient(channel); + } + + public async Task> ListSinksAsync(CancellationToken token = default) + { + var sinks = await _auditClient.ListSinksAsync(new ListSinksRequest(), Metadata.Empty, null, token); + return sinks.Sinks; + } + + public async Task RegisterFileSinkAsync(string targetPath, CancellationToken token = default) + { + var resp = await _auditClient.RegisterFileSinkAsync( + new RegisterFileSinkRequest {TargetPath = targetPath}, + Metadata.Empty, + null, + token + ); + + return resp.ResolvedPath; + } + + public async Task RemoveFileSinkAsync(string targetPath, CancellationToken token = default) + { + var resp = await _auditClient.RemoveFileSinkAsync(new RemoveFileSinkRequest + { + TargetPath = targetPath + }, + Metadata.Empty, + null, + token + ); + + return resp.SinkGotRemoved; + } + + public IProtoEventReader EventStreamAsync(string watcherName, CancellationToken token = default) + { + var stream = _auditClient.WatchEvents( + new WatchEventsRequest {WatcherName = watcherName}, + Metadata.Empty, + null, + token + ); + return new EventServerStreamReader(stream); + } + } +} diff --git a/src/INetMock.Client/Audit/Details.cs b/src/INetMock.Client/Audit/Details.cs index 8629536..144de5c 100644 --- a/src/INetMock.Client/Audit/Details.cs +++ b/src/INetMock.Client/Audit/Details.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Net.Http; using System.Net.Http.Headers; using Google.Protobuf.WellKnownTypes; @@ -9,11 +8,13 @@ using INetMock.Client.Audit.Details; namespace INetMock.Client.Audit { public abstract record EventDetails; + public record EmptyDetails : EventDetails; public record GenericDetails : EventDetails { private readonly Any? _detailsAny; + public GenericDetails() { _detailsAny = null; @@ -27,14 +28,16 @@ namespace INetMock.Client.Audit public static implicit operator HttpDetails(GenericDetails gd) { if (gd._detailsAny == null || gd._detailsAny.Value == null) return new(); - if(!gd._detailsAny.TypeUrl.EndsWith(HTTPDetailsEntity.Descriptor.FullName)) throw new InvalidOperationException(); + if (!gd._detailsAny.TypeUrl.EndsWith(HTTPDetailsEntity.Descriptor.FullName)) + throw new InvalidOperationException(); return new HttpDetails(gd._detailsAny); } - + public static implicit operator DnsDetails(GenericDetails gd) { if (gd._detailsAny == null || gd._detailsAny.Value == null) return new(); - if(!gd._detailsAny.TypeUrl.EndsWith(HTTPDetailsEntity.Descriptor.FullName)) throw new InvalidOperationException(); + if (!gd._detailsAny.TypeUrl.EndsWith(HTTPDetailsEntity.Descriptor.FullName)) + throw new InvalidOperationException(); return new DnsDetails(gd._detailsAny); } } @@ -43,7 +46,6 @@ namespace INetMock.Client.Audit { public HttpDetails() { - } public HttpDetails(Any? any) @@ -51,14 +53,14 @@ namespace INetMock.Client.Audit if (any == null || any.Value == null) return; var detailsEntity = HTTPDetailsEntity.Parser.ParseFrom(any.Value); - + Method = new HttpMethod(detailsEntity.Method.ToString()); Host = detailsEntity.Host; Uri = detailsEntity.Uri; Proto = detailsEntity.Proto; Headers = new INetMockHttpHeaders(detailsEntity.Headers); } - + public HttpMethod Method { get; init; } public string Host { get; init; } public string Uri { get; init; } @@ -70,16 +72,15 @@ namespace INetMock.Client.Audit { public DnsDetails() { - } public DNSOpCode OpCode { get; init; } - + public IReadOnlyList Questions { get; init; } public DnsDetails(Any? any) { - if(any == null || any.Value == null) return; + if (any == null || any.Value == null) return; var entity = DNSDetailsEntity.Parser.ParseFrom(any.Value); OpCode = entity.Opcode; diff --git a/src/INetMock.Client/Audit/Event.cs b/src/INetMock.Client/Audit/Event.cs index df66728..1ae0655 100644 --- a/src/INetMock.Client/Audit/Event.cs +++ b/src/INetMock.Client/Audit/Event.cs @@ -7,13 +7,12 @@ namespace INetMock.Client.Audit { public Event() { - } public Event(EventEntity entity) { if (entity == null) throw new ArgumentNullException(nameof(entity)); - + var details = (new T(), entity.Application) switch { (GenericDetails, _) => new GenericDetails(entity.ProtocolDetails) as T, @@ -33,7 +32,7 @@ namespace INetMock.Client.Audit Application = entity.Application; Details = details; } - + public long Id { get; init; } public DateTimeOffset Timestamp { get; init; } public TransportProtocol Transport { get; init; } @@ -69,10 +68,10 @@ namespace INetMock.Client.Audit _ => new EmptyDetails() as T }; } - + if (details == null) return null; - + return new() { Id = ge.Id, diff --git a/src/INetMock.Client/Audit/EventServerStreamReader.cs b/src/INetMock.Client/Audit/EventServerStreamReader.cs deleted file mode 100644 index ce754a9..0000000 --- a/src/INetMock.Client/Audit/EventServerStreamReader.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.Threading; -using System.Threading.Tasks; -using Grpc.Core; - -namespace INetMock.Client.Audit -{ - public sealed class EventServerStreamReader : IProtoEventReader - { - private readonly IAsyncStreamReader _asyncEventStream; - - public EventServerStreamReader(IAsyncStreamReader asyncEventStream) - { - _asyncEventStream = asyncEventStream; - } - - public async Task ReadAsync(CancellationToken token = default) - { - if (!await _asyncEventStream.MoveNext(token)) return null; - return _asyncEventStream.Current; - } - - public void Dispose() - { - } - - public ValueTask DisposeAsync() => ValueTask.CompletedTask; - } -} diff --git a/src/INetMock.Client/Audit/IAuditApiClient.cs b/src/INetMock.Client/Audit/IAuditApiClient.cs new file mode 100644 index 0000000..6d29f8e --- /dev/null +++ b/src/INetMock.Client/Audit/IAuditApiClient.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace INetMock.Client.Audit +{ + public interface IAuditApiClient + { + IProtoEventReader EventStreamAsync(string watcherName, CancellationToken token = default); + Task> ListSinksAsync(CancellationToken token = default); + Task RegisterFileSinkAsync(string targetPath, CancellationToken token = default); + Task RemoveFileSinkAsync(string targetPath, CancellationToken token = default); + } +} diff --git a/src/INetMock.Client/Audit/IEventReader.cs b/src/INetMock.Client/Audit/IEventReader.cs index bcff725..9702237 100644 --- a/src/INetMock.Client/Audit/IEventReader.cs +++ b/src/INetMock.Client/Audit/IEventReader.cs @@ -5,10 +5,10 @@ using System.Threading.Tasks; namespace INetMock.Client.Audit { - public interface IEventReader: IDisposable, IAsyncDisposable where T : EventDetails, new() + public interface IEventReader : IDisposable, IAsyncDisposable where T : EventDetails, new() { IAsyncEnumerable> ReadAllAsync(CancellationToken token = default); - + /// /// /// diff --git a/src/INetMock.Client/Audit/Serialization/EventServerStreamReader.cs b/src/INetMock.Client/Audit/Serialization/EventServerStreamReader.cs new file mode 100644 index 0000000..a65aa2d --- /dev/null +++ b/src/INetMock.Client/Audit/Serialization/EventServerStreamReader.cs @@ -0,0 +1,30 @@ +using System.Threading; +using System.Threading.Tasks; +using Grpc.Core; + +namespace INetMock.Client.Audit.Serialization +{ + public sealed class EventServerStreamReader : IProtoEventReader + { + private readonly AsyncServerStreamingCall _asyncEventStream; + + public EventServerStreamReader(AsyncServerStreamingCall asyncEventStream) + { + _asyncEventStream = asyncEventStream; + } + + public async Task ReadAsync(CancellationToken token = default) + { + if (!await _asyncEventStream.ResponseStream.MoveNext(token)) return null; + return _asyncEventStream.ResponseStream.Current; + } + + public void Dispose() => _asyncEventStream.Dispose(); + + public ValueTask DisposeAsync() + { + _asyncEventStream.Dispose(); + return ValueTask.CompletedTask; + } + } +} diff --git a/src/INetMock.Client/Audit/GenericReader.cs b/src/INetMock.Client/Audit/Serialization/GenericReader.cs similarity index 89% rename from src/INetMock.Client/Audit/GenericReader.cs rename to src/INetMock.Client/Audit/Serialization/GenericReader.cs index 2d8dcbf..b175aec 100644 --- a/src/INetMock.Client/Audit/GenericReader.cs +++ b/src/INetMock.Client/Audit/Serialization/GenericReader.cs @@ -3,7 +3,7 @@ using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; -namespace INetMock.Client.Audit +namespace INetMock.Client.Audit.Serialization { public sealed class GenericReader : IEventReader { @@ -14,7 +14,8 @@ namespace INetMock.Client.Audit _reader = reader; } - public async IAsyncEnumerable> ReadAllAsync([EnumeratorCancellation] CancellationToken token = default) + public async IAsyncEnumerable> ReadAllAsync( + [EnumeratorCancellation] CancellationToken token = default) { while (true) { diff --git a/src/INetMock.Client/Audit/ProtoReader.cs b/src/INetMock.Client/Audit/Serialization/ProtoReader.cs similarity index 96% rename from src/INetMock.Client/Audit/ProtoReader.cs rename to src/INetMock.Client/Audit/Serialization/ProtoReader.cs index b2534d9..bc0180c 100644 --- a/src/INetMock.Client/Audit/ProtoReader.cs +++ b/src/INetMock.Client/Audit/Serialization/ProtoReader.cs @@ -5,14 +5,14 @@ using System.Threading; using System.Threading.Tasks; using Google.Protobuf; -namespace INetMock.Client.Audit +namespace INetMock.Client.Audit.Serialization { public sealed class ProtoReader : IProtoEventReader { private readonly MemoryPool _memoryPool; private readonly Stream _sourceStream; private readonly bool _keepStreamOpen; - + public ProtoReader(Stream sourceStream, bool keepStreamOpen = false) { _memoryPool = MemoryPool.Shared; @@ -41,10 +41,10 @@ namespace INetMock.Client.Audit var entity = new EventEntity(); entity.MergeFrom(msgMem.ToArray()); - + return entity; } - + public async ValueTask DisposeAsync() { if (!_keepStreamOpen) diff --git a/src/INetMock.Client/Audit/TypedReader.cs b/src/INetMock.Client/Audit/Serialization/TypedReader.cs similarity index 98% rename from src/INetMock.Client/Audit/TypedReader.cs rename to src/INetMock.Client/Audit/Serialization/TypedReader.cs index b4c6729..6ed486c 100644 --- a/src/INetMock.Client/Audit/TypedReader.cs +++ b/src/INetMock.Client/Audit/Serialization/TypedReader.cs @@ -3,7 +3,7 @@ using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; -namespace INetMock.Client.Audit +namespace INetMock.Client.Audit.Serialization { /// /// Configures how the TypedReader proceeds with mismatching entities. diff --git a/src/INetMock.Client/INetMock.Client.csproj b/src/INetMock.Client/INetMock.Client.csproj index e20a5ff..58c4030 100644 --- a/src/INetMock.Client/INetMock.Client.csproj +++ b/src/INetMock.Client/INetMock.Client.csproj @@ -19,5 +19,6 @@ + diff --git a/tests/INetMock.Client.Test/Audit/GenericReaderTest.cs b/tests/INetMock.Client.Test/Audit/Serialization/GenericReaderTest.cs similarity index 89% rename from tests/INetMock.Client.Test/Audit/GenericReaderTest.cs rename to tests/INetMock.Client.Test/Audit/Serialization/GenericReaderTest.cs index 61b076d..7bfd7d4 100644 --- a/tests/INetMock.Client.Test/Audit/GenericReaderTest.cs +++ b/tests/INetMock.Client.Test/Audit/Serialization/GenericReaderTest.cs @@ -1,9 +1,10 @@ using System.IO; using INetMock.Client.Audit; +using INetMock.Client.Audit.Serialization; using INetMock.Client.Test.Hex; using Xunit; -namespace INetMock.Client.Test.Audit +namespace INetMock.Client.Test.Audit.Serialization { public class GenericReaderTest { @@ -23,7 +24,7 @@ namespace INetMock.Client.Test.Audit public async void TestRead_HttpEvent_Success() { await using var protoReader = new ProtoReader(new MemoryStream(_httpEventPayloadBytes)); - await using var reader = new GenericReader(protoReader); + await using IEventReader reader = new GenericReader(protoReader); await foreach (var ev in reader.ReadAllAsync()) { Assert.NotNull(ev); @@ -44,7 +45,7 @@ namespace INetMock.Client.Test.Audit { await using var memStream = new MemoryStream(_dnsEventPayloadBytes); await using var protoReader = new ProtoReader(new MemoryStream(_dnsEventPayloadBytes)); - await using var reader = new GenericReader(protoReader); + await using IEventReader reader = new GenericReader(protoReader); await foreach (var ev in reader.ReadAllAsync()) { Assert.NotNull(ev); diff --git a/tests/INetMock.Client.Test/Audit/TypedReaderTest.cs b/tests/INetMock.Client.Test/Audit/Serialization/TypedReaderTest.cs similarity index 84% rename from tests/INetMock.Client.Test/Audit/TypedReaderTest.cs rename to tests/INetMock.Client.Test/Audit/Serialization/TypedReaderTest.cs index ed79fea..57b90f5 100644 --- a/tests/INetMock.Client.Test/Audit/TypedReaderTest.cs +++ b/tests/INetMock.Client.Test/Audit/Serialization/TypedReaderTest.cs @@ -1,9 +1,10 @@ using System.IO; using INetMock.Client.Audit; +using INetMock.Client.Audit.Serialization; using INetMock.Client.Test.Hex; using Xunit; -namespace INetMock.Client.Test.Audit +namespace INetMock.Client.Test.Audit.Serialization { public class TypedReaderTest { @@ -23,7 +24,7 @@ namespace INetMock.Client.Test.Audit public async void TestRead_HttpEvent_Success() { await using var protoReader = new ProtoReader(new MemoryStream(_httpEventPayloadBytes)); - await using var reader = new TypedReader(protoReader, DropMode.DropEntity); + await using IEventReader reader = new TypedReader(protoReader, DropMode.DropEntity); await foreach (var ev in reader.ReadAllAsync()) { Assert.NotNull(ev); @@ -34,7 +35,7 @@ namespace INetMock.Client.Test.Audit public async void TestRead_DnsEvent_Success() { await using var protoReader = new ProtoReader(new MemoryStream(_dnsEventPayloadBytes)); - await using var reader = new TypedReader(protoReader, DropMode.DropEntity); + await using IEventReader reader = new TypedReader(protoReader, DropMode.DropEntity); await foreach (var ev in reader.ReadAllAsync()) { Assert.NotNull(ev);