Add audit API client
- cleanup - generate PCAP API
This commit is contained in:
parent
bb46b7f58a
commit
15106dbfd6
13 changed files with 151 additions and 58 deletions
73
src/INetMock.Client/Audit/Client/AuditApiClient.cs
Normal file
73
src/INetMock.Client/Audit/Client/AuditApiClient.cs
Normal file
|
@ -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<IEnumerable<string>> ListSinksAsync(CancellationToken token = default)
|
||||
{
|
||||
var sinks = await _auditClient.ListSinksAsync(new ListSinksRequest(), Metadata.Empty, null, token);
|
||||
return sinks.Sinks;
|
||||
}
|
||||
|
||||
public async Task<string> 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<bool> 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<DNSQuestionEntity> 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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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<EventEntity> _asyncEventStream;
|
||||
|
||||
public EventServerStreamReader(IAsyncStreamReader<EventEntity> asyncEventStream)
|
||||
{
|
||||
_asyncEventStream = asyncEventStream;
|
||||
}
|
||||
|
||||
public async Task<EventEntity?> ReadAsync(CancellationToken token = default)
|
||||
{
|
||||
if (!await _asyncEventStream.MoveNext(token)) return null;
|
||||
return _asyncEventStream.Current;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
public ValueTask DisposeAsync() => ValueTask.CompletedTask;
|
||||
}
|
||||
}
|
14
src/INetMock.Client/Audit/IAuditApiClient.cs
Normal file
14
src/INetMock.Client/Audit/IAuditApiClient.cs
Normal file
|
@ -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<IEnumerable<string>> ListSinksAsync(CancellationToken token = default);
|
||||
Task<string> RegisterFileSinkAsync(string targetPath, CancellationToken token = default);
|
||||
Task<bool> RemoveFileSinkAsync(string targetPath, CancellationToken token = default);
|
||||
}
|
||||
}
|
|
@ -5,10 +5,10 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace INetMock.Client.Audit
|
||||
{
|
||||
public interface IEventReader<T>: IDisposable, IAsyncDisposable where T : EventDetails, new()
|
||||
public interface IEventReader<T> : IDisposable, IAsyncDisposable where T : EventDetails, new()
|
||||
{
|
||||
IAsyncEnumerable<Event<T>> ReadAllAsync(CancellationToken token = default);
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
|
|
|
@ -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<EventEntity> _asyncEventStream;
|
||||
|
||||
public EventServerStreamReader(AsyncServerStreamingCall<EventEntity> asyncEventStream)
|
||||
{
|
||||
_asyncEventStream = asyncEventStream;
|
||||
}
|
||||
|
||||
public async Task<EventEntity?> 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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<GenericDetails>
|
||||
{
|
||||
|
@ -14,7 +14,8 @@ namespace INetMock.Client.Audit
|
|||
_reader = reader;
|
||||
}
|
||||
|
||||
public async IAsyncEnumerable<Event<GenericDetails>> ReadAllAsync([EnumeratorCancellation] CancellationToken token = default)
|
||||
public async IAsyncEnumerable<Event<GenericDetails>> ReadAllAsync(
|
||||
[EnumeratorCancellation] CancellationToken token = default)
|
||||
{
|
||||
while (true)
|
||||
{
|
|
@ -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<byte> _memoryPool;
|
||||
private readonly Stream _sourceStream;
|
||||
private readonly bool _keepStreamOpen;
|
||||
|
||||
|
||||
public ProtoReader(Stream sourceStream, bool keepStreamOpen = false)
|
||||
{
|
||||
_memoryPool = MemoryPool<byte>.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)
|
|
@ -3,7 +3,7 @@ using System.Runtime.CompilerServices;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace INetMock.Client.Audit
|
||||
namespace INetMock.Client.Audit.Serialization
|
||||
{
|
||||
/// <summary>
|
||||
/// Configures how the TypedReader proceeds with mismatching entities.
|
|
@ -19,5 +19,6 @@
|
|||
<Protobuf Include="proto/audit/details/http_details.proto" GrpcServices="Client" AdditionalImportDirs="./proto/" />
|
||||
<Protobuf Include="proto/rpc/audit.proto" GrpcServices="Client" AdditionalImportDirs="./proto/" />
|
||||
<Protobuf Include="proto/rpc/health.proto" GrpcServices="Client" AdditionalImportDirs="./proto/" />
|
||||
<Protobuf Include="proto/rpc/pcap.proto" GrpcServices="Client" AdditionalImportDirs="./proto/" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
@ -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<GenericDetails> 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<GenericDetails> reader = new GenericReader(protoReader);
|
||||
await foreach (var ev in reader.ReadAllAsync())
|
||||
{
|
||||
Assert.NotNull(ev);
|
|
@ -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<HttpDetails>(protoReader, DropMode.DropEntity);
|
||||
await using IEventReader<HttpDetails> reader = new TypedReader<HttpDetails>(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<DnsDetails>(protoReader, DropMode.DropEntity);
|
||||
await using IEventReader<DnsDetails> reader = new TypedReader<DnsDetails>(protoReader, DropMode.DropEntity);
|
||||
await foreach (var ev in reader.ReadAllAsync())
|
||||
{
|
||||
Assert.NotNull(ev);
|
Loading…
Reference in a new issue